I made a custom script file for PBR and it worked with OpenWrt 23.05. It's more complex but if simplify (I use another interface and generate IPs in the file first) this command works in 23.05:
nft "add element inet fw4 pbr_wan_4_dst_ip_user { 139.59.210.197, }"
In 23.05 after command executed I can see in nft list ruleset that new set named pbr_wan_4_dst_ip_user created and some other rules, so it [was] not required to create it manualy.
Now I have router with OpenWrt 24.10 release and this command returns error:
Error: No such file or directory
add element inet fw4 pbr_wan_4_dst_ip_user { 139.59.210.197, }
^^^^^^^^^^^^^^^^^^^^^
If I add single IP to pbr interface it works in both 23 and 24 owrt (without creating new set).
23.05 (official build for ax6s): pbr 1.1.6-20 (nft mode), dnsmasq 2.90-2
24.10 (custom with small patches for ax3000t): pbr 1.1.8-r10 (fw4 nft file mode), dnsmasq-full 2.90-r4
Is it an error in PBR or nft or anything else and how to make this command work?
I tried with and without comma and even brackets (copilot suggested), it doesn't work. Without comma:
root@OpenWrt:~# nft "add element inet fw4 pbr_wan_4_dst_ip_user { 139.59.210.197 }"
Error: No such file or directory
add element inet fw4 pbr_wan_4_dst_ip_user { 139.59.210.197 }
^^^^^^^^^^^^^^^^^^^^^
Thanks, I'm trying to go the same way. I already have added the set the same way. But in my real case I need pbr_mark_0x020000 instead of pbr_mark_0x010000. I added it like this (the same way it looks in 23.05):
and added IP to the set and it even works.
But the problem is I don't want to hardcode pbr_mark_0x020000 because it may change and I don't mind what is this at all. Now I'm trying to find how this:
chain pbr_mark_0x020000 {
meta mark set meta mark & 0xff02ffff | 0x00020000
return
}
relates to the wg interface so I can parse something and extract it. I checked all these numbers in nft runtime config and in /etc/config/pbr but couldn't find any of these numbers.
Well it's done. This is all the script pbr.user.tun2vless.my.
#!/bin/sh
# This file is heavily based on code from https://github.com/Xentrk/netflix-vpn-bypass/blob/master/IPSET_Netflix.sh
# Modified for OpenWrt 24.10 because its NFT and PBR don't create set automatically
TARGET_INTERFACE='tun2vless'
TARGET_SET="my_${TARGET_INTERFACE}_4_dst_ip_user"
TARGET_TABLE='inet fw4'
TARGET_DL_FILE="/etc/pbr.list.my"
TARGET_NFT_FILE="/etc/pbr.list.my.nft"
PBR_TABLE="pbr_${TARGET_INTERFACE}"
# Get pbr magic number 0x20000 from output string:
# 29998: from all fwmark 0x20000/0xff0000 lookup pbr_tun2vless
# from command:
# ip rule show
# If doesn't work may try `ip route show table 100` if it will be like `100` instead of `pbr_tun2vless`
PBR_MARK_RAW=$(ip rule show | grep -m1 "${PBR_TABLE}" | awk 'match($0, /fwmark 0x[^\/]*/) {print substr($0, RSTART+9, RLENGTH-9)}')
# now PBR_MARK_RAW=20000
if [ -z "$PBR_MARK_RAW" ]; then
echo "Error: PBR_MARK_RAW is empty"
return 1
fi
# Find nft chain with this pbr mark, string looks like:
# chain pbr_mark_0x020000 {
NFT_CHAIN_RAW=$(nft list table inet fw4 | grep -m1 -E "\s*chain pbr_mark_0x0*${PBR_MARK_RAW}\s*\{\$")
if [ -z "$NFT_CHAIN_RAW" ]; then
echo "Error: NFT_CHAIN_RAW is empty"
return 1
fi
# Parse `pbr_mark_0x020000` chain name
NFT_CHAIN=$(echo "${NFT_CHAIN_RAW}" | awk 'match($0, /chain pbr_mark_0x[0-9a-f]*/) {print substr($0, RSTART+6, RLENGTH-6)}')
# now NFT_CHAIN=pbr_mark_0x020000
if [ -z "$NFT_CHAIN" ]; then
echo "Error: NFT_CHAIN is empty"
return 1
fi
# Create set
nft "add set inet fw4 ${TARGET_SET} {type ipv4_addr; flags interval; auto-merge; }"
# Create rule in chain
nft "add rule inet fw4 pbr_prerouting ip daddr @${TARGET_SET} goto ${NFT_CHAIN}"
[ -z "$nft" ] && nft="$(command -v nft)"
_ret=1
printf "add element %s %s { " "$TARGET_TABLE" "$TARGET_SET" > "$TARGET_NFT_FILE"
awk '/^\d/{printf $1 ", "}' "$TARGET_DL_FILE" >> "$TARGET_NFT_FILE"
printf " } " >> "$TARGET_NFT_FILE"
"$nft" -f "$TARGET_NFT_FILE"
_ret=0
return $_ret
It looks pbr.list.my file, skips empty and starting from # lines, takes other lines as IPv4, and adds them to go through specified interface.
Might be it may not work in some cases and then it's required to go deeper and extract interface name from like ip route show table 100 command (I put comment in case to remember), but for my it works without this.
I got a similar issue with pbr in 24.10.0 in connectíon with DSCPclassify but in my case the problem seems to be that pbr overrides the nft list table inet dscpclassify with every interface change (e.g. Wireguard or OpenVPN/tunX). I could be wrong but is my issue somewhat related to yours?
So I'd say instead of making a user file which contradicts the logic of the fw4 nft file use, rewrite the user file so that it adds to the fw4 nft file that pbr creates rather than call nft commands directly.
You're right, the set doesn't exist. And nft file should be used.
My first attempt was to make it work by putting my nft files near /usr/share/nftables.d/ruleset-post/30-pbr.nft file and it worked, almost okay except when I uncheck pbr user file then nft file still existed and applied. I partially solved this to make this file symlink to nft file in /tmp (it disappears after reboot).
But later I found how it works and how to make it without this workaround: PBR in 24.10 creates set for custom file after its execution - #12 by kanani