OpenWrt: route different computers via different upstreams based on their IP

Let's say you have two IPv4 upstreams: 10.1.0.1 and 10.2.0.1.

10.1.0.1 is used as the default route, but you want some computers to be routed via 10.2.0.1, based on their LAN IP address.

Let's imagine for an example that you have two DHCP clients connected:

# cat /tmp/dhcp.leases 
1629000000 01:02:03:aa:bb:cc 192.168.1.200 MacBook-Pro 01:01:02:03:aa:bb:cc
1629000000 01:02:03:dd:ee:ff 192.168.1.210 MacBook-Air 01:01:02:03:dd:ee:ff

and you want to route MacBook-Air (192.168.1.210) via the second upstream 10.2.0.1.

Your main routing table looks like this:

# ip r
default via 10.1.0.1 dev eth2  src 10.1.0.100 
192.168.1.0/24 dev br-lan scope link  src 192.168.1.1
10.1.0.0/24 dev eth2 scope link  src 10.1.0.100 
10.2.0.0/24 dev eth3 scope link  src 10.2.0.100

Add new routing table:

# echo "100 mytable" >> /etc/iproute2/rt_tables

Define new IP set:

# ipset create myset hash:net

Fill it with LAN IPs of computers you want to route via the second upstream:

# ipset add myset 192.168.1.210

Add iptables rules to mark packets coming from those IPs. Add it to /etc/firewall.user, then restart firewall.

iptables -t mangle -A PREROUTING -m set --match-set myset src -j MARK --set-mark 0x64

Add routing rule matching the fwmark:

# ip rule add fwmark 0x64 table mytable

Set default route in table mytable:

# ip route add default via 10.2.0.1 table mytable

You may also want to add route for LAN:

# ip route add 192.168.1.0/24 via 192.168.1.1 table mytable

Basically that's it, now packets coming from 192.168.1.210 will be routed through 10.2.0.1.

To make these changes persistent, use /etc/rc.local script (executed at boot) and /etc/hotplug.d hooks.

If you have any comments, contact me by email.