-
-
Save Kishi85/b7f379f9aa19f4878af28b8e1a8887ab to your computer and use it in GitHub Desktop.
| #!/bin/sh /etc/rc.common | |
| # Start before firewall and mwan3 which are at Prio 19 | |
| START=18 | |
| APP=nft2ipset | |
| USE_PROCD=1 | |
| SCRIPTPATH="/tmp/nft2ipset" | |
| write_script() { | |
| cat > "$1" <<'EOT' | |
| #!/bin/sh | |
| #check if the script is already running | |
| PID=$$ | |
| SCRIPT="$(basename $0)" | |
| TMPDIR="/tmp" | |
| MONITORPIDFILE="$TMPDIR/$SCRIPT-$$.nftmonitorpid" | |
| MONITORFIFO="$TMPDIR/$SCRIPT-$$.nftmonitorfifo" | |
| mkfifo "$MONITORFIFO" | |
| cleanup () { | |
| # Cleanup nft monitor subprocess | |
| if [ -f "$MONITORPIDFILE" ]; then | |
| MONITORPID="$(cat "$MONITORPIDFILE")" | |
| if [ "$MONITORPID" -gt 1 ]; then | |
| kill "$MONITORPID" | |
| fi | |
| fi | |
| # Remove pid file and fifo | |
| rm "$MONITORFIFO" "$MONITORPIDFILE" | |
| } | |
| trap cleanup TERM INT EXIT QUIT ABRT | |
| create_or_update_ipset() { | |
| # Determine ipset parameters | |
| local DEF="$1" | |
| local NAME="$(echo "$DEF" | cut -d' ' -f2)" | |
| local OPTS="" | |
| local FAMILY="inet" | |
| if echo "$DEF" | grep -q "ipv6_addr"; then | |
| FAMILY="inet6" | |
| OPTS="$OPTS family $FAMILY" | |
| fi | |
| local TIMEOUT="$(echo "$DEF" | sed -r 's/.*timeout ([0-9]*)s.*/\1/; t; s/.*/0/')" | |
| if [ -n "$TIMEOUT" -a "$TIMEOUT" -gt 0 ]; then | |
| OPTS="$OPTS timeout $TIMEOUT" | |
| fi | |
| # Create or update ipset from nftables set | |
| if [ "$(ipset list -n "$NAME")" = "$NAME" ]; then | |
| CUR="$(ipset list -t "$NAME")" | |
| if ! ( echo "$CUR" | grep -q "family $FAMILY"); then | |
| ( ipset destroy "$NAME" 2>&1 | logger -t "$SCRIPT" ) || logger -t "$SCRIPT" "WARNING: Could not destroy ipset with family != $FAMILY" | |
| elif ! ( echo "$CUR" | grep -q "timeout $TIMEOUT"); then | |
| # Swap current iteration of the ipset with a new iteration due to timeout mismatch | |
| ipset create "_$NAME" hash:ip $OPTS | |
| ipset swap "_$NAME" "$NAME" | |
| ipset destroy "_$NAME" | |
| logger -t "$SCRIPT" "Replaced ipset $NAME with new iteration with timeout $TIMEOUT" | |
| fi | |
| fi | |
| if [ "$(ipset list -n "$NAME")" != "$NAME" ]; then | |
| # Create a new ipset with options matching the nftables set | |
| ipset create "$NAME" hash:ip $OPTS | |
| # Restart mwan3 if this ipset is used by it, it is already running but the set name is not found in active rule output | |
| if [ $? = 0 ] && grep -q "option ipset '$NAME'" /etc/config/mwan3 2>/dev/null && ( service | grep mwan3 | grep running ) && ( ! (mwan3 rules | grep -q "match-set $NAME" ) ); then | |
| mwan3 restart | |
| fi | |
| logger -t "$SCRIPT" "Created new ipset $NAME with timeout $TIMEOUT" | |
| fi | |
| # Add already existing entries to the set | |
| echo "$DEF" | sed -re 's/.*elements = \{ ([^\}]+) \}.*/\1/g; t; s/.*//g' | tr ',' '\n' | sed -re 's/^[ ]+//g;s/expires/timeout/g;s/s$//g' | while read LINE; do | |
| if [ -n "$LINE" ]; then | |
| ipset -q add "$NAME" $LINE && logger -t "$SCRIPT" "Added $LINE to $NAME upon ipset creation/update" || true | |
| fi | |
| done | |
| } | |
| # Check if ipsets exist for all currently existing nftsets or create otherwise | |
| nft -nT list sets | tr '\n' ' ' | awk '{$1=$1;print}' | sed -r 's/ (set|table)/\n\1/g' | grep "^set" | while read DEF; do | |
| NAME="$(echo "$DEF" | cut -d' ' -f2)" | |
| if [ -z "$NAME" ] || ! grep -q "option ipset '$NAME'" /etc/config/mwan3; then | |
| logger -t "$SCRIPT" "Ignored set '$NAME' as it is invalid or not used by mwan3" | |
| else | |
| create_or_update_ipset "$DEF" | |
| fi | |
| done | |
| # Monitor nftables rule changes | |
| nft -nT monitor > "$MONITORFIFO" 2>&1 & | |
| echo $! > "$MONITORPIDFILE" | |
| while read LINE; do | |
| # Update ipsets according to specified nft monitor option (this should be always one operation per line) | |
| if echo "$LINE" | grep -q "add element inet"; then | |
| NAME="$(echo "$LINE" | cut -d' ' -f 5)" | |
| if [ -z "$NAME" ] || ! grep -q "option ipset '$NAME'" /etc/config/mwan3; then | |
| logger -t "$SCRIPT" "Ignored set '$NAME' as it is invalid or not used by mwan3" | |
| else | |
| # Check if ipset exists or create otherwise | |
| if [ "$(ipset list -n $NAME)" != "$NAME" ]; then | |
| DEF="$(nft -tnT list sets | tr '\n' ' ' | awk '{$1=$1;print}' | sed -r 's/ (set|table)/\n\1/g' | grep "^set $NAME")" | |
| create_or_update_ipset "$DEF" | |
| fi | |
| # Add element to ipset | |
| IP="$(echo "$LINE" | cut -d' ' -f 7)" | |
| EXPIRES="$(echo "$LINE" | sed -re 's/.*expires ([0-9]+)s.*/\1/; t; s/.*/0/')" | |
| ADDOPTS="" | |
| if [ $EXPIRES -gt 0 ]; then | |
| ADDOPTS="timeout $EXPIRES" | |
| fi | |
| if ipset -q test "$NAME" "$IP"; then | |
| # Refresh the entry by deleting it first if already existing | |
| ipset -q del "$NAME" "$IP" | |
| ipset -q add "$NAME" "$IP" $ADDOPTS | |
| else | |
| ipset -q add "$NAME" "$IP" $ADDOPTS | |
| logger -t "$SCRIPT" "Added $IP to ipset $NAME $ADDOPTS" | |
| fi | |
| fi | |
| elif echo "$LINE" | grep -q "add set inet"; then | |
| NAME="$(echo "$LINE" | cut -d' ' -f 5)" | |
| if [ -z "$NAME" ] || ! grep -q "option ipset '$NAME'" /etc/config/mwan3; then | |
| logger -t "$SCRIPT" "Ignored set '$NAME' as it is invalid or not used by mwan3" | |
| else | |
| # Create or update ipset | |
| DEF="$(nft -nT list sets | tr '\n' ' ' | awk '{$1=$1;print}' | sed -r 's/ (set|table)/\n\1/g' | grep "^set $NAME")" | |
| create_or_update_ipset "$DEF" | |
| fi | |
| elif echo "$LINE" | grep -q "delete set inet"; then | |
| NAME="$(echo "$LINE" | cut -d' ' -f 5)" | |
| if [ -z "$NAME" ] || ! grep -q "option ipset '$NAME'" /etc/config/mwan3; then | |
| logger -t "$SCRIPT" "Ignored set '$NAME' as it is invalid or not used by mwan3" | |
| else | |
| # Clear and try to delete removed ipset (This will fail if it is in use by any iptables rule) | |
| ipset clear "$NAME" | |
| ipset destroy "$NAME" 2>&1 | logger -t "$SCRIPT" | |
| fi | |
| fi | |
| done < "$MONITORFIFO" | |
| EOT | |
| } | |
| start_service() { | |
| write_script "$SCRIPTPATH" | |
| chmod +x "$SCRIPTPATH" | |
| procd_open_instance | |
| procd_set_param command "$SCRIPTPATH" | |
| procd_set_param respawn | |
| procd_set_param pidfile /var/run/nft2ipset.pid | |
| procd_close_instance | |
| } | |
| service_stopped() { | |
| rm "$SCRIPTPATH" | |
| } | |
| # vim: ts=2 sw=2 et |
BTW there are a couple of places where the code uses sed -r 's/(set|table)/\n\1/g' to parse nft's output but I think it doesn't handle the case where a nftable's name ends with 'set' or 'table'. I've tried replacing them with sed -r 's/ (set|table)/\n\1/g' which seems to work.
I think also that the monitoring part sometimes receives a line with two or more set, maybe when a DNS resolution return both ipv4 and ipv6 and instead of updating correctly both set it goes all in creating a new ipset with both names inside, even with a \n between them.
Example: I have hulu and hulu6 ipset for ipv4 and ipv6 after sometimes I finish with a set called:
hulu
hulu6
With the \n between the two names.
Consider also adding the following signals to be trapped: QUIT, ABRT
Hi all.. I had some issues with the script especially if you have other nft sets, like for example nft sets used by BanIP package.
The /tmp/nft2ipset generated script was eating a lot of unnecessary resources even triggering oom by nft. It also tries to add all the IP's from banip sets (during banip restarts or reloads) into mwan3 which should not be the case.
Sun Feb 23 20:08:09 2025 kern.warn kernel: [109990.841739] nft invoked oom-killer: gfp_mask=0xc2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_COMP|__GFP_NOMEMALLOC), order=1, oom_score_adj=0
Now, i've been tinkering with the generated script for almost a week now and I just want to share below a more optimized version of nft2ipset. Key point on the optimization, it only uses ipsets defined any mwan3 rules.
Edit/Update 2025-02-24: Re-adjusted the script as after a few reboots it started failing.. more of cleanup of the script with minor changes
Script Update 2025-02-26: It seems that the part "nft -nT monitor" is not killed when calling "restart" or "stop" for the nft2ipset service, so a quick fix for the service_stopped() funciton.
#!/bin/sh /etc/rc.common
# Start before firewall and mwan3 which are at Prio 19
START=18
APP=nft2ipset
USE_PROCD=1
SCRIPTPATH="/tmp/nft2ipset"
write_script() {
cat > "$1" <<'EOT'
#!/bin/sh
#check if the script is already running
PID=$$
SCRIPT="$(basename $0)"
TMPDIR="/tmp"
MONITORPIDFILE="$TMPDIR/$SCRIPT-$$.nftmonitorpid"
MONITORFIFO="$TMPDIR/$SCRIPT-$$.nftmonitorfifo"
mkfifo "$MONITORFIFO"
# Extract all ipset names from MWAN3
SET_NAMES=$(uci show mwan3 | grep '\.ipset=' | awk -F '=' '{gsub(/[ "\047]/, "", $2); print $2}' | sed ':a; N; $!ba; s/\n/|/g')
cleanup () {
# Cleanup nft monitor subprocess
if [ -f "$MONITORPIDFILE" ]; then
MONITORPID="$(cat "$MONITORPIDFILE")"
if [ "$MONITORPID" -gt 1 ]; then
kill "$MONITORPID"
fi
fi
# Remove pid file and fifo
rm "$MONITORFIFO" "$MONITORPIDFILE"
}
trap cleanup TERM INT EXIT
create_or_update_ipset() {
# Determine ipset parameters
local DEF="$1"
local NAME="$(echo "$DEF" | cut -d' ' -f2)"
local OPTS=""
local FAMILY="inet"
if echo "$DEF" | grep -q "ipv6_addr"; then
FAMILY="inet6"
OPTS="$OPTS family $FAMILY"
fi
local TIMEOUT="$(echo "$DEF" | sed -r 's/.*timeout ([0-9]*)s.*/\1/; t; s/.*/0/')"
if [ -n "$TIMEOUT" -a "$TIMEOUT" -gt 0 ]; then
OPTS="$OPTS timeout $TIMEOUT"
fi
# Create or update ipset from nftables set
if [ "$(ipset list -n "$NAME")" = "$NAME" ]; then
CUR="$(ipset list -t "$NAME")"
if ! ( echo "$CUR" | grep -q "family $FAMILY"); then
( ipset destroy "$NAME" 2>&1 | logger -t "$SCRIPT" ) || logger -t "$SCRIPT" "WARNING: Could not destroy ipset with family != $FAMILY"
elif ! ( echo "$CUR" | grep -q "timeout $TIMEOUT"); then
# Swap current iteration of the ipset with a new iteration due to timeout mismatch
ipset create "_$NAME" hash:ip $OPTS
ipset swap "_$NAME" "$NAME"
ipset destroy "_$NAME"
logger -t "$SCRIPT" "Replaced ipset $NAME with new iteration with timeout $TIMEOUT"
fi
fi
if [ "$(ipset list -n "$NAME")" != "$NAME" ]; then
# Create a new ipset with options matching the nftables set
ipset create "$NAME" hash:ip $OPTS
# Restart mwan3 if this ipset is used by it, it is already running but the set name is not found in active rule output
if [ $? = 0 ] && grep -q "option ipset '$NAME'" /etc/config/mwan3 2>/dev/null && ( service | grep mwan3 | grep running ) && ( ! (mwan3 rules | grep -q "match-set $NAME" ) ); then
mwan3 restart
fi
logger -t "$SCRIPT" "Created new ipset $NAME with timeout $TIMEOUT"
fi
# Add already existing entries to the set
echo "$DEF" | sed -re 's/.*elements = \{ ([^\}]+) \}.*/\1/g; t; s/.*//g' | tr ',' '\n' | sed -re 's/^[ ]+//g;s/expires/timeout/g;s/s$//g' | while read LINE; do
if [ -n "$LINE" ]; then
ipset -q add "$NAME" $LINE && logger -t "$SCRIPT" "Added $LINE to $NAME upon ipset creation/update" || true
fi
done
}
# Check if ipsets exist for only MWAN3-related nftsets
nft -nT list sets | tr '\n' ' ' | awk '{$1=$1;print}' | sed -r 's/(set|table)/\n\1/g' | grep -E "^set ($SET_NAMES) " | while read DEF; do
create_or_update_ipset "$DEF"
done
# Start monitoring nftables but filter only relevant sets
nft -nT monitor | grep -E "($(echo "$SET_NAMES" | sed 's/|/\\|/g'))" > "$MONITORFIFO" 2>&1 &
echo $! > "$MONITORPIDFILE"
while read LINE; do
if echo "$LINE" | grep -q "add element inet fw4"; then
# Extract the set name and check if it's in SET_NAMES
NAME="$(echo "$LINE" | cut -d' ' -f 5)"
if echo "$SET_NAMES" | grep -qw "$NAME"; then
# Check if ipset exists or create otherwise
if [ "$(ipset list -n "$NAME" 2>/dev/null)" != "$NAME" ]; then
DEF="$(nft -nT list sets | tr '\n' ' ' | awk '{$1=$1;print}' | sed -r 's/(set|table)/\n\1/g' | grep "^set $NAME")"
create_or_update_ipset "$DEF"
fi
# Add element to ipset
IP="$(echo "$LINE" | cut -d' ' -f 7)"
EXPIRES="$(echo "$LINE" | sed -re 's/.*expires ([0-9]+)s.*/\1/; t; s/.*/0/')"
ADDOPTS=""
if [ "$EXPIRES" -gt 0 ]; then
ADDOPTS="timeout $EXPIRES"
fi
if ipset -q test "$NAME" "$IP"; then
ipset -q del "$NAME" "$IP"
ipset -q add "$NAME" "$IP" $ADDOPTS
else
ipset -q add "$NAME" "$IP" $ADDOPTS
logger -t "$SCRIPT" "Added $IP to ipset $NAME $ADDOPTS"
fi
fi
elif echo "$LINE" | grep -q "add set inet fw4"; then
# Extract the set name and check if it's in SET_NAMES
NAME="$(echo "$LINE" | cut -d' ' -f 5)"
if echo "$SET_NAMES" | grep -qw "$NAME"; then
DEF="$(nft -nT list sets | tr '\n' ' ' | awk '{$1=$1;print}' | sed -r 's/(set|table)/\n\1/g' | grep "^set $NAME")"
create_or_update_ipset "$DEF"
fi
elif echo "$LINE" | grep -q "delete set inet fw4"; then
# Extract the set name and check if it's in SET_NAMES
NAME="$(echo "$LINE" | cut -d' ' -f 5)"
if echo "$SET_NAMES" | grep -qw "$NAME"; then
ipset clear "$NAME"
ipset destroy "$NAME" 2>&1 | logger -t "$SCRIPT"
fi
fi
done < "$MONITORFIFO"
EOT
}
start_service() {
write_script "$SCRIPTPATH"
chmod +x "$SCRIPTPATH"
procd_open_instance
procd_set_param command "$SCRIPTPATH"
procd_set_param respawn
procd_close_instance
}
service_stopped() {
# Remove the script file
rm -f "$SCRIPTPATH"
# Kill any running nft -nT monitor processes
pkill -f "nft -nT monitor" 2>/dev/null
}
# vim: ts=2 sw=2 et
I created a separate gist for easier installation into openwrt (see first comment on the gist): https://gist.github.com/AcidSlide/cd646a8cc81534ad4d3f48075310fe9b
I'm so sorry not to have had time to update this earlier but I've now finally gotten around to to incorporate the following:
- Fixed the sed syntax as suggested by @xurubin
- Trapped QUIT and ABRT as suggested by @posita -> This should allow the script to always properly cleanup the nft monitor+fifo and also allow service_stopped to remove the temporary script file as it is no longer actively used by any process (or child thereof)
- This script will now only sync nft to ipsets for sets that are in use by mwan3 as requested and implemented by @AcidSlide but I've had to move the uci call inside the processing loop to ensure mwan3 config changes to ipsets are always picked up without having the need to restart nft2ipset to repopulate SET_NAMES
- Removed the hard requirement for nft sets to be in netfilter table fw4 it is not important for the scripts function.
I have not been able to reproduce the multiple lines issues people have mentioned as nft monitor works on a one line per operation basis so until I'm able to reproduce this there is no proper fix.
Thanks for the update.. I'll do some test of the changes this weekend
I have not been able to reproduce the multiple lines issues people have mentioned as nft monitor works on a one line per operation basis so until I'm able to reproduce this there is no proper fix.
Can confirm that it's spawning multiple instances of the nft2ipset:
# ps w | grep -i nft
16573 root 1440 S {nft2ipset} /bin/sh /tmp/nft2ipset
16605 root 10864 S {nft2ipset} /bin/sh /tmp/nft2ipset
16957 root 10864 S {nft2ipset} /bin/sh /tmp/nft2ipset
18754 root 1796 R grep --color=auto -i nft
And somehow my NFT Sets from banip are still being triggered by the /tmp/nft2ipset script
Sat Jul 12 13:17:59 2025 user.notice nft2ipset: Created new ipset etcompromised.v4 with timeout 0
Sat Jul 12 13:18:00 2025 user.notice nft2ipset: Created new ipset firehol1.v4 with timeout 0
Sat Jul 12 13:18:09 2025 user.notice nft2ipset: Created new ipset firehol2.v4 with timeout 0
Sat Jul 12 13:18:13 2025 user.notice nft2ipset: Created new ipset greensnow.v4 with timeout 0
Sat Jul 12 13:18:14 2025 user.notice nft2ipset: Created new ipset ipthreat.v4 with timeout 0
Note: posted also my latest version but not yet merged with your latest changes
I have not been able to reproduce the multiple lines issues people have mentioned as nft monitor works on a one line per operation basis so until I'm able to reproduce this there is no proper fix.
Can confirm that it's spawning multiple instances of the
nft2ipset:# ps w | grep -i nft 16573 root 1440 S {nft2ipset} /bin/sh /tmp/nft2ipset 16605 root 10864 S {nft2ipset} /bin/sh /tmp/nft2ipset 16957 root 10864 S {nft2ipset} /bin/sh /tmp/nft2ipset 18754 root 1796 R grep --color=auto -i nft
That's not necessarily being the case it is likely that those are just the subshells here (one for nft monitor background process and the while read loop) and hence a display issue. Question is if there are multiple nft monitors up or if it is just one? if there are multiple then i'd have to look into procd's options some more if there is anything wrong there. A workaround would be to add a lock to the wrapper that allows the script to be only started once.
I'm currently running Openwrt 24.10.2 in a x64 VM on Proxmox. What version/architecture are you running this on?
And somehow my NFT Sets from
banipare still being triggered by the/tmp/nft2ipsetscriptSat Jul 12 13:17:59 2025 user.notice nft2ipset: Created new ipset etcompromised.v4 with timeout 0 Sat Jul 12 13:18:00 2025 user.notice nft2ipset: Created new ipset firehol1.v4 with timeout 0 Sat Jul 12 13:18:09 2025 user.notice nft2ipset: Created new ipset firehol2.v4 with timeout 0 Sat Jul 12 13:18:13 2025 user.notice nft2ipset: Created new ipset greensnow.v4 with timeout 0 Sat Jul 12 13:18:14 2025 user.notice nft2ipset: Created new ipset ipthreat.v4 with timeout 0Note: posted also my latest version but not yet merged with your latest changes
That is weird as the script checks for non-mwan3 sets in line 87-92 now and skips processing that line from nft monitor:
NAME="$(echo "$LINE" | cut -d' ' -f 5)"
if [ -z "$NAME" -o "$(uci show mwan3 | grep '\.ipset=' | awk -F '=' '{gsub(/[ "\047]/, "", $2); print $2}' | tr '\n' '|' | grep -w "$NAME" | wc -l)" -eq 0 ]; then
# Empty or non-mwan3 ipset found
continue
fi
I'll add some debug logging on the next iteration so we might be able to find out what is going wrong here and also do some further testing myself to see if the check is working correctly. Never mind I've found the main problem for the filtering. The set will get created upon script start if it exists previously as the filtering happens at the wrong point.
Updated once more with the following:
- Simplified set name check to do a very simple grep on the mwan3 config file as it a lot less overhead than transforming the uci output and should do the same thing (if there are any problems with this assumptions please comment).
- Added the missing set name check for the initial set creation that is outside of the monitor loop (this should finally cover all cases).
- Undo previous refactoring that would add a lot of useless debug output
As for the multiple processes thing: I still cannot reproduce this on x64 (OpenWRT 24.10.2 with /bin/sh from BusyBox) so it might be something architecture dependent that i'm missing out on. From my knowledge nft2ipset showing multiple times could just be display issue due to subshells for the monitor background process and the while read loop. The real question is if there are multiple /tmp/nft2ipset-[0-9]+.monitorpid files and corresponding processes in the process list as that would indicate the script running simultaneously.
As for the multiple processes thing: I still cannot reproduce this on x64
I'll do some re-test later and see if I can pinpoint where the multiple process is coming from and if there are multiple PID files also.
On my current version of the nft2ipset, the multi-process doesn't happen.
The real question is if there are multiple
/tmp/nft2ipset-[0-9]+.monitorpidfiles and corresponding processes in the process list as that would indicate the script running simultaneously
Latest version seems to work properly now
- no multiple process seen via
ps w | grep -i nft - none mwan3 ipset use, ignored properly now
You mentioned the monitorpid.. I saw multiple files before re-testing and not sure if it had to do with previous mentioned issue (if it was the cause or an output of it) of multiple process spawned but deleted all of them before testing
The real question is if there are multiple
/tmp/nft2ipset-[0-9]+.monitorpidfiles and corresponding processes in the process list as that would indicate the script running simultaneouslyLatest version seems to work properly now
- no multiple process seen via
ps w | grep -i nft- none mwan3 ipset use, ignored properly now
You mentioned the monitorpid.. I saw multiple files before re-testing and not sure if it had to do with previous mentioned issue (if it was the cause or an output of it) of multiple process spawned but deleted all of them before testing
Glad to hear that it works now as intended on your end as well.
The multiple monitor files could have been remnants of crashes of the script as the cleanup trap would not have been executed in that case. Not a problem as long as the pid that is saved inside the file is no longer existing with the orphaned nft monitor process.
@Kishi85 I updated my router today and somehow on my edge case, after a boot/reboot i've got multiple nft2ipset running
root@mt6000 /root [#]# ps w | grep -i nft
1850 root 1452 S {nft2ipset} /bin/sh /tmp/nft2ipset
1959 root 6552 S nft -nT monitor
20239 root 1980 S grep --color=auto -iE post|oom|ntpd|TestNotify|nft2ipset
20328 root 1452 S {nft2ipset} /bin/sh /tmp/nft2ipset
20329 root 46868 R nft -nT list sets
20413 root 1812 S grep --color=auto -i nft
root@mt6000 /root [#]# ls -laht /tmp/nft2ipset*
prw-r--r-- 1 root root 0 Jul 19 09:21 /tmp/nft2ipset-20512.nftmonitorfifo
-rwxr-xr-x 1 root root 5.2K Jul 19 09:21 /tmp/nft2ipset
prw-r--r-- 1 root root 0 Jul 19 09:19 /tmp/nft2ipset-1850.nftmonitorfifo
-rw-r--r-- 1 root root 5 Jul 19 09:18 /tmp/nft2ipset-1850.nftmonitorpid
i'm still investigating how it's happening.. but so far it's only happening after a reboot/boot
Testing Update: ok found the issue.. doing a /etc/init.d/nft2ipset restart was the culprit. Doing a stop then start doesn't do this. It's only the restart is the issue.
Test Update #2: This is weird.. it's somehow a hit/miss thing. Mostly it happens after a reboot/boot. Or a timing issue?? When using restart.
@Kishi85 I updated my router today and somehow on my edge case, after a boot/reboot i've got multiple
nft2ipsetrunningroot@mt6000 /root [#]# ps w | grep -i nft 1850 root 1452 S {nft2ipset} /bin/sh /tmp/nft2ipset 1959 root 6552 S nft -nT monitor 20239 root 1980 S grep --color=auto -iE post|oom|ntpd|TestNotify|nft2ipset 20328 root 1452 S {nft2ipset} /bin/sh /tmp/nft2ipset 20329 root 46868 R nft -nT list sets 20413 root 1812 S grep --color=auto -i nft root@mt6000 /root [#]# ls -laht /tmp/nft2ipset* prw-r--r-- 1 root root 0 Jul 19 09:21 /tmp/nft2ipset-20512.nftmonitorfifo -rwxr-xr-x 1 root root 5.2K Jul 19 09:21 /tmp/nft2ipset prw-r--r-- 1 root root 0 Jul 19 09:19 /tmp/nft2ipset-1850.nftmonitorfifo -rw-r--r-- 1 root root 5 Jul 19 09:18 /tmp/nft2ipset-1850.nftmonitorpidi'm still investigating how it's happening.. but so far it's only happening after a reboot/boot
Testing Update: ok found the issue.. doing a
/etc/init.d/nft2ipset restartwas the culprit. Doing astopthenstartdoesn't do this. It's only therestartis the issue.Test Update #2: This is weird.. it's somehow a hit/miss thing. Mostly it happens after a reboot/boot. Or a timing issue?? When using
restart.
That is odd indeed and seems like something wrong with the procd parameters as the service and script should only be able to be started once. The script itself should be fine here but somehow the service starts twice? Would explain the restart behaviour as well. This could also be an odd racecondition in procd for the restart case?
Anyway, I've added an explicit pid file parameter to the procd configuration of the script so the real pid of the script gets stored somewhere for procd to reference. Maybe procd is just loosing track of the script pid it started without that for some odd reason? Then this should help, otherwise at least no further harm is done.
Works OpenWrt 24.10.2
Replace dnsmaq to dnsmasq-full to suppor nftset
- /luci/admin/network/firewall/ipsets
- /luci/admin/network/dhcp
Necessary Family IPv4+6 (does not work only with IPv4)
- /luci/admin/network/mwan3/rule
handwritten ipset
- /etc/init.d/nft2ipset start
Test
nft list set inet fw4 filtrado

Works perfectly with the mwan3 rule
Hello.
Excuse me. Why did you use hash:ip? I created nft ipsets with an ipset-extras incuding different Geo-IP, different ASN and I guess the nft2ipset doesn't work well with it. All the IPs aren't included to the ipset, I guess. I changed hash:ip to hash:net in script, and it looks probably good, but maybe I don't know something?

When I am using mwan3 with tailscale and above solution, then also it's exit node functionality not working.
It took nearly 2 days got to know that mwan3 iptables can be the problem.
Finally need to remove mwan3.
Also created a script to replicate failover functionality using another script which you can use trigger using crontab. Sharing below if it help someone