There have been similar questions on StackExchange but none of the answers helped me, so I'll try a question of my own.

I have a VPN connection via OpenVPN. By default, all traffic is redirected through the tunnel using OpenVPN's "two more specific routes" trick, but I disabled that. My routing table is like this: UGH   0      0        0 eth0 UH    0      0        0 tun1 UGH   0      0        0 tun1   U     0      0        0 eth0         UG    0      0        0 tun1         UG    0      0        0 eth0

And the interface configuration is like this:

# ifconfig
eth0      Link encap:Ethernet  HWaddr XX-XX-
          inet addr:  Bcast:  Mask:
          inet6 addr: fe80::211:9ff:fe8d:acbd/64 Scope:Link
          RX packets:394869 errors:0 dropped:0 overruns:0 frame:0
          TX packets:293489 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:388519578 (370.5 MiB)  TX bytes:148817487 (141.9 MiB)
          Interrupt:20 Base address:0x6f00

tun1      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:  P-t-P:  Mask:
          RX packets:64 errors:0 dropped:0 overruns:0 frame:0
          TX packets:67 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100 
          RX bytes:9885 (9.6 KiB)  TX bytes:4380 (4.2 KiB)

plus the lo device.

The routing table has two default routes, one via eth0 through my local network router (DSL modem) at, and another via tun1 through the VPN's gateway. With this configuration, if I connect to a site, the route chosen is the direct one (because it has less hops?):

# traceroute -n
traceroute to (, 30 hops max, 60 byte packets
 1  0.427 ms  0.491 ms  0.610 ms
 2  17.981 ms  20.137 ms  22.141 ms
 3  23.681 ms  25.009 ms  26.401 ms

This is fine, because my goal is to send only traffic from specific applications through the tunnel (esp. transmission, using its -i / bind-address-ipv4 option). To test whether this can work at all, I check it first with traceroute's -s option:

# traceroute -n -s
traceroute to (, 30 hops max, 60 byte packets
 1  * * *
 2  * * *
 3  * * *

This I take to mean that connection using the tunnel's local address as source is not possible.

What is possible (though only as root) is to specify the source interface:

# traceroute -n -i tun1
traceroute to (, 30 hops max, 60 byte packets
 1  129.337 ms  297.758 ms  297.725 ms
 2  * * *
 3  297.653 ms  297.652 ms  297.650 ms

So apparently the tun1 interface is working and it is possible to send packets through it.

But selecting the source interface is not implemented in my actual target application (transmission), so I would like to get source address selection to work.

What am I doing wrong?

Edit: Based on the answer by DerfK, here's my OpenVPN configuration:

In the .conf- or .ovpn-file, include these commands

# disable automatic route configuration
# enable executing scripts
script-security 2
# script to configure routes
up updown.sh
# script to deconfigure routes
down updown.sh

And the script updown.sh contains:

case $script_type in

up)     echo routes up
        # reproduce OpenVPN's standard routes
        ip route add $trusted_ip via $route_net_gateway
        ip route add $route_network_1 via $route_vpn_gateway
        # but put the default route in an extra table
        ip route add default via $route_vpn_gateway table 200
        # and make sure it is activated by selection of the interface's address
        ip rule add from $ifconfig_local/32 table 200
        # flush routing cache (but everything seems to work without this, too)
        ip route flush cache

down)   echo routes down
        ip route del $trusted_ip


With this configuration, the traceroute -s command gives the same output as the traceroute -i showing the route through the VPN to the target address.

Something I did not explain in my original post: The VPN in question does not provide access to a protected local network, but to the Internet, but from a different location / IP address. Otherwise, adding a default route would not have been necessary in the first place.


What you are looking for is called "Source based routing" and the old route program can't manage that. You'll need to use iproute2 and set up an alternate routing table based on source IP address. Using the guide here you'll have something like:

# Designate "table 200" as "vpntunnel"
# - optional, but otherwise we'd have to use 200 everywhere.  Also, 200 is an arbitrary number, 0 253 254 255 are reserved.
echo 200 vpntunnel >> /etc/iproute2/rt_tables
# Packets from your tunnel address use this table
ip rule add from table vpntunnel
# The default route for packets using the vpntunnel is...
ip route add default via dev tun1 table vpntunnel
# Flush routing cache
ip route flush cache

I'm not sure if you'll need to remove the route from the regular route table before doing this, but it should be OK to leave it (in fact it might be necessary in order to get the kernel to select the right source IP to talk to for apps that don't bind to an IP).

| improve this answer | |
  • Thanks a lot, that did it! One thing I'm not clear about though, is the last line in your configuration example, ip route flush cache. If I understand the man page right, this deletes all the entries in the (main?) routing table. Why would I want to do that? – A. Donda Oct 15 '12 at 1:12
  • I'm not sure where you're getting that idea. It deletes all the entries in the cache, not the actual table – DerfK Oct 15 '12 at 1:32
  • Right, I overlooked the last word in the command. Thanks again! – A. Donda Oct 15 '12 at 1:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.