I'm currently dealing with a VPN which connection endpoint lies within the subnet which prefix shall be tunneled via that specific VPN.
Essentially the problem thus boils down to match against a (larger) set of destination addresses (/16 mask), except for a wholly contained (small) subset of specific destinations that shall not routed that way (and instead go via the default route).
If the problem was about filtering, in Linux using this could be implemented using a ipset
set up like
ipset create MyVPN hash:net
ipset add MyVPN $MYVPNNET/$MYVPNMASK
ipset add MyVPN $MYVPNENDPOINT nomatch
However such ipsets can only be used inside netfilter.
Now my question is, how I could set up something equivalent using Linux Advanced IP Routing, i.e. the ip route
family of commands?
Routes are calculated on a most-specific-first approach. So if your small subnet needs the default route, put that first and then add the others:
Default Gateway in this example is 10.0.0.1 VPN is 10.0.0.2
Would route traffic to the subnet (10.0.1.0) via default gateway, VPN via 10.0.0.2, and other default traffic via default gateway.
As it turns out, in Linux one can use ipset matching to select routing tables. The extra ingredient is using a netfilter rule that will match the outgoing packets and apply a fwmark to them, which then can be used to select a dedicated routing table. This dedicated routing table then will contain just a single default route through the VPN.
Here's in script form the general idea, how to set this up.
To tear everthing down, just follow the script in reverse, deleting stuff; the ipset can be
destroy
ed with a single command.