howto only tunnel specific hosts route through openvpn client on tomato [closed]

I am relatively newbie in networking world although I did coding and know some sysadmin background for a long time. and here I'm only one step from my destination.

The whole picture is : at home I use one LinkSys E3000 as the gateway(don't know yet if this is it's name), wireless AP and no other routing/switching devices. It serves 1 PC and 1 Mac with LAN, 1 Mac Mini + 1 iPad + 2 smartphones with WIFI.

My goal is use an openvpn client on the E3000 (with tomato firmware) and make my iPad and smartphone's all WiFi traffic through it, and other devices route remain the same non-openvpn route.

So far I'm able to connect openvpn client on E3000 to an openvpn server, tunnel all my devices' all traffic through that openvpn connection. What's left is howto selectively route by source IP (at least in my guessing) to the tunnel while don't bother others.

I had learned some 'iptables' and 'route' in past few days however without much luck, so here comes my question. Here are some info which will help you get the structure.

ifconfig -a output, some useless lines striped, and in the web interface C0:C1:C0:1A:E0:28 is WAN, C0:C1:C0:1A:E0:27 is LAN, C0:C1:C0:1A:E0:29 is 2.4G wifi AP, C0:C1:C0:1A:E0:2A is 5G wifi AP.

root@router:/tmp/home/root# ifconfig -a

br0 Link encap:Ethernet HWaddr C0:C1:C0:1A:E0:27
inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

eth0 Link encap:Ethernet HWaddr C0:C1:C0:1A:E0:27
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

eth1 Link encap:Ethernet HWaddr C0:C1:C0:1A:E0:29
UP BROADCAST RUNNING ALLMULTI MULTICAST MTU:1500 Metric:1

eth2 Link encap:Ethernet HWaddr C0:C1:C0:1A:E0:2A
UP BROADCAST RUNNING ALLMULTI MULTICAST MTU:1500 Metric:1

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host

ppp0 Link encap:Point-to-Point Protocol
inet addr:172.200.1.43 P-t-P:172.200.0.1 Mask:255.255.255.255 UP POINTOPOINT RUNNING MULTICAST MTU:1480 Metric:1

vlan1 Link encap:Ethernet HWaddr C0:C1:C0:1A:E0:27
UP BROADCAST RUNNING ALLMULTI MULTICAST MTU:1500 Metric:1

vlan2 Link encap:Ethernet HWaddr C0:C1:C0:1A:E0:28
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

wl0.1 Link encap:Ethernet HWaddr C0:C1:C0:1A:E0:29
BROADCAST MULTICAST MTU:1500 Metric:1

brctl show output

root@router:/tmp/home/root# brctl show
bridge name bridge id       STP enabled interfaces
br0     8000.c0c1c01ae027   no      vlan1
                            eth1
                            eth2

before openvpn route-up script

root@router:/tmp/home/root# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.200.0.1     0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 br0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
0.0.0.0         172.200.0.1     0.0.0.0         UG    0      0        0 ppp0

openvpn server push

PUSH: Received control message: 'PUSH_REPLY,redirect-gateway,dhcp-option DNS 8.8.8.8,route 172.20.0.1,topology net30,ping 10,ping-restart 120,ifconfig 172.20.0.6 172.20.0.5'

openvpn's stock route-up script

Apr 24 14:52:06 router daemon.notice openvpn[1768]: /sbin/ifconfig tun11 172.20.0.6 pointopoint 172.20.0.5 mtu 1500
Apr 24 14:52:08 router daemon.notice openvpn[1768]: /sbin/route add -net 72.14.177.29 netmask 255.255.255.255 gw 172.200.0.1
Apr 24 14:52:08 router daemon.notice openvpn[1768]: /sbin/route add -net 0.0.0.0 netmask 128.0.0.0 gw 172.20.0.5
Apr 24 14:52:08 router daemon.notice openvpn[1768]: /sbin/route add -net 128.0.0.0 netmask 128.0.0.0 gw 172.20.0.5
Apr 24 14:52:08 router daemon.notice openvpn[1768]: /sbin/route add -net 172.20.0.1 netmask 255.255.255.255 gw 172.20.0.5

route after openvpn

root@router:/tmp/home/root# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.20.0.5      0.0.0.0         255.255.255.255 UH    0      0        0 tun11
72.14.177.29    172.200.0.1     255.255.255.255 UGH   0      0        0 ppp0
172.200.0.1     0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
172.20.0.1      172.20.0.5      255.255.255.255 UGH   0      0        0 tun11
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 br0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
0.0.0.0         172.20.0.5      128.0.0.0       UG    0      0        0 tun11
128.0.0.0       172.20.0.5      128.0.0.0       UG    0      0        0 tun11
0.0.0.0         172.200.0.1     0.0.0.0         UG    0      0        0 ppp0

something I had noticed and tried: * on the web interface of openvpn client there is an option "Create NAT on tunnel", if i check this, there is the following script (probably executed after openvpn connection established)

root@router:/tmp/home/root# cat /tmp/etc/openvpn/fw/client1-fw.sh
#!/bin/sh
iptables -I INPUT -i tun11 -j ACCEPT
iptables -I FORWARD -i tun11 -j ACCEPT
iptables -t nat -I POSTROUTING -s 192.168.1.0/255.255.255.0 -o tun11 -j MASQUERADE

if i uncheck this option, the last line will not appear. Then I guess probably the my issue will be solved by iptables and NAT related commands, I just haven't got enough knowledge to figure them out. I tried run

iptables -t nat -I POSTROUTING -s 192.168.1.6 -o tun11 -j MASQUERADE

manually after openvpn connected (192.168.1.6 is the ip address of my iPad), then my iPad get internet with openvpn tunnel, however all other devices can't reach internet.

in case if needed, here is the iptables about NAT

root@router:/tmp/home/root# iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DROP       all  --  0.0.0.0/0            192.168.1.0/24      
WANPREROUTING  all  --  0.0.0.0/0            172.200.1.43        
upnp       all  --  0.0.0.0/0            172.200.1.43        

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0           
SNAT       all  --  192.168.1.0/24       192.168.1.0/24      to:192.168.1.1 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain WANPREROUTING (1 references)
target     prot opt source               destination         
DNAT       icmp --  0.0.0.0/0            0.0.0.0/0           to:192.168.1.1 

Chain upnp (1 references)
target     prot opt source               destination         
DNAT       udp  --  0.0.0.0/0            0.0.0.0/0       udp dpt:5353 to:192.168.1.3:5353 

Thanks in advance for helping and read this so much, I hope i made every info you need to give a help :)


Solution 1:

Whether this firmware support iproute2, which may support more than one route table, based on src ip.

echo "200 ovpn" >> /etc/iproute2/rt_tables
ip rule add from YOUR.WIFI.IP.S table ovpn

and add route rule for the table

ip route add default via VPN.ROUTE.IP.ADDR dev vpn_dev table ovpn
ip route flush cache

you can ref this: Linux Advanced Routing & Traffic Control HOWTO : http://lartc.org/howto/index.html

Or, as you are Chinese, you can read my blog on this topic: http://wangxu.me/blog/p/675

Hope this could help

Solution 2:

I finally did it :-)

I'm using v1.28.9054 MIPSR2-beta K26 USB vpn3.6, but should work on others, as it's networking.

OpenVPN wants to setup all your routing, you've got to stop that...

In VPN Tunneling/Client/Basic

Uncheck "Create NAT on Tunnel" In VPN Tunneling/Client/Advanced

Uncheck "Redirect Internet Traffic"

Custom Configuration, add the line: route-nopull

In Administration/Scripts/Firewall, make sure you have:

iptables -I FORWARD -i br0 -o tun11 -j ACCEPT
iptables -I FORWARD -i tun11 -o br0 -j ACCEPT
iptables -I INPUT -i tun11 -j REJECT
iptables -t nat -A POSTROUTING -o tun11 -j MASQUERADE

Reboot, and viola, you got nothing...

Then, in a VPN up script (Best choice), or if you have your VPN start with WAN, put in your Administration/Scripts/WANUP

sleep 30
ip route flush table 200
ip route flush cache
ip rule add from 192.168.1.11 lookup 200
ip rule add from 192.168.1.13 lookup 200
VPN_GW=`ifconfig tun11 | awk '/inet addr/ {split ($2,A,":"); print A[2]}'`
ip route add table 200 default via $VPN_GW dev tun11

This probaly isn't the "best" or "proper" way to do it, but it works. Now only 192.168.1.11 and 192.168.2.13 will go through the OpenVPN tunnel. All other devices, and their traffic will go local.

This was extremely important for me, as i didnt want my Transmission torrent traffic going over the VPN. Some guy like SgtPepperKSU is looking at this and probably laughing... Anyway, from one Routing noob to another...

Solution 3:

I did things a little differently but still accomplished the same thing pretty much. Thought I'd share it here.

I set up my Tomato router as an OpenVPN Client so that it routes ALL internet traffic through the VPN. I used StrongVPN.com's service for this purpose and they provided step-by-step instructions, so it was pretty easy to get that part going. Google "Tomato OpenVPN Setup Tutorial StrongVPN" and you'll find it

But the "selective routing only certain hosts" thing was very tricky.

I ended up implementing it as a "WAN UP" script (In the Tomato GUI: Administration->Scripts->WAN UP). The c ode below is what I put into that box. It has lots of comments to explain what's going on. It is based heavily on the code I found here:

http://linksysinfo.org/index.php?threads/route-only-specific-ports-through-vpn-openvpn.37240/

And reading this article was extremely helpful:

http://linux-ip.net/html/adv-multi-internet.html

Here's the code:

# This code goes in the WAN UP section of the Tomato GUI.
#
# 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

# Spotify explicitly uses the VPN
iptables -t mangle -A PREROUTING -i br0 -m iprange --dst-range 78.31.8.1-78.31.15.254 -j MARK --set-mark 0
iptables -t mangle -A PREROUTING -i br0 -m iprange --dst-range 193.182.8.1-193.182.15.254 -j MARK --set-mark 0