Static route split tunnelling understanding

I have an openWRT router with near default config and with openvpn configured.

My subnetworks are:
lan - 192.168.2.0/24 - must go throught vpn
wi-fi1 - interface name: woof 10.0.9.0/24 - must go through vpn
wi-fi2 - interface name: bold 10.0.7.0/24 - must go directly to ISP

I had a task to do split tunneling in such a way that I could choose which subnet would go directly through the ISP and which through the VPN.
But I don't just want to do it, I want to get at least a little bit of a handle on the theoretical part of what I'm doing.

1. The first thing I want to understand. Is it possible to do split tunneling without PBR and creating additional routing tables?

If yes, how? And can static routes help me with this?

What was I trying to do?
Following AI's advice, I tried to disable the creation of default routes for vpn. I unchecked the "use default gateway" option for the vpnN (tun0) interface and added the following line in the ovpn config:
pull-filter ignore "redirect-gateway"

Next, I tried to add static routes using Luci. It looked something like this:
config route
	option target '0.0.0.0/1'
	option gateway '10.44.44.1'
	option interface 'vpnN'
	option metric '0'
	option table 'main'

config route
	option interface 'vpnN'
	option target '128.0.0.0/1'
	option gateway '10.44.44.1'
	option metric '0'
	option table 'main'

config route
	option interface 'wan'
	option gateway '170.30.230.1'
	option target '80.70.70.72/32'
	option metric '0'
	option table 'main'

config route
	option target '192.168.2.0/24'
	option gateway '10.44.44.1'
	option interface 'vpnN'
	option metric '10'
	option table 'main'
	
config route
	option target '10.0.7.0/24'
	option gateway '170.30.230.1'
	option interface 'wan'
	option metric '0'
	option table 'main'

No matter what I did, the route for the 10.0.7.0 network did not work. Devices connected to this network remained without internet.

If it is possible, I want to do split tunneling using static routes without using routing tables and PBR.

If this is not possible, then how to do it with routing tables?

And then I want to feel and understand why it is not convenient and why everyone uses PBR. I want to understand the inconveniences and limitations of the standard openwrt shell

I'm still taking my first steps in openwrt and so I want to configure things more through lucy than through cli or config files. Both options complement each other for a better visualisation, though.
If I am misrepresenting something, please correct my misconceptions. Give me fish and teach me fishing)

2. The second thing. I understand that split tunneling can be done via "WAN default" and "VPN default". I want to understand how to do it both ways and understand the differences.

My current setup without static routes (Default routes and all traffic goes through VPN.)

My routing table (automatic default routes) is:
0.0.0.0/1 via 10.44.44.1 dev tun0
default via 170.30.230.1 dev pppoe-wan
10.0.7.0/24 dev br-bold scope link  src 10.0.7.1
10.0.9.0/24 dev br-woof scope link  src 10.0.9.1
10.44.44.0/22 dev tun0 scope link  src 10.44.44.5
80.70.70.72 via 170.30.230.1 dev pppoe-wan
128.0.0.0/1 via 10.44.44.1 dev tun0
170.30.230.1 dev pppoe-wan scope link  src 10.180.150.180
192.168.2.0/24 dev br-lan scope link  src 192.168.2.1
Column 1 Column 2 Column 3 Column 4 E F
Destination Gateway Genmask Flags Metric Iface
0.0.0.0 10.44.44.1 128.0.0.0 UG 0 tun0
10.44.44.0 0.0.0.0 255.255.252.0 U 0 tun0
128.0.0.0 10.44.44.1 128.0.0.0 UG 0 tun0
0.0.0.0 170.30.230.1 0.0.0.0 UG 0 pppoe-wan
80.70.70.72 170.30.230.1 255.255.255.255 UGH 0 pppoe-wan
170.30.230.1 0.0.0.0 255.255.255.255 UH 0 pppoe-wan
10.0.7.0 0.0.0.0 255.255.255.0 U 0 br-bold
10.0.9.0 0.0.0.0 255.255.255.0 U 0 br-woof
192.168.2.0 0.0.0.0 255.255.255.0 U 0 br-lan
etc/config/network
config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'lan2'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.2.1'
	option netmask '255.255.255.0'
	option ip6assign '60'
	list dns '10.0.254.1'

config interface 'wan'
	option device 'wan'
	option proto 'pppoe'
	option username 'username'
	option password 'password'
	option ipv6 'auto'
	option peerdns '0'

config interface 'wan6'
	option device 'wan'
	option proto 'dhcpv6'
	option reqaddress 'try'
	option reqprefix 'auto'
	option norelease '1'
	option peerdns '0'

config device
	option name 'wan'

config device
	option name 'eth0'

config device
	option name 'lan1'

config device
	option name 'lan2'

config interface 'vpnN'
	option proto 'none'
	option device 'tun0'

config device
	option type 'bridge'
	option name 'br-woof'
	option bridge_empty '1'

config device
	option type 'bridge'
	option name 'br-bold'
	option bridge_empty '1'

config interface 'woof'
	option proto 'static'
	option device 'br-woof'
	option ipaddr '10.0.9.1'
	option netmask '255.255.255.0'
	list dns '10.0.254.1'

config interface 'bold'
	option proto 'static'
	option device 'br-bold'
	option ipaddr '10.0.7.1'
	option netmask '255.255.255.0'

IPs changed, mac addresses removed, unnecessary removed for better perception

You can install the full pbr app or do it manually with routing tables and routing rules which is just the manual variant of PBR:

See how I do it manually:
OpenWRT Policy Based Routing (PBR)

The PBR app:

Either way you use PBR :grinning_face:

1 Like

"Split tunneling" is not the proper term for this use case. A split tunnel is purely destination based, e.g. go to corporate LAN IPs via VPN but the general Internet via the regular unencrypted WAN.

A single routing table is destination based. It doesn't consider the source of the packets, only destination. Thus it can't be used for what you want. You will need multiple tables, and tags to direct packets from different source networks to their table. This can be set up manually or with the pbr helper application.

2 Likes

I want to add that IPv6 has build in source specific routing and Linux does support it.

1 Like

First of all, thank you very much for clarifying. It's much easier now. I even managed to do something, but I had to do a little more than what the guide suggested. The guide is excellent. It's exactly what I was looking for and couldn't find earlier (search engines are very poor nowdays, and the AI is still too dumb for such things).

All the guides I've found in the internet usualy describe a situation where most of the traffic use the WAN, and exceptions via VPN
I wanted to do the opposite. (VPN - default, exceptions to WAN)
So I was doing according to the guide OpenWRT Policy Based Routing (PBR)

But in order for it to really work, I had to add two additional routes:
config route
	option interface 'wan'
	option target '80.70.70.72/32'
	option gateway '170.30.230.1'
	option metric '0'
	option table 'wan_direct'

config route
	option target '10.0.7.0/24'
	option gateway '0.0.0.0'
	option metric '0'
	option table 'wan_direct'
	option interface 'bold'
My full config:
config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'lan2'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.2.1'
	option netmask '255.255.255.0'
	option ip6assign '60'
	list dns '10.0.254.1'

config interface 'wan'
	option device 'wan'
	option proto 'pppoe'
	option username 'username'
	option password 'password'
	option ipv6 'auto'
	option peerdns '0'
	list dns '9.9.9.9'

config interface 'wan6'
	option device 'wan'
	option proto 'dhcpv6'
	option reqaddress 'try'
	option reqprefix 'auto'
	option norelease '1'
	option peerdns '0'

config device
	option name 'wan'

config device
	option name 'eth0'

config device
	option name 'lan1'

config device
	option name 'lan2'

config interface 'vpnN'
	option proto 'none'
	option device 'tun0'

config device
	option type 'bridge'
	option name 'br-woof'
	option bridge_empty '1'

config device
	option type 'bridge'
	option name 'br-bold'
	option bridge_empty '1'

config interface 'woof'
	option proto 'static'
	option device 'br-woof'
	option ipaddr '10.0.9.1'
	option netmask '255.255.255.0'
	list dns '10.0.254.1'

config interface 'bold'
	option proto 'static'
	option device 'br-bold'
	option ipaddr '10.0.7.1'
	option netmask '255.255.255.0'
	list dns '9.9.9.9'
	option defaultroute '0'

config route
	option interface 'wan'
	option target '0.0.0.0/0'
	option gateway '170.30.230.1'
	option table 'wan_direct'
	option metric '0'

config rule
	option priority '2000'
	option src '10.0.7.0/24'
	option dest '0.0.0.0/0'
	option lookup 'wan_direct'

config route
	option interface 'wan'
	option target '80.70.70.72/32'
	option gateway '170.30.230.1'
	option metric '0'
	option table 'wan_direct'

config route
	option target '10.0.7.0/24'
	option gateway '0.0.0.0'
	option metric '0'
	option table 'wan_direct'
	option interface 'bold'
My routing table:
Column 1 Column 2 Column 3 Column 4 E
Device Target Gateway Metric Table
(tun0) 0.0.0.0/1 10.44.44.1 0 main
(tun0) 10.44.44.0/22 - 0 main
(tun0) 128.0.0.0/1 10.44.44.1 0 main
lan 192.168.2.0/24 - 0 main
wan 0.0.0.0/0 170.30.230.1 0 wan_direct
wan 80.70.70.72 170.30.230.1 0 wan_direct
wan 0.0.0.0/0 170.30.230.1 0 main
wan 80.70.70.72 170.30.230.1 0 main
wan 170.30.230.1 - 0 main
woof 10.0.9.0/24 - 0 main
bold 10.0.7.0/24 - 0 wan_direct
bold 10.0.7.0/24 - 0 main

I'm not sure if I did it correctly. Please check me

1. I had to add additional routes 80.70.70.72/32 and 10.0.7.0/24 to make it work. Why?

2. 80.70.70.72 - What kind of address is this? I'm assuming it's a technical address from my ISP. In other examples I saw only gateway address. This is not the same.

3. I used to think that in the WAN interface I should also uncheck "use default gateway" (similar to the method of removing default route via VPN) and replace the default routes with static routes. But without default routes nothing worked for me. Could you please clarify in which cases this checkbox really needs to be unchecked?

4. I don't want DNS for bold 10.0.7.0 resolve by VPN DNS, so for the WAN interface I've set up a custom DNS 9.9.9.9
The problem is that when I do a dnsleaktest, I see two DNS servers. One of them is the VPN country. How can I get rid of this leak? Oh no, I see dns leak on my lan VPN network too.

1 Like

The VPN needs the default route to route traffic to its endpoint (which is 80.70.70.72) via the WAN so you should NOT remove the default gateway from the WAN.

Probably because you did this you had to make this extra route

If you reinstate the default gateway for the wan, then reboot the router you should not need that route and it can be removed.

Having local routes in your new table is usually a good idea from the guide:

If you want to use local routes in your new routing table then use suppress prefix length with lower priority
then routing rules:
/etc/config/network:
config rule 'policy_localroutes'
option lookup 'main'
option suppress_prefixlength '0' # for Open VPN use '1'
option priority '1000'

If you do this correctly then this rule should not be necessary and can be removed (but adding the local routes directly to the table like you did will also work):

Also no need to set any metrics

About DNS it looks like you want Split DNS but that is a whole other can of worms, I suggest you make a new thread for this.
My notes about the subject: https://github.com/egc112/OpenWRT-egc-add-on/tree/main/stop-dns-leak#split-dns

1 Like

No, no. I didn't disable default gateway for WAN. Only for testing. I immediately turned it back on.
But after a second test, it turned out that the route 80.70.70.72/32 really is not needed. My bad.

I did this. I added "policy_localroutes rule" to /etc/config/network
But internet connection on bold 10.0.7.0/24 (to WAN) subnet was lost. Reboot after each action and double testing.
I tried to read about what is it and what is it for. But I didn't have enough knowledge about networking to understand it right away.
The guide says: "in your new routing table" but config looks up in 'main' table.

config rule 'policy_localroutes'
	option lookup 'main'
	option suppress_prefixlength '0'
	option priority '1000'

Is 'main' correct table for this rule? I am confused a bit.

Yes but in your case as you are using OpenVPN which does not use a default router but def1 you need to use a value of 1

You use a priority lower than your your wan_direct table so that this rule comes first so there will be a lookup into the main (default table) but will suppress routes /0 and /1 so that you can use all your local routes but not the default routes.

At least that is the theory

And... Finally. It worked!

I did this:

config rule 'policy_localroutes'
        option lookup 'main'
        option suppress_prefixlength '1'
        option priority '1000'

And it gave the opportunity to get rid of an unnecessary route:

config route
        option target '10.0.7.0/24'
        option gateway '0.0.0.0'
        option table 'wan_direct'
        option interface 'bold'

Thanks a lot, @egc.

I didn't even fully understand what we did, but I got the general idea.
AI's answer also helped me to understand a little better. Maybe this explanation will be useful for someone else too.

What def1 usually means in context openwrt?

In OpenWrt context, "def1" most commonly appears as an iptables-mark/routing trick used by VPN clients (OpenVPN, strongSwan, WireGuard helpers, or scripts) to implement split tunneling or policy routing. It usually refers to adding a route that replaces the default route with two more-specific routes for the VPN gateway and the rest of traffic via the VPN — keeping the original WAN gateway reachable so the VPN tunnel can be established.

Typical meaning / usage

"def1" = create two /1 routes (0.0.0.0/1 and 128.0.0.0/1) that together cover the whole IPv4 internet. These routes are placed in the routing table pointing at the VPN interface/gateway, effectively becoming the new default route without removing the existing default route entry.
This technique preserves the original default gateway entry (so traffic to the VPN server itself still goes out via the real WAN gateway) and avoids clobbering the existing route policy. Tools call this "def1" because they implement the default route via those /1s.

Why it's used

Allows sending virtually all traffic through the VPN while leaving the original default route present so the tunnel establishment and certain local traffic continue to work.
Simpler than deleting/replacing the original default route; safer for reconnects.

Where you see it

OpenVPN option in scripts: --redirect-gateway def1
OpenWrt firewall/router scripts that set up VPN routing
Some luci-app-openvpn or provider scripts

Verification

ip route show will show: 0.0.0.0/1 via dev 128.0.0.0/1 via dev (and original default via still present)

IPv6 equivalent

For IPv6, similar behavior uses ::/1 and 8000::/1 routes.

Short summary

"def1" is shorthand for the "replace default route by two /1 routes" method (used by OpenVPN and others) to route all traffic via VPN while keeping the original default route intact.

Great to see it is solved.

Like you did is exactly what I had in mind.

def1 is a specific instruction for openvpn

The mechanism, using the /1 to override the default route instead of replacing can also be useful in e.g. wireguard when you switch tunnels on and off :slight_smile:

If your problem is solved, please consider marking this topic as [Solved]. See How to mark a topic as [Solved] for a short how-to.
Thanks! :slight_smile:

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.