Success!
I took a bit of a convoluted path with plenty of trial and error but it is up and running now as I wanted. PBR is indeed the key. For the benefit of others who wish to do the same I will attempt to describe the steps I took - the ones that worked - here:
Part 1 - local VPN network with WiFi
-
Go to the User Guide page on setting up a Guest network:
https://openwrt.org/docs/guide-user/network/wifi/guestwifi/guest-wlan
I see no reason why this couldn't be done on the GUI if you know what you're doing, but the guide does it on the command line so might as well go with that.
-
Follow the steps as given there, substituting 'vpn' for 'guest' anywhere you see it in the code, for example the first line becomes
uci -q delete network.vpn_dev
and the fourth line becomes
uci set network.vpn_dev.name="br-vpn"
...and so forth.
-
When you get to the ipaddr don't use the one in the guide change it to 192.168.4.1 (or any other range you haven't used elsewhere)
-
When you get to step 4 - Firewall skip all the lines referencing dns since we don't want dns queries being handled by the local resolver, we want them to go out the VPN pipe along with everything else.
-
When you have completed this page, test that you can connect to the vpn wifi network, and that you can reach websites by ip address since dns won't be working. As an example ipleak.net is currently resolving to 95.85.16.212 so try that. It should show your traffic is still coming from your ISP - that is okay for the moment - the important part is the new vpn network and the new vpn wifi are able to pass data.
Part 2 - Wireguard
-
Go to the Wireguard Basics page in the User Guide https://openwrt.org/docs/guide-user/services/vpn/wireguard/basics and follow the process to install the software. Skip step 4 for now - we'll get to that next.
-
Now we're going to follow the Wireguard Client page https://openwrt.org/docs/guide-user/services/vpn/wireguard/client I tried doing this part in the GUI and my connection didn't work so I had to go back and do it by command line as is shown here. I don't know why it would be any different but that was my experience.
-
For step 1 - Preparation we are going to have to make some changes to the contents of the variables based on what information your VPN service provider (VSP) has given you, and set up some additional variables that aren't shown in the guide but are used in later steps.
VPN_IF="wg"
calling this interface "vpn" the same as the network we just set up is confusing so I changed mine to "wg" for clarity.
VPN_SERV="the public address your VSP told you to connect to, sometimes called the endpoint"
VPN_PORT="51820"
unless your VSP gave you a different number i.e. 443 use that instead
VPN_ADDR="the interface address given by your VSP"
My VSP did not provide any IPv6 details so I skipped the VPN_ADDR6
VPN_KEY="the *private* key string from your VSP"
VPN_PUB="the *public* key string from your VSP"
VPN_PSK="the *preshared* key string from your VSP"
You can check that you've set the contents of any variable correctly by using, for example
echo $VPN_SERV
-
Now proceed through steps 2 (maybe not needed? I did it anyway) 3 and begin 4. Note that if your connection to your openWRT device gets interrupted or you get logged out for any reason you will have to repeat the variable settings above as they are not carried over from one user session to the next. Also note that if, like me, your VSP did not supply any IPv6 details you can skip any lines that reference IPADDR6.
-
When, in step 4, you get to the line
uci set network.wgserver.route_allowed_ips="1"
change it to
uci set network.wgserver.route_allowed_ips="0"
Setting a 1 here makes the Wireguard interface the default route for the entire device which is not what we want. Setting a 0 ensures that all traffic will continue to go via your ISP except for what we route via Wireguard using PBR.
-
The notes about race condition and dynamic connection I think are not applicable to this configuration since we haven't changed the default route.
-
Skip the testing at the end of the page for now since traceroute will go out the default route anyway. To check whether your VPN is up, go to the Status > WireGuard page in the GUI and see if the Latest Handshake field reports a recent date/timestamp. There may also be a small amount of Data Received/Data Transmitted. If your connection appears to be down, go to Network > Interfaces and try clicking Restart on the wg interface. If that doesn't work, you will need to troubleshoot your Wiregard settings.
-
Optionally, consider going to Edit on wg and unticking the Bring up on boot tickbox. You will have to manually Restart the wg interface if your openWRT device reboots but it seems to do it a whole lot faster for me with this box unticked, and I don't necessarily want to run my VPN connection 24/7/365 either.
-
(maybe not needed?) Edit your wg interface, on the Advanced Settings tab, and add the dns server your VSP gave you under Use custom DNS servers. If your VSP did not give you a dns server address try entering one of the common public DNS servers such as 1.1.1.1 (cloudflare) or 8.8.8.8 (google)
-
While in Network > Interfaces, Edit the vpn interface we created in part 1. Go to DHCP Server > Advanced Settings and in the DHCP-Options field add 6,ip of your VSP dns server. Or if they didn't provide one then, as above, use the ip of a public server i.e.
6,1.1.1.1
Not really sure if DHCP is supposed to be distributing the custom DNS server we set in 14. but it doesn't seem to. Setting it as an option here does work, however.
Part 3 - setting up Policy Based Routing and tying it together.
Believe it or not, Part 2 was the hard part. The User Guide page on PBR https://openwrt.org/docs/guide-user/network/routing/pbr mentions a PBR app and PBR with netifd. Initially I wasted a lot of time trying to get netifd working but the setup script in the Guide didn't seem to do much (it did execute - I checked) it turns out the app is the way to go, at least on openWRT v 23.05 and later. If you are trying to do this on an older version I get the feeling it is going to be significantly more complicated for you.
- Install the pbr and luci-app-pbr packages, then run
uci set pbr.config.enabled="1"
uci commit pbr
/etc/init.d/pbr restart
To enable PBR, and to activate the GUI log out/log in again. You should get a new Services > Policy Routing menu when it is active.
-
At the top of the Policy Based Routing - Status page you should see your two gateways: wan/eth0.2/ip from your ISP, with a tick beside it indicating it remains the default route, and wg/ip from your VSP, with no tick beside it.
-
A little further down the page in the Policies section there are two example policies that are not enabled. Click the green Add button beneath them.
-
Give you new policy a name like "VPN to WG" set the Local addresses/devices field to the same ip we set on the vpn network way back in step 3 i.e. 192.168.4.1/24, set the Interface field to wg and hit Save.
-
Join a device to the vpn wifi network and open ipleak.net It should indicate your address is that of your VSP. It should also indicate your DNS address is coming from your VSP, or the public dns server if you configured it that way. At the very least your dns should not be coming from your ISP.
Thassit! Job done!