How to Route Only Outgoing Traffic Over an OpenVPN Client

iptablesopenvpnrouting

I want to route all traffic from computer_X over the vpn client except outgoing traffic
(I can also install a vpn-server on the client if that makes it easier).

Incoming connections, such as requests to my webserver :80 or :443 or ssh :22, will still be routed by default via my WAN interface, but outgoing connections, such as :80 requests from my computer_X should be routed over the vpn client.

I added a rule to always use the WAN_GATEWAY as default route for packets that origin from my WAN_INTERFACE. See:

# ip route show table 42
default via WAN_GATEWAY dev eth0 

# ip rule list
0:      from all lookup local 
32765:  from WAN_IP lookup 42
32766:  from all lookup main 
32767:  from all lookup default 

# ip r
default via WAN_GATEWAY dev eth0 onlink 
10.8.0.0/24 via 10.8.0.2 dev tun0 
10.8.0.2 dev tun0  proto kernel  scope link  src 10.8.0.1 
WAN_SUBNET/26 via WAN_GATEWAY dev eth0 
WAN_SUBNET/26 dev eth0  proto kernel  scope link  src WAN_IP 

# ip a
eth0: inet WAN_IP ...
tun0: inet 10.8.0.1 peer 10.8.0.2/32 scope global tun0

Now I want to route all outgoing traffic over my tun0 device, but I can't just ip route add default via 10.8.0.1, because you can't route a tunnel over itself?

But maybe I can still do a default route with

ip route default via 10.8.0.1

but additionally create a specific route for the vpn connections like so?

ip route add table 32 default via WAN_IP
ip rule add from 10.8.0.0/8 table 32

I was hoping that this would prevent the vpn doesn't routing through itself.

Or do I have to add all routes for all subnets except 10.8.0.0/8 manually (to make sure that the tunnel is not tunneling itself)?

ip route add 128.0.0.0/1  via 10.8.0.1
ip route add 64.0.0.0/2 via 10.8.0.1
ip route add 32.0.0.0/3 via 10.8.0.1
ip route add 16.0.0.0/4 via 10.8.0.1
ip route add 12.0.0.0/6 via 10.8.0.1
ip route add 11.0.0.0/7 via 10.8.0.1
ip route add 9.0.0.0/8 via 10.8.0.1

Best Answer

OpenVPN by default adds the route to the OpenVPN server in the default routing table. Routing decision is made by the most matching rule, if no rules are matched default gateway is used. Since there is more precise rule for OpenVPN server, it is used instead of the default route.

You should have your default configuration route all traffic via OpenVPN and then configure the exceptions for your special cases.

You can configure a separate network namespace with its own routing configuration and run the services in there. This possibly requires you to assign a separate IP address for your namespace and/or use a NAT configuration between your namespaces.

Alternative for separate network namespaces is to use policy routing with packet marking.

Use iptables to mark packets with 10 from source ports 80, 443 and 22:

iptables -t mangle -A OUTPUT -p tcp -m multiport --sports 80,443,22 -j MARK --set-mark 10

Configure routing tables. Use OpenVPN configuration for default routing table (all traffic via OpenVPN tunnel, except the tunnel itself). Have a separate routing table for the marked traffic.

# add new routing table 100 and set its default routing to your default gw
ip route add table 100 default via $DEFAULT_GW

# add rule to use the new table for packets marked 10
ip rule add fwmark 10 table 100

# flush routing cache
ip route flush cache
Related Question