I would like to use WireGuard only for selected domains and have all other traffic go through the normal WAN interface. This is backwards to all those who want VPN on except for Netflix.
Since my exceptions are domain-based, I need to use an ipset with dnsmasq… I’ve tried the vpn-policy-routing package, but it does not work out-of-the box with GL-iNet’s setup.
I’ve tried modifying the /etc/init.d/wireguard script, but when I don’t disable lan2wan forwarding, after removing the default routes feeding wg0 (0.0.0.0/1 and 188.8.131.52/1) I can get traffic to go out through the WAN. But in testing, when I manually add a route for an IP address to the wg0 interface, it always goes out the wan.
This is not an unusual use case where I would want to route only corporate traffic, identifiable by the company’s domain names, through the VPN and send everything else out the wan port.
It ought to be possible, however, to route by domain. Use the ipset capability of dnsmasq to record the affected ip addresses in an ipset table and apply a fwmark to those addresses.
We can incorporate the fwmark in the iptables and ip rules to separate the special domain traffic from the rest and route accordingly.
This was the basis of the vpn-policy-routing package mentioned in the OP. (See here.)
But that package was just doesn’t quite seem to work with GL-iNet’s implementation of wireguard. The /etc/init.d/wireguard script forces all traffic to wg0 and uses iptables to block lan-wan and forwarding output, leaving wg0 as the only output interface. Then it adds two routes which effectively become a default route to wg0.
Changing those routes don’t help. Adding a route to a specific ip address still forces the traffic over WG. If I disable the wg script disables, then everything goes to the wan interface and nothing to wg0.
I’m just not getting something right about how wg manipulates iptables and routing to achieve the “route-all” and how I can modify it so it could route based on an fwmark.
Not possible, routing is done on the packet level, where you have MAC and IP addresses, not host names. Host names have long disappeared from the processing by the time routing occurs (typically gone before the socket is even opened, before any traffic flows).
ipset is a firewall (netfilter) construct. Routing tables are different. dnsmasq is something else entirely, being a DHCP and DNS server.
I appreciate the engagement. There is a lot of power buried that often doesn’t get used.
The secret (and what GL-iNet implemented in the latest test versions) is a bit messy but straightforward…
Configure dnsmasq to add to an ipset when it finds a match on a domain name. Thus, dnsmasq ends up building a list of ip addresses which match the domain name. For the new GL-iNet version, the set to route via VPN is named gl_via_vpn_domain. Over time, this accumulates the ip net for anything resolved with any of the specified domain names.
Iptable entries are created with a special matching rule on ipset name. When the rule is matched (viz. ip address is in domain) a mark is set. The mark can be used for further matching in iptables rule evaluation. GL-iNet’s script creates: iptables -t mangle -A ROUTE_POLICY -i br-lan -m set --match-set gl_bypass_vpn_domain dst -j MARK --set-mark 0x80000/0x80000. Thus any packet from the lan matching an IP previously placed in ipset gl_via_vpn_domain by dnsmasq is marked with mark 0x80000.
There’s an ip rule that says if you match mark 0x80000, use table 52 for routing. LIkewise, a mark of 0x100000 routes through table 52. One is ip rule add fwmark 0x100000/0x100000 lookup 51 pref 51
Finally, gl_route_policy add an explicit route under table number 51 to force traffic through the wg0 interface while table 52 forces traffic to route through the wan interface. The former is used when the policy is to route “via” and the latter for “bypass”.
It’s a long chain (forgive the iptables pun) from a domain name being resolved in dnsmasq to finally being routed, but it works pretty well.
If you’re interested, grab a copy of /etc/init.d/gl_route_policy as well as an iptable, ipset and ip route table dump and enjoy.