Policy-Based-Routing (pbr) package discussion

Having some issues with the pbr package recently. PBR will not start if my openvpn gateway is down (which it is the majority of the time). It gives the following errors (Failed to set up 'NordVPNTUN/tun0/0.0.0.0'!
Failed to install fw4 nft file '/var/run/pbr.nft'!) The first of those errors always used to appear but the service would start nonetheless. If I enable the openvpn client I can then start pbr but then when I disable the openvpn client, PBR doesn't then recognise that Openvpn is down and continues to try and enforce policies even though I use the "do not enforce policies when their gateway is down" option.

I'm not sure if I'm qualified to make this call, I see that the jump from dstnat to dstnat_lan is conditional on LAN interfaces, so I'm not sure if it's a good idea to unconditionally jump from dstnat to dstnat_lan_pbr.

I think that was the design goal, is that not how it currently works?

README -> Getting Help.

It almost works like that.
I had some time to work on it and made a patch, but I am travelling tomorrow..

So i hope I can get back to you the day after.

I am also testing an idea for the destnat_lan problem, using the destnat_lan does not seem to be a good idea as that is only targeting br_lan.

But i will send in my ideas the day after tommorrow.

1 Like

Running for several hours I see this.
image
This happened after I rebooted the router. It was running OK for several hours without any error. Then I saw that in Luci.
The VPN tunnel wasn't even used simply because my activity didn't hit any rule. I have only one rule because I'm still testing how all the things work.
And one question about the PBR DNS Policies. It doesn't use encrypted DNS, right?
The errors disappeared after some time but still the current version 1.1.7-15 looks broken to me because if I set PBR DNS rule it works but the other rule to route the same client via VPN stops working and the client goes through default WAN connection.
Maybe my rules are wrong?

I installed https-dns-proxy with default Clodflare and Google DNSes to try what will be the result.
When I checked with dnscheck.tools
I see a message
"Your DNS resolvers provide partial client IP address information (ECS):"
and I can see my public IP address (only the last octet is 0).
Isn't this a security/privacy risk?

image

I have a separate vlan for guests (guest network br-vlan). When I connect to the guest network and try to open a domain that should be routed through VPN it cannot be opened. I read in the help about procd_lan_interface config option but cannot find it. I want to route the guest network clients through VPN.

All config files below as requested in wiki. When Openvpn client is down, pbr will not start (not sure if this intended as this wasn't the case previously). When VPN is up, I have to start the service manually. When I then take the VPN down, pbr continues to run and doesn't recognise that the VPN is down. I've tried the hotfix described in the wiki as I thought it might make a difference but no difference.

 ubus call system board
{
        "kernel": "5.15.167",
        "hostname": "OpenWrt",
        "system": "ARMv7 Processor rev 1 (v7l)",
        "model": "Linksys WRT3200ACM",
        "board_name": "linksys,wrt3200acm",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "23.05.5",
                "revision": "r24106-10cc5fcd00",
                "target": "mvebu/cortexa9",
                "description": "OpenWrt 23.05.5 r24106-10cc5fcd00"
        }
}
uci export dhcp
package dhcp

config dnsmasq
        option domainneeded '1'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option localservice '1'
        option ednspacket_max '1232'
        list rebind_domain 'plex.direct'
        option confdir '/tmp/dnsmasq.d'
        option cachesize '0'
        list server '/mask.icloud.com/'
        list server '/mask-h2.icloud.com/'
        list server '/use-application-dns.net/'
        list server '127.0.0.1#5053'
        list server '127.0.0.1#5054'
        option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
        option doh_backup_noresolv '-1'
        option noresolv '1'
        list doh_backup_server '/mask.icloud.com/'
        list doh_backup_server '/mask-h2.icloud.com/'
        list doh_backup_server '/use-application-dns.net/'
        list doh_backup_server '127.0.0.1#5053'
        list doh_backup_server '127.0.0.1#5054'
        list doh_server '127.0.0.1#5053'
        list doh_server '127.0.0.1#5054'

config dhcp 'lan'
        option interface 'lan'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'
        option dhcpv6 'server'
        option ra 'server'
        list ra_flags 'managed-config'
        list ra_flags 'other-config'
        option start '40'

config dhcp 'wan'
        option interface 'wan'
        option ignore '1'

config odhcpd 'odhcpd'
        option maindhcp '0'
        option leasefile '/tmp/hosts/odhcpd'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'

config host
        option name 'Synology-DS918'
        option dns '1'
        option ip '192.168.10.10'
        option leasetime '24h'
        option mac 'REDACT'

config host
        option dns '1'
        option ip '192.168.10.3'
        option leasetime '24h'
        option name 'Unifi-entrance-hall'
        option mac 'REDACT'

config host
        option dns '1'
        option ip '192.168.10.4'
        option leasetime '24h'
        option name 'Unifi-dining-room'
        option mac 'REDACT'

config host
        option name 'Unifi-Outdoor'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.6'
        option leasetime '24h'

config host
        option name 'Mark-Laptop'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.129'
        option leasetime '24h'

config host
        option name 'Mark-Laptop-eth'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.165'
        option leasetime '24h'

config host
        option name 'Wiser-Heat'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.89'
        option leasetime '24h'

config host
        option name 'GrandstreamHT813'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.5.100'
        option leasetime '24h'

config host
        option name 'CanonMG7550'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.12'
        option leasetime '24h'

config host
        option name 'CanonMG4250'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.13'
        option leasetime '24h'

config host
        option name 'Unifi-Plant-Room'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.5'
        option leasetime '24h'

config host
        option name 'Raspberry-Pi-Zigbee-hub'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.11'
        option leasetime '24h'

config host
        option name 'Pi-zero-camera'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.20'
        option leasetime '24h'

config host
        option name 'TP-Link-Fly-zapper'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.21'
        option leasetime '24h'

config host
        option name 'TP-Link-DAB-Water-Pump'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.22'
        option leasetime '24h'

config dhcp 'VOIP'
        option interface 'VOIP'
        option start '100'
        option limit '150'
        option leasetime '12h'
        list ra_flags 'none'

config dhcp 'Guest'
        option interface 'Guest'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option force '1'
        list ra_flags 'none'

config domain
        option ip '192.168.10.10'
        option name 'REDACT'

config host
        option name 'USW-Flex-Mini'
        option dns '1'
        option mac 'REDACT'
        option leasetime '24h'
        option ip '192.168.10.2'

config host
        option ip '192.168.10.91'
        option mac 'REDACT'
        option name 'Mark-Macbook-pro'
        option dns '1'
        option leasetime '24h'

config host
        option name 'marka-malt0'
        option ip '192.168.10.175'
        option mac 'REDACT'
        option leasetime '24h'

config host
        option name 'TP-Link-Entrance-hall-lamp'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.23'
        option leasetime '24h'

config host
        option name 'TP-Link-Entrance-dehumidifier'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.24'
        option leasetime '24h'

config domain
        option ip '192.168.10.10'
        option name 'REDACT'

config host
        option name 'TP-Link-conservatory-dehumidifier'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.25'
        option leasetime '24h'

config host
        option name 'Shelly2.5-James-bathroom'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.30'
        option leasetime '24h'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config host
        option name 'LG-Kitchen-TV'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.78'
        option leasetime '24h'

config host
        option name 'LG-OLED-Lounge'
        option dns '1'
        option mac 'REDACT'
        option ip '192.168.10.90'
        option leasetime '24h'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

config host
        option name 'Unifi-study'
        list mac 'REDACT'
        option ip '192.168.10.8'
        option leasetime '24h'

config host
        option name 'USW-Flex-Mini-2'
        list mac 'REDACT'
        option ip '192.168.10.7'
        option leasetime '24h'

config dhcp 'Surveillance'
        option interface 'Surveillance'
        option start '100'
        option limit '150'
        option leasetime '12h'

config host
        option name 'Synology-DS918-Surveillance'
        option ip '192.168.88.10'
        list mac 'REDACT'
        option leasetime '24h'

config host
        option name 'USW-Flex'
        list mac 'REDACT'
        option ip '192.168.10.9'
        option leasetime '24h'

config host
        option name 'DAHUA-Yard-Cam'
        option ip '192.168.88.50'
        list mac 'REDACT'
        option leasetime '24h'

config host
        option name 'Dahua-road-cam'
        option ip '192.168.88.51'
        list mac 'REDACT'
        option leasetime '24h'

config domain
        option name 'REDACT'
        option ip '192.168.10.10'

package firewall

config defaults
        option output 'ACCEPT'
        option forward 'REJECT'
        option synflood_protect '1'
        option input 'REJECT'
        option drop_invalid '1'

config zone 'lan'
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'lan'
        list network 'wgserver'

config zone 'wan'
        option name 'wan'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'wan'
        list network 'wan6'

config forwarding
        option src 'lan'
        option dest 'wan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option src_ip 'fc00::/6'
        option dest_ip 'fc00::/6'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

config rule
        option name 'Support-UDP-Traceroute'
        option src 'wan'
        option proto 'udp'
        option family 'ipv4'
        option target 'REJECT'
        option enabled '0'
        option dest_port '33434-33689'

config include
        option path '/etc/firewall.user'

config zone
        option name 'VOIP'
        option output 'ACCEPT'
        option forward 'REJECT'
        option input 'REJECT'
        list network 'VOIP'

config forwarding
        option src 'VOIP'
        option dest 'wan'

config rule
        option name 'VOIP DNS'
        option src 'VOIP'
        option dest_port '53'
        option target 'ACCEPT'

config rule
        option name 'VOIP DHCP'
        list proto 'udp'
        option src 'VOIP'
        option dest_port '67-68'
        option target 'ACCEPT'

config rule
        option target 'ACCEPT'
        option name 'Guest DNS'
        option src 'Guest'
        list proto 'tcp'
        list proto 'udp'
        option dest_port '53'

config forwarding
        option src 'lan'
        option dest 'VOIP'

config zone
        option name 'Guest'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        list network 'Guest'

config forwarding
        option src 'Guest'
        option dest 'wan'

config rule
        option name 'Guest DHCP'
        list proto 'udp'
        option src 'Guest'
        option dest_port '67-68'
        option target 'ACCEPT'

config rule
        option name 'Surveillance DNS'
        option src 'surveillance'
        option target 'ACCEPT'
        list proto 'tcp'
        list proto 'udp'
        option dest_port '53'
        option enabled '0'

config rule
        option name 'Surveillance DHCP'
        list proto 'udp'
        option src 'surveillance'
        option target 'ACCEPT'
        option dest_port '67-68'

config zone
        option name 'nordvpn'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'NordVPNTUN'

config forwarding
        option src 'lan'
        option dest 'nordvpn'

config rule
        option name 'Allow Wireguard'
        list proto 'udp'
        option target 'ACCEPT'
        option src 'wan'
        option dest_port '6728'

config rule
        option dest 'wan'
        option target 'REJECT'
        option src 'lan'
        option name 'Block internet access for certain IOT devices'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'

config redirect
        option target 'DNAT'
        option src 'lan'
        option src_dport '123'
        option name 'NTP hijack'
        list proto 'udp'
        option dest_port '123'

config redirect
        option target 'DNAT'
        option name 'NTP Surveillance'
        option src 'surveillance'
        option src_dport '123'
        list proto 'udp'
        option dest_port '123'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'Plex'
        list proto 'tcp'
        option src 'wan'
        option src_dport '32400'
        option dest_ip '192.168.10.10'
        option dest_port '32400'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'HTTPS'
        option src 'wan'
        option dest_ip '192.168.10.10'
        list proto 'tcp'
        option src_dport '443'
        option dest_port '443'

config redirect
        option target 'DNAT'
        option name 'DNS Hijack chromecast'
        option family 'any'
        option src 'lan'
        option src_dport '53'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'
        list src_mac 'REDACT'

config zone
        option name 'surveillance'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        list network 'Surveillance'

config forwarding
        option src 'lan'
        option dest 'surveillance'

config include 'pbr'
        option fw4_compatible '1'
        option type 'script'
        option path '/usr/share/pbr/firewall.include'```
uci export network
package network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix ''

config device
        option name 'br-lan'
        option type 'bridge'
        option igmp_snooping '1'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'

config interface 'lan'
        option proto 'static'
        option netmask '255.255.255.0'
        option ip6assign '60'
        option ipaddr '192.168.10.1'
        option device 'br-lan.1'

config device
        option name 'wan'

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

config interface 'wan6'
        option device 'wan'
        option proto 'dhcpv6'
        option reqaddress 'try'
        option reqprefix 'auto'
        option peerdns '0'
        list dns '2606:4700:4700::1112'
        list dns '2606:4700:4700::1002'
        list dns '2620:fe::fe'

config bridge-vlan
        option device 'br-lan'
        option vlan '1'
        list ports 'lan1:u*'
        list ports 'lan2:u*'
        list ports 'lan3:u*'
        list ports 'lan4:u*'

config bridge-vlan
        option device 'br-lan'
        option vlan '5'
        list ports 'lan1:t'
        list ports 'lan4:t'

config interface 'VOIP'
        option proto 'static'
        option device 'br-lan.5'
        option ipaddr '192.168.5.1'
        option netmask '255.255.255.0'

config bridge-vlan
        option device 'br-lan'
        option vlan '3'
        list ports 'lan1:t'
        list ports 'lan4:t'

config interface 'Guest'
        option proto 'static'
        option device 'br-lan.3'
        option ipaddr '10.10.3.1'
        option netmask '255.255.255.0'

config interface 'NordVPNTUN'
        option proto 'none'
        option device 'tun0'
        list dns '103.86.96.100'
        list dns '103.86.99.100'

config wireguard_vpn

config interface 'wgserver'
        option proto 'wireguard'
        option private_key 'REDACT'
        option listen_port 'REDACT'
        list addresses '192.168.50.1/24'

config wireguard_wgserver
        option description 'Pixel 7'
        option public_key 'REDACT'
        option private_key 'REDACT'
        list allowed_ips '192.168.50.2/32'

config interface 'Surveillance'
        option proto 'static'
        list ipaddr '192.168.88.1/24'
        option device 'br-lan.88'

config bridge-vlan
        option device 'br-lan'
        option vlan '88'
        list ports 'lan1:t'
        list ports 'lan4:t'

config wireguard_wgserver
        option public_key 'REDACT'
        option private_key 'REDACT'
        option description 'Pixel 7a'
        list allowed_ips '192.168.50.3/32'

config wireguard_wgserver
        option description 'Pixel 7a (Giorgia)'
        option public_key 'REDACT'
        option private_key 'REDACT'
        list allowed_ips '192.168.50.4/32'
uci export pbr
package pbr

config pbr 'config'
        option verbosity '2'
        option src_ipset '0'
        option dest_ipset '0'
        option ipv6_enabled '0'
        option boot_timeout '30'
        option procd_boot_delay '30'
        option procd_reload_delay '1'
        option webui_enable_column '0'
        option webui_protocol_column '0'
        option webui_chain_column '0'
        option webui_sorting '1'
        list webui_supported_protocol 'tcp'
        list webui_supported_protocol 'udp'
        list webui_supported_protocol 'tcp udp'
        list webui_supported_protocol 'icmp'
        list webui_supported_protocol 'all'
        option resolver_set 'dnsmasq.nftset'
        option rule_create_option 'add'
        option strict_enforcement '0'
        option webui_show_ignore_target '1'
        option enabled '0'
        list ignored_interface 'wgserver'

config policy
        option name 'DNS'
        option dest_addr '103.86.96.100 103.86.99.100'
        option interface 'NordVPNTUN'

config policy
        option interface 'wan'
        option name 'VOIP VLAN'
        option src_addr '192.168.5.0/24'

config policy
        option interface 'wan'
        option name 'Guest VLAN'
        option src_addr '10.10.3.0/24'

config policy
        option interface 'wan'
        option name 'Synology Nginx'
        option src_addr '192.168.10.10'
        option src_port '443'

config policy
        option name 'Plex local server'
        option src_port '32400'
        option interface 'wan'

config policy
        option name 'Plex remote servers'
        option dest_addr 'plex.tv my.plexapp.com'
        option interface 'wan'

config policy
        option interface 'wan'
        option name 'Canon MG7550'
        option src_addr '192.168.10.12'

config policy
        option interface 'wan'
        option name 'Canon MG4250'
        option src_addr '192.168.10.13'

config policy
        option interface 'wan'
        option name 'Arky Macbook'
        option src_addr '192.168.10.91'

config policy
        option interface 'wan'
        option name 'Wiser Heat'
        option src_addr '192.168.10.89'

config policy
        option interface 'wan'
        option name 'Wifi Calling'
        option dest_port '500 4500'

config policy
        option interface 'wan'
        option name 'Zigbee Hub'
        option src_addr '192.168.10.11'

config policy
        option interface 'wan'
        option name 'Pi Zero Camera'
        option src_addr '192.168.10.20'

config policy
        option interface 'wan'
        option name 'Fly Zapper'
        option src_addr '192.168.10.21'

config policy
        option interface 'wan'
        option name 'DAB Water pump'
        option src_addr '192.168.10.22'

config include
        option path '/etc/pbr.custom.user'
        option enabled '1'

config policy
        option interface 'wan'
        option name 'Mark laptop ethernet'
        option src_addr '192.168.10.175'

config policy
        option interface 'wan'
        option name 'Entrance hall lamp'
        option src_addr '192.168.10.23'

config policy
        option interface 'wan'
        option name 'Entrance dehumidifier'
        option src_addr '192.168.10.24'

config policy
        option interface 'wan'
        option name 'Conservatory dehumidifier'
        option src_addr '192.168.10.25'

config policy
        option interface 'NordVPNTUN'
        option name 'Italian TV media'
        option src_addr 'REDACT'

config policy
        option name 'VPN test'
        option src_addr 'REDACT'
        option interface 'NordVPNTUN'

config dns_policy
        option name 'Mark work PC'
        option src_addr 'REDACT'
        option dest_dns 'wan'

config dns_policy
        option src_addr '192.168.10.0/24'
        option dest_dns 'NordVPNTUN'
        option name 'NordVPN'
/etc/init.d/pbr status

pbr - environment
pbr 1.1.7-17 running on OpenWrt 23.05.5.

Dnsmasq version 2.90  Copyright (c) 2000-2024 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack no-ipset nftset auth cryptohash DNSSEC no-ID loop-detect inotify dumpfile

pbr chains - policies
        chain pbr_forward { # handle 62
        }
        chain pbr_input { # handle 63
        }
        chain pbr_output { # handle 64
        }
        chain pbr_postrouting { # handle 66
        }
        chain pbr_prerouting { # handle 65
        }
        chain pbr_dstnat_lan { # handle 61
        }

pbr chains - marking

pbr nft sets

dnsmasq sets
nftset=/plex.tv/4#inet#fw4#pbr_wan_4_dst_ip_cfg076ff5 # Plex remote servers
nftset=/plex.tv/4#inet#fw4#pbr_wan_4_dst_ip_cfg076ff5 # Plex remote servers
nftset=/my.plexapp.com/4#inet#fw4#pbr_wan_4_dst_ip_cfg076ff5 # Plex remote servers
nftset=/my.plexapp.com/4#inet#fw4#pbr_wan_4_dst_ip_cfg076ff5 # Plex remote servers

IPv4 table 256 route: default via REDACT dev pppoe-wan
IPv4 table 256 rule(s):
29999:  from all sport 6728 lookup pbr_wan
30000:  from all fwmark 0x10000/0xff0000 lookup pbr_wan
IPv4 table 257 route:
IPv4 table 257 rule(s):
/etc/init.d/pbr reload
Using wan interface (on_start): wan
Found wan gateway (on_start): REDACT
Setting up routing for 'wan/pppoe-wan/REDACT' [✓]
Setting up routing for 'NordVPNTUN/tun0/0.0.0.0' [✗]
Routing 'DNS' via NordVPNTUN [✓]
Routing 'VOIP VLAN' via wan [✓]
Routing 'Guest VLAN' via wan [✓]
Routing 'Synology Nginx' via wan [✓]
Routing 'Plex local server' via wan [✓]
Routing 'Plex remote servers' via wan [✓]
Routing 'Canon MG7550' via wan [✓]
Routing 'Canon MG4250' via wan [✓]
Routing 'Arky Macbook' via wan [✓]
Routing 'Wiser Heat' via wan [✓]
Routing 'Wifi Calling' via wan [✓]
Routing 'Zigbee Hub' via wan [✓]
Routing 'Pi Zero Camera' via wan [✓]
Routing 'Fly Zapper' via wan [✓]
Routing 'DAB Water pump' via wan [✓]
Routing 'Mark laptop ethernet' via wan [✓]
Routing 'Entrance hall lamp' via wan [✓]
Routing 'Entrance dehumidifier' via wan [✓]
Routing 'Conservatory dehumidifier' via wan [✓]
Routing 'Italian TV media' via NordVPNTUN [✓]
Routing 'VPN test' via NordVPNTUN [✓]
Routing 'Mark work PC' DNS to wan [✓]
Routing 'NordVPN' DNS to NordVPNTUN [✓]
Running /etc/pbr.custom.user RTNETLINK answers: File exists
RTNETLINK answers: File exists
RTNETLINK answers: File exists
RTNETLINK answers: File exists
RTNETLINK answers: File exists
RTNETLINK answers: File exists
RTNETLINK answers: File exists
RTNETLINK answers: File exists
RTNETLINK answers: File exists
RTNETLINK answers: File exists
[✓]
Installing fw4 nft file [✗]
pbr 1.1.7-17 monitoring interfaces: wan NordVPNTUN
pbr 1.1.7-17 (nft mode) started with gateways:
wan/pppoe-wan/REDACT[✓]
ERROR: Failed to set up 'NordVPNTUN/tun0/0.0.0.0'!
ERROR: Failed to install fw4 nft file '/var/run/pbr.nft'!```

/etc/init.d/pbr status

pbr - environment
pbr 1.1.7-17 running on OpenWrt 23.05.5.

Dnsmasq version 2.90  Copyright (c) 2000-2024 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack no-ipset nftset auth cryptohash DNSSEC no-ID loop-detect inotify dumpfile

pbr chains - policies
        chain pbr_forward { # handle 62
        }
        chain pbr_input { # handle 63
        }
        chain pbr_output { # handle 64
        }
        chain pbr_postrouting { # handle 66
        }
        chain pbr_prerouting { # handle 65
        }
        chain pbr_dstnat_lan { # handle 61
        }

pbr chains - marking

pbr nft sets

dnsmasq sets
nftset=/plex.tv/4#inet#fw4#pbr_wan_4_dst_ip_cfg076ff5 # Plex remote servers
nftset=/plex.tv/4#inet#fw4#pbr_wan_4_dst_ip_cfg076ff5 # Plex remote servers
nftset=/my.plexapp.com/4#inet#fw4#pbr_wan_4_dst_ip_cfg076ff5 # Plex remote servers
nftset=/my.plexapp.com/4#inet#fw4#pbr_wan_4_dst_ip_cfg076ff5 # Plex remote servers

IPv4 table 256 route: default via REDACT dev pppoe-wan
IPv4 table 256 rule(s):
29999:  from all sport 6728 lookup pbr_wan
30000:  from all fwmark 0x10000/0xff0000 lookup pbr_wan
IPv4 table 257 route:
IPv4 table 257 rule(s):

That's the issue for now. Last version which worked fine is pbr-nft_1.1.4-3.

Ok here is my take on the DNS policy routing, as I am travelling at this moment it is not thoroughly tested.

The first is that there duplicate lines in the firewall when using MAC address and interfaces (e.g. @br-lan)

This was because the filter rules also considered those as domains.

So I added extra conditions to the is_domain.see patch below:

is_domain() { ! is_ipv6 "$1" && ! is_mac_address "$1" && ! is_phys_dev "$1" && str_contains "$1" '[a-zA-Z]'; }

The second is that I could not use two rules one for IPv4 and one for IPv6 e.g. for the same MAC address.
By adding meta nfproto ipv4/ipv6 this seems to work.
I just added this in the lines below probably not the best place but it will give you an idea

		param4="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param4} meta nfproto ipv4 ${proto_i} ${nft_rule_params} ${dest4} comment \"$name\""
		param6="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param6} meta nfproto ipv6 ${proto_i} ${nft_rule_params} ${dest6} comment \"$name\""

Then the pbr_dstnat_lan problem, as said not the the best place because dstnat_lan chain is not always present but also as it applies only to br-lan.

A better place seems to jump directly from dstnat chain to pbr_dstnat

I altered the name in the script, see patch below, and made the necessary changes in the firewall rules, I have not made a diff for that but these are my notes:

Rename directory /usr/share/nftables.d/chain-post/dstnat_lan to /usr/share/nftables.d/chain-post/dstnat
In the newly created directory edit this file: /usr/share/nftables.d/chain-post/dstnat/pbr-30.nft replace line " jump pbr_dstnat_lan comment "Jump into pbr dstnat_lan chain"; " with: " jump pbr_dstnat comment "Jump into pbr dstnat chain"; "
In /usr/share/nftables.d/table-post/30-pbr.nft replace "chain pbr_dstnat_lan {}" with: "chain pbr_dstnat {}"

Some simple tests seem to work reliably for IPv4 and IPv6, normally I would test a lot more but as I am traveling I have limited time.

@stangri I hope you can make use of my findings.
Patches are also on my repo: https://github.com/egc112/OpenWRT-egc-add-on/tree/main/pbr
But as said this time I lacked the time to do some more thorough testing so handle with care (you always do I know :wink: )

Patch https:https://github.com/egc112/OpenWRT-egc-add-on/blob/main/pbr/pbr-dns-policy-1.patch

--- pbr-1.1.7-17.bash	2024-09-30 14:36:04.255433000 +0200
+++ pbr-1.1.7-17-egc-3.bash	2024-09-30 18:26:17.095710000 +0200
@@ -5,6 +5,11 @@
 # sysctl net.ipv4.conf.default.rp_filter=1
 # sysctl net.ipv4.conf.all.rp_filter=1
 
+# Rename /usr/share/nftables.d/chain-post/dstnat_lan to /usr/share/nftables.d/chain-post/dstnat
+# In the newly created directory edit this file: /usr/share/nftables.d/chain-post/dstnat/pbr-30.nft replace line " jump pbr_dstnat_lan comment "Jump into pbr dstnat_lan chain"; " with: " jump pbr_dstnat comment "Jump into pbr dstnat chain"; "
+# In /usr/share/nftables.d/table-post/30-pbr.nft replace "chain pbr_dstnat_lan {}" with: "chain pbr_dstnat {}"
+
+
 # shellcheck disable=SC2034
 START=94
 # shellcheck disable=SC2034
@@ -13,7 +18,7 @@
 [ -n "${IPKG_INSTROOT}" ] && return 0
 
 readonly packageName='pbr'
-readonly PKG_VERSION='1.1.7-17'
+readonly PKG_VERSION='1.1.7-17-egc-3'
 readonly packageCompat='8'
 readonly serviceName="$packageName $PKG_VERSION"
 readonly packageConfigFile="/etc/config/${packageName}"
@@ -306,7 +311,9 @@
 uci_get_protocol() { uci_get 'network' "$1" 'proto'; }
 is_default_dev() { [ "$1" = "$(ip -4 r | grep -m1 'dev' | grep -Eso 'dev [^ ]*' | awk '{print $2}')" ]; }
 is_disabled_interface() { [ "$(uci_get 'network' "$1" 'disabled')" = '1' ]; }
-is_domain() { ! is_ipv6 "$1" && str_contains "$1" '[a-zA-Z]'; }
+#egc
+#is_domain() { ! is_ipv6 "$1" && str_contains "$1" '[a-zA-Z]'; }
+is_domain() { ! is_ipv6 "$1" && ! is_mac_address "$1" && ! is_phys_dev "$1" && str_contains "$1" '[a-zA-Z]'; }
 is_dslite() { local p; network_get_protocol p "$1"; [ "${p:0:6}" = "dslite" ]; }
 is_family_mismatch() { ( is_ipv4_netmask "${1//!}" && is_ipv6 "${2//!}" ) || ( is_ipv6 "${1//!}" && is_ipv4_netmask "${2//!}" ); }
 is_greater() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
@@ -633,8 +640,8 @@
 			return 1
 		fi
 		if is_config_enabled 'dns_policy'; then
-			if ! nft_call list chain inet fw4 dstnat_lan; then
-				state add 'errorSummary' 'errorDefaultFw4ChainMissing' 'dstnat_lan'
+			if ! nft_call list chain inet fw4 dstnat; then
+				state add 'errorSummary' 'errorDefaultFw4ChainMissing' 'dstnat'
 				return 1
 			fi
 		fi
@@ -912,7 +919,7 @@
 
 cleanup_main_chains() {
 	local i j
-	for i in $chainsList dstnat_lan; do
+	for i in $chainsList dstnat; do
 		i="$(str_to_lower "$i")"
 		nft_call flush chain inet "$nftTable" "${nftPrefix}_${i}"
 	done
@@ -1174,7 +1181,7 @@
 	local negation value dest4 dest6 first_value
 	local inline_set_ipv4_empty_flag inline_set_ipv6_empty_flag
 	local name="$1" src_addr="$2" dest_dns="$3" uid="$4"
-	local chain='dstnat_lan' iface='dns'
+	local chain='dstnat' iface='dns'
 
 	if [ -z "${dest_dns_ipv4}${dest_dns_ipv6}" ]; then
 		processPolicyError='true'
@@ -1239,8 +1246,11 @@
 			fi
 		fi
 
-		param4="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param4} ${proto_i} ${nft_rule_params} ${dest4} comment \"$name\""
-		param6="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param6} ${proto_i} ${nft_rule_params} ${dest6} comment \"$name\""
+		#egc
+		#param4="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param4} ${proto_i} ${nft_rule_params} ${dest4} comment \"$name\""
+		#param6="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param6} ${proto_i} ${nft_rule_params} ${dest6} comment \"$name\""
+		param4="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param4} meta nfproto ipv4 ${proto_i} ${nft_rule_params} ${dest4} comment \"$name\""
+		param6="$nftInsertOption rule inet ${nftTable} ${nftPrefix}_${chain} ${param6} meta nfproto ipv6 ${proto_i} ${nft_rule_params} ${dest6} comment \"$name\""
 
 		local ipv4_error='0' ipv6_error='0'
 		if [ "$policy_routing_nft_prev_param4" != "$param4" ] && \
@@ -2326,7 +2336,7 @@
 	fi
 	echo "$_SEPARATOR_"
 	echo "$packageName chains - policies"
-	for i in $chainsList dstnat_lan; do
+	for i in $chainsList dstnat; do
 		"$nft" -a list table inet "$nftTable" | sed -n "/chain ${nftPrefix}_${i} {/,/\t}/p"
 	done
 	echo "$_SEPARATOR_"
1 Like

DNS policy is a simple redirect of DNS53 so does not work as is with encrypted dns and also is not compatible with other DNS redirect like DNS hijacking (which is installed automatically with HTTPS DNS proxy)

I have an idea how to deal with this, basically add procd_dns_port so that you can redirect to a different port, on that port you can have a instance of an (encrypted) dns server running so basically using splitdns.

Will ask Stan if this is feasible and if so will make a write up when I am back

1 Like

I tried to test pbr, but it doesn't seem work when resolver_set is dnsmasq.nftset, it still showing WAN IP instead of wg IP. If resolver_set is none, it's ok.
Here is my config:

ubus call system board
{
        "kernel": "5.15.137",
        "hostname": "Router",
        "system": "MediaTek MT7621 ver:1 eco:3",
        "model": "Xiaomi Mi Router CR6608",
        "board_name": "xiaomi,mi-router-cr6608",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "23.05.2",
                "revision": "r23630-842932a63d",
                "target": "ramips/mt7621",
                "description": "OpenWrt 23.05.2 r23630-842932a63d"
        }
}

-----------------------------------------
uci export dhcp
all
uci export network
uci export pbrpackage dhcp

config dnsmasq
        option domainneeded '1'
        option localise_queries '1'
        option rebind_protection '1'
        option rebind_localhost '1'
        option local '/lan/'
        option domain 'lan'
        option expandhosts '1'
        option authoritative '1'
        option readethers '1'
        option leasefile '/tmp/dhcp.leases'
        option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
        option localservice '1'
        option ednspacket_max '1232'

config dhcp 'lan'
        option interface 'lan'
        option leasetime '12h'
        option dhcpv4 'server'
        option start '2'
        option limit '255'
        list dhcp_option '6,192.168.1.66'

config dhcp 'wan'
        option interface 'wan'
        option ignore '1'

config odhcpd 'odhcpd'
        option maindhcp '0'
        option leasefile '/tmp/hosts/odhcpd'
        option leasetrigger '/usr/sbin/odhcpd-update'
        option loglevel '4'

config host
        option name 'PC'
        option dns '1'
        option ip '192.168.1.99'
        option duid '000100012b2223aea8a1596cd380'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'RMMaster'
        option dns '1'
        option ip '192.168.1.14'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'RMTom'
        option dns '1'
        option ip '192.168.1.15'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'RMMT'
        option dns '1'
        option ip '192.168.1.16'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'SmartPlug'
        option dns '1'
        option ip '192.168.1.30'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'RMProPlus'
        option dns '1'
        option ip '192.168.1.55'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'Raspberry'
        option dns '1'
        option ip '192.168.1.66'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'Synology'
        option dns '1'
        option ip '192.168.1.68'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'CamOutdoor'
        option dns '1'
        option ip '192.168.1.88'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'CamIndoor'
        option dns '1'
        option ip '192.168.1.133'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'M5-Main'
        option dns '1'
        option ip '192.168.1.60'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'M5-LR'
        option dns '1'
        option ip '192.168.1.61'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'M5-BR'
        option dns '1'
        option ip '192.168.1.62'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'CamMT'
        option dns '1'
        option ip '192.168.1.90'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option name 'CamTS'
        option dns '1'
        option ip '192.168.1.89'
        list mac 'REDACT'
        option leasetime 'infinite'

config host
        option ip '192.168.1.77'
        option leasetime 'infinite'
        option name 'TV'
        list mac 'REDACT'
        option dns '1'


uci export firewall
package firewall

config defaults
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option synflood_protect '1'
        option drop_invalid '1'
        option flow_offloading '1'
        option flow_offloading_hw '1'

config zone
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'lan'
        option mtu_fix '1'

config zone
        option name 'wan'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'
        list network 'wan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'HTTP'
        option family 'ipv4'
        list proto 'tcp'
        option src 'wan'
        option dest_ip '192.168.1.66'
        option src_dport '80'
        option dest_port '80'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'HTTP_8080'
        option family 'ipv4'
        list proto 'tcp'
        option src 'wan'
        option src_dport '8080'
        option dest_ip '192.168.1.66'
        option dest_port '8080'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'HTTPS'
        option family 'ipv4'
        list proto 'tcp'
        option src 'wan'
        option src_dport '443'
        option dest_ip '192.168.1.66'
        option dest_port '443'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'RDP'
        option family 'ipv4'
        list proto 'tcp'
        option src 'wan'
        option src_dport 'REDACT'
        option dest_ip '192.168.1.99'
        option dest_port 'REDACT'
        option enabled '0'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'DNS'
        option src 'wan'
        option src_dport '8443'
        option dest_ip '192.168.1.66'
        option dest_port '8443'

config redirect
        option dest 'lan'
        option target 'DNAT'
        option name 'DMZ'
        option family 'ipv4'
        option src 'wan'
        option src_dport '1-65535'
        option dest_ip '192.168.1.68'

config rule
        option proto 'igmp'
        option target 'ACCEPT'
        option src 'lan'
        option enabled '0'

config rule
        option proto 'udp'
        option target 'ACCEPT'
        option src 'lan'
        list dest_ip '224.0.0.0/4'
        option enabled '0'

config rule
        option name 'PC'
        list proto 'all'
        option src 'lan'
        list src_ip '192.168.1.99'
        option dest 'wan'
        option target 'ACCEPT'
        option enabled '0'

config rule
        option name 'Block'
        option src 'lan'
        option dest 'wan'
        option target 'REJECT'
        list proto 'all'
        list dest_ip '162.159.193.0/22'
        list dest_ip '162.159.46.1'
        list dest_ip '162.159.36.1'
        list dest_ip '162.159.197.0/24'
        list dest_ip '162.159.137.105'
        list dest_ip '162.159.138.105'

config rule
        option name 'IPad1'
        option src 'lan'
        list src_mac 'REDACT'
        option dest 'wan'
        option target 'REJECT'
        option weekdays 'Sun'
        option start_time '19:00:00'
        option stop_time '23:59:59'
        list proto 'all'

config rule
        option name 'iPad'
        option src 'lan'
        list src_mac 'REDACT'
        option dest 'wan'
        option target 'REJECT'
        option weekdays 'Mon Tue Wed Thu Fri'
        option start_time '21:30:00'
        option stop_time '19:00:00'
        list proto 'all'

config zone
        option name 'sgvpn'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        list network 'sgVPN'
        option mtu_fix '1'

config forwarding
        option src 'lan'
        option dest 'sgvpn'

config include 'pbr'
        option fw4_compatible '1'
        option type 'script'
        option path '/usr/share/pbr/firewall.include'

config forwarding
        option src 'lan'
        option dest 'wan'

-------------------------------------------
uci export network
package network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        option igmp_snooping '1'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask '255.255.255.0'
        option ip6assign '60'
        option igmp_snooping '1'
        option delegate '0'
        option ipv6 '0'

config interface 'wan'
        option proto 'pppoe'
        option username 'REDACT'
        option ipv6 '0'
        option password 'REDACT'
        option delegate '0'
        option keepalive '1 5'
        option device 'wan'
        option peerdns '0'
        list dns '8.8.8.8'
        list dns '8.8.4.4'

config device
        option name 'wan'

config interface 'sgVPN'
        option proto 'wireguard'
        option private_key 'REDACT'
        list addresses '10.8.0.6/24'
        list dns '8.8.8.8'

config wireguard_sgVPN
        option description 'Imported peer configuration'
        option public_key 'REDACT'
        option preshared_key 'REDACT'
        list allowed_ips '0.0.0.0/0'
        list allowed_ips '::/0'
        option endpoint_host 'REDACT'
        option endpoint_port 'REDACT'
        option persistent_keepalive '25'

-------------------------------------------
uci export pbr
package pbr

config pbr 'config'
        option enabled '1'
        option verbosity '2'
        option strict_enforcement '1'
        option resolver_set 'dnsmasq.nftset'
        list resolver_instance '*'
        option ipv6_enabled '0'
        option boot_timeout '30'
        option rule_create_option 'add'
        option procd_boot_delay '0'
        option procd_reload_delay '1'
        option webui_show_ignore_target '0'
        option nft_rule_counter '0'
        option nft_set_auto_merge '1'
        option nft_set_counter '0'
        option nft_set_flags_interval '1'
        option nft_set_flags_timeout '0'
        option nft_set_policy 'performance'
        list webui_supported_protocol 'all'
        list webui_supported_protocol 'tcp'
        list webui_supported_protocol 'udp'
        list webui_supported_protocol 'tcp udp'
        list webui_supported_protocol 'icmp'

config include
        option path '/usr/share/pbr/pbr.user.aws'
        option enabled '0'

config include
        option path '/usr/share/pbr/pbr.user.netflix'
        option enabled '0'

config include
        option path '/usr/share/pbr/pbr.user.wg_server_and_client'
        option enabled '0'

config dns_policy
        option name 'Redirect Local IP DNS'
        option src_addr '192.168.1.99'
        option dest_dns '1.1.1.1'
        option enabled '0'

config policy
        option name 'Ignore Local Requests'
        option interface 'ignore'
        option dest_addr '10.0.0.0/24 10.0.1.0/24 192.168.100.0/24 192.168.1.0/24'
        option enabled '0'

config policy
        option name 'Plex/Emby Local Server'
        option interface 'wan'
        option src_port '8096 8920 32400'
        option enabled '0'

config policy
        option name 'Netflix'
        option dest_addr 'icanhazip.com'
        option interface 'sgVPN'

-------------------------------------
/etc/init.d/pbr status

pbr - environment
pbr 1.1.6-20 running on OpenWrt 23.05.2.

Dnsmasq version 2.90  Copyright (c) 2000-2024 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack no-ipset nftset auth cryptohash DNSSEC no-ID loop-detect inotify dumpfile

pbr fw4 nft file: /usr/share/nftables.d/ruleset-post/30-pbr.nft
add chain inet fw4 pbr_mark_0x010000
add rule inet fw4 pbr_mark_0x010000  mark set mark and 0xff00ffff xor 0x010000
add rule inet fw4 pbr_mark_0x010000 return
add chain inet fw4 pbr_mark_0x020000
add rule inet fw4 pbr_mark_0x020000  mark set mark and 0xff00ffff xor 0x020000
add rule inet fw4 pbr_mark_0x020000 return
add set inet fw4 pbr_sgVPN_4_dst_ip_cfg086ff5 { type ipv4_addr;                  auto-merge;                            flags interval;                                  policy performance;                             comment "Netflix"; }
add rule inet fw4 pbr_prerouting ip daddr @pbr_sgVPN_4_dst_ip_cfg086ff5  goto pbr_mark_0x020000 comment "Netflix"

pbr chains - policies
        chain pbr_forward { # handle 40
        }
        chain pbr_input { # handle 41
        }
        chain pbr_output { # handle 42
        }
        chain pbr_postrouting { # handle 44
        }
        chain pbr_prerouting { # handle 43
                ip daddr @pbr_sgVPN_4_dst_ip_cfg086ff5 goto pbr_mark_0x020000 comment "Netflix" # handle 5073
        }
        chain pbr_dstnat_lan { # handle 39
        }

pbr chains - marking
        chain pbr_mark_0x010000 { # handle 5066
                meta mark set meta mark & 0xff01ffff | 0x00010000 # handle 5067
                return # handle 5068
        }
        chain pbr_mark_0x020000 { # handle 5069
                meta mark set meta mark & 0xff02ffff | 0x00020000 # handle 5070
                return # handle 5071
        }

pbr nft sets
        set pbr_sgVPN_4_dst_ip_cfg086ff5 { # handle 5072
                type ipv4_addr
                flags interval
                auto-merge
                comment "Netflix"
        }

dnsmasq sets
nftset=/icanhazip.com/4#inet#fw4#pbr_sgVPN_4_dst_ip_cfg086ff5 # Netflix

IPv4 table 256 route: default via 203.210.148.67 dev pppoe-wan
IPv4 table 256 rule(s):
30000:  from all fwmark 0x10000/0xff0000 lookup pbr_wan
IPv4 table 257 route: default via 10.8.0.6 dev sgVPN
IPv4 table 257 rule(s):
29998:  from all fwmark 0x20000/0xff0000 lookup pbr_sgVPN


--------------------------------------------------------
/etc/init.d/pbr reload
Using wan interface (on_start): wan
Found wan gateway (on_start): 203.210.x.x
Setting up routing for 'wan/pppoe-wan/203.210.x.x' [✓]
Setting up routing for 'sgVPN/10.8.0.6' [✓]
Routing 'Netflix' via sgVPN [✓]
Installing fw4 nft file [✓]
pbr 1.1.6-20 monitoring interfaces: wan sgVPN
Restarting dnsmasq [✓]
pbr 1.1.6-20 (fw4 nft file mode) started with gateways:
wan/pppoe-wan/203.210.x.x [✓]
sgVPN/10.8.0.6

Is it likely to be easily fixed in the future?

Check the output of

nft -c -f /var/run/pbr.nft 

In my case, the rules created for tor policies were wrong.

			param4="$nftInsertOption rule inet $nftTable dstnat meta nfproto ipv4 $param4"
			param6="$nftInsertOption rule inet $nftTable dstnat meta nfproto ipv6 $param6"
			dest_udp_53="udp dport 53 counter redirect to :${torDnsPort} comment \"Tor-DNS-UDP\""
			dest_tcp_80="tcp dport 80 counter redirect to :${torTrafficPort} comment \"Tor-HTTP-TCP\""
			dest_udp_80="udp dport 80 counter redirect to :${torTrafficPort} comment \"Tor-HTTP-UDP\""
			dest_tcp_443="tcp dport 443 counter redirect to :${torTrafficPort} comment \"Tor-HTTPS-TCP\""
			dest_udp_443="udp dport 443 counter redirect to :${torTrafficPort} comment \"Tor-HTTPS-UDP\""

fw4 file is now installed correctly again. Tor policies work.

Further, it seems, nft rules for output policies have no effect. We already had this problem once.

1 Like

Seems like there are issues with your custom user file, my bet is that's what's preventing fw4 nft user file from working.

For the OpenVPN tunnel setup, can you post/PM me the output of ip -4 route list table main when the tunnel is up as well as when the tunnel is down?

Thanks will do that. I did notice that but didn't understand the significance.

Thanks to @egc and @ENKI the 1.1.7-19 has fixes for:

  • dropping dependency on dstnat_lan (@egc fix)
  • better domain detection in is_domain() (@egc fix)
  • more reliable DNS policies (@egc fix)
  • proper chain name for tor policies (@ENKI fix)

@ENKI -- dunno how I missed duplicate chain names in tor policies before, but instead of inserting policies into dstnat chain like in your fix, they are being inserted into pbr_dstnat chain which can be properly cleaned on stop. If you can elaborate on the OUTPUT policies I can look into it.

1 Like

@stangri

Just looked at /usr/share/pbr/pbr.user.aws and optimized it a bit. Its untested but produces the same nft command line.

I did some speed testing and the results looks promising:

  • first-run (200%) ~2x
  • second-run (2000%) ~20x

Awk seems to be a better tool for this particular script.

Updated version
  • first-run
# time ./pbr.user.aws.new
real	0m 2.10s
user	0m 0.15s
sys	0m 0.08s
  • second-run
# time ./pbr.user.aws.new
real	0m 0.12s
user	0m 0.12s
sys	0m 0.02s
  • code
#!/bin/sh

URL="https://ip-ranges.amazonaws.com/ip-ranges.json"
DB="/var/pbr_tmp_aws_ip_ranges.gz"

TABLE='inet fw4'
IFACE='wan'
NFTSET_4="pbr_${IFACE}_4_dst_ip_user"
#NFTSET_6="pbr_${IFACE}_6_dst_ip_user" 

_ret=0

[ -s "$DB" ] || uclient-fetch --no-check-certificate -qO- $URL | gzip > $DB

params=$(zcat $DB | awk -F\" '/ip_prefix/{printf "%s%s",sep,$4;sep=", "}')
[ -n "$params" ] && nft "add element $TABLE $NFTSET_4 { $params }" || _ret=1

[ -n "$NFTSET_6" ] || return $_ret

params=$(zcat $DB | awk -F\" '/ipv6_prefix/{printf "%s%s",sep,$4;sep=", "}')
[ -n "$params" ] && nft "add element $TABLE $NFTSET_6 { $params }" || _ret=1

return $_ret
Current version
  • first-run
# time ./pbr.user.aws
real	0m 5.12s
user	0m 2.13s
sys	0m 0.37s
  • second-run
# time ./pbr.user.aws
real	0m 2.33s
user	0m 1.96s
sys	0m 0.35s
  • code
#!/bin/sh
# This file is heavily based on code from https://github.com/Xentrk/netflix-vpn-bypass/blob/master/IPSET_Netflix.sh

TARGET_INTERFACE='wan'
TARGET_NFTSET_4="pbr_${TARGET_INTERFACE}_4_dst_ip_user"
TARGET_NFTSET_6="pbr_${TARGET_INTERFACE}_6_dst_ip_user"
TARGET_TABLE='inet fw4'
TARGET_URL="https://ip-ranges.amazonaws.com/ip-ranges.json"
TARGET_DL_FILE_4="/var/pbr_tmp_aws_ip_ranges.ipv4"
# Uncomment the following line if you enabled ipv6 for pbr and want IPv6 entries added to the IPv6 set
# TARGET_DL_FILE_6="/var/pbr_tmp_aws_ip_ranges.ipv6"
_ret=0

if [ ! -s "$TARGET_DL_FILE_4" ]; then
        uclient-fetch --no-check-certificate -qO- "$TARGET_URL" 2>/dev/null | grep "ip_prefix" | sed 's/^.*\"ip_prefix\": \"//; s/\",//' > "$TARGET_DL_FILE_4"
fi

if [ -s "$TARGET_DL_FILE_4" ]; then
        params=
        while read -r p; do params="${params:+$params, }${p}"; done < "$TARGET_DL_FILE_4"
        [ -n "$params" ] && nft "add element $TARGET_TABLE $TARGET_NFTSET_4 { $params }" || _ret=1
fi

if [ -n "$TARGET_DL_FILE_6" ] && [ ! -s "$TARGET_DL_FILE_6" ]; then
        uclient-fetch --no-check-certificate -qO- "$TARGET_URL" 2>/dev/null | grep "ipv6_prefix" | sed 's/^.*\"ipv6_prefix\": \"//; s/\",//' > "$TARGET_DL_FILE_6"
fi

if [ -s "$TARGET_DL_FILE_6" ]; then
        params=
        while read -r p; do params="${params:+$params, }${p}"; done < "$TARGET_DL_FILE_6"
        [ -n "$params" ] && nft "add element $TARGET_TABLE $TARGET_NFTSET_6 { $params }" || _ret=1
fi

return $_ret
1 Like
I'm trying to configure PBR version 1.1.6 on OpenWRT 23.05.4 using the standard x86 64 build on a PC Engines APU2. 
I've followed the PBR guide and have dnsmasq-full installed.

The wan interface is the default route and tun0 is an OpenVPN client.

My router with OpenVPN client is in Portugal and the VPN server is in the UK.

If I route ipleak.net through the vpn (pre-routing chain), Quad9 dns through the vpn (output routing chain), and set DNS Forwards /ipleak.net/9.9.9.9 then I get the following results:

- Using Dnsmasq nft set for domain resolver set support - Portuguese IP address, UK DNS servers
- Disable domain resolver set support - UK IP address, UK DNS servers

I've flushed caches, rebooted all devices (router, iPhone, Linux PC/Firefox, Mac M2) etc etc and I still get the same result. 
I would expect the same result whether or not I use Dnsmasq nft set for resolving domains.

I can live with not using Dnsmasq nft sets except that bbc.co.uk keeps redirecting to the international site. 
With my previous build (OpenWRT 19.07.5, VPN-Policy-Routing 0.2.1-13) this was rock solid - I just routed bbc.co.uk (prerouting chain) to the vpn and every device on my network got bbc.co.uk 
This is also why I think there is a problem somewhere. 

I've worked through my config several times and can't find any obvious problems, so could someone with a better understanding of PBR take a look please?

I've uploaded all files requested in the Wiki, but removed sensitive info and unnecessary config such as static lease info.
#!/usr/sbin/nft -f

add chain inet fw4 pbr_mark_0x010000
add rule inet fw4 pbr_mark_0x010000  mark set mark and 0xff00ffff xor 0x010000
add rule inet fw4 pbr_mark_0x010000 return
add chain inet fw4 pbr_mark_0x020000
add rule inet fw4 pbr_mark_0x020000  mark set mark and 0xff00ffff xor 0x020000
add rule inet fw4 pbr_mark_0x020000 return
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.54 } ip daddr { 151.101.64.81,151.101.0.81,151.101.192.81,151.101.128.81 }  goto pbr_mark_0x020000 comment "KevinMacBookAir"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.1 } tcp sport { 5201 } tcp dport { 5201 }  goto pbr_mark_0x020000 comment "iPerf"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.1 } udp sport { 5201 } udp dport { 5201 }  goto pbr_mark_0x020000 comment "iPerf"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.6 }  goto pbr_mark_0x020000 comment "ATV4k.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.7 }  goto pbr_mark_0x020000 comment "FireTV.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 43.250.140.36 }  goto pbr_mark_0x020000 comment "SkippySky"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.5 }  goto pbr_mark_0x020000 comment "LG-TV.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 212.58.249.206,212.58.249.207,212.58.244.129,212.58.244.210 }  goto pbr_mark_0x020000 comment "BBCi"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 151.101.64.81,151.101.0.81,151.101.192.81,151.101.128.81 }  goto pbr_mark_0x020000 comment "BBC-UK"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 151.101.192.81,151.101.0.81,151.101.64.81,151.101.128.81 }  goto pbr_mark_0x020000 comment "BBC-COM"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 88.221.66.76 }  goto pbr_mark_0x020000 comment "BA"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.162 }  goto pbr_mark_0x020000 comment "Denise-iPhone"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 95.100.104.10,95.100.104.24 }  goto pbr_mark_0x020000 comment "EbayUK"
add rule inet fw4 pbr_prerouting ip daddr { 192.168.2.1/24 }  goto pbr_mark_0x020000 comment "UK-Home"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 95.85.16.212 }  goto pbr_mark_0x020000 comment "IPLeak"
add rule inet fw4 pbr_output ip daddr { 9.9.9.9 }  goto pbr_mark_0x020000 comment "Quad9-DNS-for-VPN"
add rule inet fw4 pbr_prerouting ip daddr { 23.239.16.110 }  goto pbr_mark_0x020000 comment "DNSLeakTest"



*package dhcp*

config dnsmasq
	option domainneeded '1'
	option localise_queries '1'
	option rebind_protection '1'
	option rebind_localhost '1'
	option local '/lan/'
	option domain 'lan'
	option expandhosts '1'
	option cachesize '1000'
	option authoritative '1'
	option readethers '1'
	option leasefile '/tmp/dhcp.leases'
	option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
	option localservice '1'
	option ednspacket_max '1232'
	list server '1.1.1.1'
	list server '/ipleak.net/dnsleaktest.com/9.9.9.9'
	list server '/bbc.co.uk/bbc.com/9.9.9.9'

config dhcp 'lan'
	option interface 'lan'
	option start '100'
	option limit '150'
	option leasetime '12h'
	option force '1'

config dhcp 'wan'
	option interface 'wan'
	option ignore '1'

config host
	option mac 'XX:XX:XX:XX:XX:XX'
	option name 'ATV4k.lan'
	option dns '1'
	option ip '192.168.1.6'

*package firewall*

config defaults
	option syn_flood '1'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'

config zone
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'lan'

config zone
	option name 'wan'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'
	list network 'wan'

config zone
	option name 'vpn'
	option input 'ACCEPT'
	option forward 'ACCEPT'
	option output 'ACCEPT'
	option network 'vpn0'
	option masq '1'

config forwarding
	option dest 'vpn'
	option src 'lan'

config forwarding
	option src 'lan'
	option dest 'wan'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'
	list src_ip 'fc00::/6'
	list dest_ip 'fc00::/6'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

config include 'pbr'
	option fw4_compatible '1'
	option type 'script'
	option path '/usr/share/pbr/firewall.include'

*package network*

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fd1b:0d9b:f1f3::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth1'
	list ports 'eth2'
	option ipv6 '0'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'
	option ip6assign '60'

config interface 'wan'
	option device 'eth0'
	option proto 'dhcp'
	option peerdns '0'
	list dns '185.228.168.9'

config interface 'vpn0'
	option ifname 'tun0'
	option proto 'none'
	option device 'tun0'

config device
	option name 'eth0'
	option ipv6 '0'

config device
	option name 'eth1'
	option ipv6 '0'

config device
	option name 'eth2'
	option ipv6 '0'

config device
	option name 'tun0'
	option ipv6 '0'



*package pbr*

config pbr 'config'
	option enabled '1'
	option verbosity '2'
	option strict_enforcement '1'
	option resolver_set 'none'
	list resolver_instance '*'
	option ipv6_enabled '0'
	list ignored_interface 'vpnserver'
	option boot_timeout '30'
	option rule_create_option 'add'
	option procd_boot_delay '0'
	option procd_reload_delay '1'
	option webui_show_ignore_target '0'
	option nft_rule_counter '0'
	option nft_set_auto_merge '1'
	option nft_set_counter '0'
	option nft_set_flags_interval '1'
	option nft_set_flags_timeout '0'
	option nft_set_policy 'performance'
	list webui_supported_protocol 'all'
	list webui_supported_protocol 'tcp'
	list webui_supported_protocol 'udp'
	list webui_supported_protocol 'tcp udp'
	list webui_supported_protocol 'icmp'
	list supported_interface 'vpn0'

config include
	option path '/usr/share/pbr/pbr.user.aws'
	option enabled '0'

config include
	option path '/usr/share/pbr/pbr.user.netflix'
	option enabled '0'

config include
	option path '/usr/share/pbr/pbr.user.wg_server_and_client'
	option enabled '0'

config policy
	option name 'Plex/Emby Local Server'
	option interface 'wan'
	option src_port '8096 8920 32400'
	option enabled '0'

config policy
	option name 'Plex/Emby Remote Servers'
	option interface 'wan'
	option dest_addr 'plex.tv my.plexapp.com emby.media app.emby.media tv.emby.media'
	option enabled '0'

config policy
	option name 'ATV4k.lan'
	option src_addr '192.168.1.6'
	option interface 'vpn0'

config policy
	option name 'FireTV.lan'
	option src_addr '192.168.1.7'
	option interface 'vpn0'

config policy
	option name 'BBCi'
	option dest_addr 'bbci.co.uk'
	option interface 'vpn0'
	option src_addr '192.168.1.0/24'

config policy
	option dest_addr 'bbc.co.uk'
	option interface 'vpn0'
	option name 'BBC-UK'
	option src_addr '192.168.1.0/24'

config policy
	option name 'BBC-COM'
	option dest_addr 'bbc.com'
	option interface 'vpn0'
	option src_addr '192.168.1.0/24'

config policy
	option interface 'vpn0'
	option name 'UK-home'
	option dest_addr '192.168.2.1/24'

config policy
	option name 'IPLeak'
	option dest_addr 'ipleak.net'
	option interface 'vpn0'
	option src_addr '192.168.1.0/24'

config policy
	option name 'Quad9-DNS-for-VPN'
	option dest_addr '9.9.9.9'
	option chain 'output'
	option interface 'vpn0'

config policy
	option name 'DNSLeakTest'
	option dest_addr 'dnsleaktest.com'
	option interface 'vpn0'



*/etc/init.d/pbr status*

pbr - environment
pbr 1.1.6-20 running on OpenWrt 23.05.4.

Dnsmasq version 2.90  Copyright (c) 2000-2024 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack no-ipset nftset auth cryptohash DNSSEC no-ID loop-detect inotify dumpfile

pbr fw4 nft file: /usr/share/nftables.d/ruleset-post/30-pbr.nft
add chain inet fw4 pbr_mark_0x010000
add rule inet fw4 pbr_mark_0x010000  mark set mark and 0xff00ffff xor 0x010000
add rule inet fw4 pbr_mark_0x010000 return
add chain inet fw4 pbr_mark_0x020000
add rule inet fw4 pbr_mark_0x020000  mark set mark and 0xff00ffff xor 0x020000
add rule inet fw4 pbr_mark_0x020000 return
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.54 } ip daddr { 151.101.128.81,151.101.192.81,151.101.0.81,151.101.64.81 }  goto pbr_mark_0x020000 comment "KevinMacBookAir"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.1 } tcp sport { 5201 } tcp dport { 5201 }  goto pbr_mark_0x020000 comment "iPerf"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.1 } udp sport { 5201 } udp dport { 5201 }  goto pbr_mark_0x020000 comment "iPerf"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.6 }  goto pbr_mark_0x020000 comment "ATV4k.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.7 }  goto pbr_mark_0x020000 comment "FireTV.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 43.250.140.36 }  goto pbr_mark_0x020000 comment "SkippySky"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.5 }  goto pbr_mark_0x020000 comment "LG-TV.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 212.58.249.206,212.58.249.207,212.58.244.129,212.58.244.210 }  goto pbr_mark_0x020000 comment "BBCi"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 151.101.128.81,151.101.192.81,151.101.0.81,151.101.64.81 }  goto pbr_mark_0x020000 comment "BBC-UK"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 151.101.64.81,151.101.128.81,151.101.0.81,151.101.192.81 }  goto pbr_mark_0x020000 comment "BBC-COM"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 88.221.66.76 }  goto pbr_mark_0x020000 comment "BA"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.162 }  goto pbr_mark_0x020000 comment "Denise-iPhone"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 23.48.165.132,23.48.165.141 }  goto pbr_mark_0x020000 comment "EbayUK"
add rule inet fw4 pbr_prerouting ip daddr { 192.168.2.1/24 }  goto pbr_mark_0x020000 comment "UK-Home"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 95.85.16.212 }  goto pbr_mark_0x020000 comment "IPLeak"
add rule inet fw4 pbr_output ip daddr { 9.9.9.9 }  goto pbr_mark_0x020000 comment "Quad9-DNS-for-VPN"
add rule inet fw4 pbr_prerouting ip daddr { 23.239.16.110 }  goto pbr_mark_0x020000 comment "DNSLeakTest"

pbr chains - policies
	chain pbr_forward { # handle 39
	}
	chain pbr_input { # handle 40
	}
	chain pbr_output { # handle 41
		ip daddr 9.9.9.9 goto pbr_mark_0x020000 comment "Quad9-DNS-for-VPN" # handle 3684
	}
	chain pbr_postrouting { # handle 43
	}
	chain pbr_prerouting { # handle 42
		ip saddr 192.168.1.54 ip daddr { 151.101.0.81, 151.101.64.81, 151.101.128.81, 151.101.192.81 } goto pbr_mark_0x020000 comment "KevinMacBookAir" # handle 3665
		ip saddr 192.168.1.1 tcp sport 5201 tcp dport 5201 goto pbr_mark_0x020000 comment "iPerf" # handle 3666
		ip saddr 192.168.1.1 udp sport 5201 udp dport 5201 goto pbr_mark_0x020000 comment "iPerf" # handle 3667
		ip saddr 192.168.1.6 goto pbr_mark_0x020000 comment "ATV4k.lan" # handle 3668
		ip saddr 192.168.1.7 goto pbr_mark_0x020000 comment "FireTV.lan" # handle 3669
		ip saddr 192.168.1.0/24 ip daddr 43.250.140.36 goto pbr_mark_0x020000 comment "SkippySky" # handle 3670
		ip saddr 192.168.1.5 goto pbr_mark_0x020000 comment "LG-TV.lan" # handle 3671
		ip saddr 192.168.1.0/24 ip daddr { 212.58.244.129, 212.58.244.210, 212.58.249.206, 212.58.249.207 } goto pbr_mark_0x020000 comment "BBCi" # handle 3673
		ip saddr 192.168.1.0/24 ip daddr { 151.101.0.81, 151.101.64.81, 151.101.128.81, 151.101.192.81 } goto pbr_mark_0x020000 comment "BBC-UK" # handle 3675
		ip saddr 192.168.1.0/24 ip daddr { 151.101.0.81, 151.101.64.81, 151.101.128.81, 151.101.192.81 } goto pbr_mark_0x020000 comment "BBC-COM" # handle 3677
		ip saddr 192.168.1.0/24 ip daddr 88.221.66.76 goto pbr_mark_0x020000 comment "BA" # handle 3678
		ip saddr 192.168.1.162 goto pbr_mark_0x020000 comment "Denise-iPhone" # handle 3679
		ip saddr 192.168.1.0/24 ip daddr { 23.48.165.132, 23.48.165.141 } goto pbr_mark_0x020000 comment "EbayUK" # handle 3681
		ip daddr 192.168.2.0/24 goto pbr_mark_0x020000 comment "UK-Home" # handle 3682
		ip saddr 192.168.1.0/24 ip daddr 95.85.16.212 goto pbr_mark_0x020000 comment "IPLeak" # handle 3683
		ip daddr 23.239.16.110 goto pbr_mark_0x020000 comment "DNSLeakTest" # handle 3685
	}
	chain pbr_dstnat_lan { # handle 38
	}

pbr chains - marking
	chain pbr_mark_0x010000 { # handle 3658
		meta mark set meta mark & 0xff01ffff | 0x00010000 # handle 3659
		return # handle 3660
	}
	chain pbr_mark_0x020000 { # handle 3661
		meta mark set meta mark & 0xff02ffff | 0x00020000 # handle 3662
		return # handle 3663
	}

pbr nft sets

IPv4 table 256 route: default via 176.78.90.1 dev eth0 
IPv4 table 256 rule(s):
30000:	from all fwmark 0x10000/0xff0000 lookup pbr_wan
IPv4 table 257 route: default via 10.8.0.6 dev tun0 
IPv4 table 257 rule(s):
29998:	from all fwmark 0x20000/0xff0000 lookup pbr_vpn0



*/etc/init.d/pbr status (after reload)*

pbr - environment
pbr 1.1.6-20 running on OpenWrt 23.05.4.

Dnsmasq version 2.90  Copyright (c) 2000-2024 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack no-ipset nftset auth cryptohash DNSSEC no-ID loop-detect inotify dumpfile

pbr fw4 nft file: /usr/share/nftables.d/ruleset-post/30-pbr.nft
add chain inet fw4 pbr_mark_0x010000
add rule inet fw4 pbr_mark_0x010000  mark set mark and 0xff00ffff xor 0x010000
add rule inet fw4 pbr_mark_0x010000 return
add chain inet fw4 pbr_mark_0x020000
add rule inet fw4 pbr_mark_0x020000  mark set mark and 0xff00ffff xor 0x020000
add rule inet fw4 pbr_mark_0x020000 return
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.54 } ip daddr { 151.101.64.81,151.101.0.81,151.101.192.81,151.101.128.81 }  goto pbr_mark_0x020000 comment "KevinMacBookAir"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.1 } tcp sport { 5201 } tcp dport { 5201 }  goto pbr_mark_0x020000 comment "iPerf"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.1 } udp sport { 5201 } udp dport { 5201 }  goto pbr_mark_0x020000 comment "iPerf"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.6 }  goto pbr_mark_0x020000 comment "ATV4k.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.7 }  goto pbr_mark_0x020000 comment "FireTV.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 43.250.140.36 }  goto pbr_mark_0x020000 comment "SkippySky"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.5 }  goto pbr_mark_0x020000 comment "LG-TV.lan"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 212.58.249.206,212.58.249.207,212.58.244.129,212.58.244.210 }  goto pbr_mark_0x020000 comment "BBCi"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 151.101.64.81,151.101.0.81,151.101.192.81,151.101.128.81 }  goto pbr_mark_0x020000 comment "BBC-UK"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 151.101.192.81,151.101.0.81,151.101.64.81,151.101.128.81 }  goto pbr_mark_0x020000 comment "BBC-COM"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 88.221.66.76 }  goto pbr_mark_0x020000 comment "BA"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.162 }  goto pbr_mark_0x020000 comment "Denise-iPhone"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 95.100.104.10,95.100.104.24 }  goto pbr_mark_0x020000 comment "EbayUK"
add rule inet fw4 pbr_prerouting ip daddr { 192.168.2.0/24 }  goto pbr_mark_0x020000 comment "UK-Home"
add rule inet fw4 pbr_prerouting ip saddr { 192.168.1.0/24 } ip daddr { 95.85.16.212 }  goto pbr_mark_0x020000 comment "IPLeak"
add rule inet fw4 pbr_output ip daddr { 9.9.9.9 }  goto pbr_mark_0x020000 comment "Quad9-DNS-for-VPN"
add rule inet fw4 pbr_prerouting ip daddr { 23.239.16.110 }  goto pbr_mark_0x020000 comment "DNSLeakTest"

pbr chains - policies
	chain pbr_forward { # handle 39
	}
	chain pbr_input { # handle 40
	}
	chain pbr_output { # handle 41
		ip daddr 9.9.9.9 goto pbr_mark_0x020000 comment "Quad9-DNS-for-VPN" # handle 3852
	}
	chain pbr_postrouting { # handle 43
	}
	chain pbr_prerouting { # handle 42
		ip saddr 192.168.1.54 ip daddr { 151.101.0.81, 151.101.64.81, 151.101.128.81, 151.101.192.81 } goto pbr_mark_0x020000 comment "KevinMacBookAir" # handle 3833
		ip saddr 192.168.1.1 tcp sport 5201 tcp dport 5201 goto pbr_mark_0x020000 comment "iPerf" # handle 3834
		ip saddr 192.168.1.1 udp sport 5201 udp dport 5201 goto pbr_mark_0x020000 comment "iPerf" # handle 3835
		ip saddr 192.168.1.6 goto pbr_mark_0x020000 comment "ATV4k.lan" # handle 3836
		ip saddr 192.168.1.7 goto pbr_mark_0x020000 comment "FireTV.lan" # handle 3837
		ip saddr 192.168.1.0/24 ip daddr 43.250.140.36 goto pbr_mark_0x020000 comment "SkippySky" # handle 3838
		ip saddr 192.168.1.5 goto pbr_mark_0x020000 comment "LG-TV.lan" # handle 3839
		ip saddr 192.168.1.0/24 ip daddr { 212.58.244.129, 212.58.244.210, 212.58.249.206, 212.58.249.207 } goto pbr_mark_0x020000 comment "BBCi" # handle 3841
		ip saddr 192.168.1.0/24 ip daddr { 151.101.0.81, 151.101.64.81, 151.101.128.81, 151.101.192.81 } goto pbr_mark_0x020000 comment "BBC-UK" # handle 3843
		ip saddr 192.168.1.0/24 ip daddr { 151.101.0.81, 151.101.64.81, 151.101.128.81, 151.101.192.81 } goto pbr_mark_0x020000 comment "BBC-COM" # handle 3845
		ip saddr 192.168.1.0/24 ip daddr 88.221.66.76 goto pbr_mark_0x020000 comment "BA" # handle 3846
		ip saddr 192.168.1.162 goto pbr_mark_0x020000 comment "Denise-iPhone" # handle 3847
		ip saddr 192.168.1.0/24 ip daddr { 95.100.104.10, 95.100.104.24 } goto pbr_mark_0x020000 comment "EbayUK" # handle 3849
		ip daddr 192.168.2.0/24 goto pbr_mark_0x020000 comment "UK-Home" # handle 3850
		ip saddr 192.168.1.0/24 ip daddr 95.85.16.212 goto pbr_mark_0x020000 comment "IPLeak" # handle 3851
		ip daddr 23.239.16.110 goto pbr_mark_0x020000 comment "DNSLeakTest" # handle 3853
	}
	chain pbr_dstnat_lan { # handle 38
	}

pbr chains - marking
	chain pbr_mark_0x010000 { # handle 3826
		meta mark set meta mark & 0xff01ffff | 0x00010000 # handle 3827
		return # handle 3828
	}
	chain pbr_mark_0x020000 { # handle 3829
		meta mark set meta mark & 0xff02ffff | 0x00020000 # handle 3830
		return # handle 3831
	}

pbr nft sets

IPv4 table 256 route: default via 176.78.90.1 dev eth0 
IPv4 table 256 rule(s):
30000:	from all fwmark 0x10000/0xff0000 lookup pbr_wan
IPv4 table 257 route: default via 10.8.0.6 dev tun0 
IPv4 table 257 rule(s):
29998:	from all fwmark 0x20000/0xff0000 lookup pbr_vpn0



*System Board*

{
	"kernel": "5.15.162",
	"hostname": "Portugal-APU2",
	"system": "AMD GX-412TC SOC",
	"model": "PC Engines APU2",
	"board_name": "pc-engines-apu2",
	"rootfs_type": "ext4",
	"release": {
		"distribution": "OpenWrt",
		"version": "23.05.4",
		"revision": "r24012-d8dd03c46f",
		"target": "x86/64",
		"description": "OpenWrt 23.05.4 r24012-d8dd03c46f"
	}
}

I like the idea of storing the file gzipped and for aws clearly there's no reason to keep separate ipv4/ipv6 files. If you want to keep the variable names unchanged/similar to the old/netflix version and decide to send a PR to my repo I'd be inclined to accept it. If you decide to bump the PKG_RELEASE, please keep it as an odd number.

VPN down:

ip -4 route list table main
default via 78.33.253.138 dev pppoe-wan proto static
10.10.3.0/24 dev br-lan.3 proto kernel scope link src 10.10.3.1
78.33.253.138 dev pppoe-wan proto kernel scope link src REDACT
192.168.5.0/24 dev br-lan.5 proto kernel scope link src 192.168.5.1
192.168.10.0/24 dev br-lan.1 proto kernel scope link src 192.168.10.1
192.168.50.0/24 dev wgserver proto kernel scope link src 192.168.50.1
192.168.88.0/24 dev br-lan.88 proto kernel scope link src 192.168.88.1

VPN up:

ip -4 route list table main
default via 78.33.253.138 dev pppoe-wan proto static
10.10.3.0/24 dev br-lan.3 proto kernel scope link src 10.10.3.1
10.100.0.0/24 dev tun0 proto kernel scope link src 10.100.0.2
78.33.253.138 dev pppoe-wan proto kernel scope link src REDACT
192.168.5.0/24 dev br-lan.5 proto kernel scope link src 192.168.5.1
192.168.10.0/24 dev br-lan.1 proto kernel scope link src 192.168.10.1
192.168.50.0/24 dev wgserver proto kernel scope link src 192.168.50.1
192.168.88.0/24 dev br-lan.88 proto kernel scope link src 192.168.88.1

I saw you are using zcat, I do not think it is available on all routers?