-
-
Save AcidSlide/cd646a8cc81534ad4d3f48075310fe9b to your computer and use it in GitHub Desktop.
| #!/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 > "$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 |
Sorry, I'm not sure I understood the instructions: is it necessary to replace dnsmasq with dnsmasq-full?
Only
dnsmasq-fullcan have IPSETs but honestly right now I don't know where to get adnsmasq-fullthat is pre-compiled with IPSET enabled. I do my own openwrt builds and on the options when buildingdnsmasq-fullI enable "IPSET Support" which is disabled by default by OpenWRT.See this forum post: https://forum.openwrt.org/t/dnsmasq-full-ipset-support-removed-in-23-05-and-master/150274/21?page=2
I am running mwan3 with the" workaround script in Openwrt 24.10 x86 (with default dnsmasq) and it seems to work.
Do you mean that it shouldn't ?
From what I read here
openwrt/packages#22474 (comment)
"...Removing the need to recompile dnsmasq-full with ipset and enabling mwan3 to work with dnsmasq's set functionality again..."
I am running mwan3 with the" workaround script in Openwrt 24.10 x86 (with default dnsmasq) and it seems to work. Do you mean that it shouldn't ? From what I read here openwrt/packages#22474 (comment) "...Removing the need to recompile dnsmasq-full with ipset and enabling mwan3 to work with dnsmasq's set functionality again..."
Oh really? Didn't know it works even without IPSETs enabled and even with just dnsmasq . Then if it works it works.
Does my updated script works for you? If it does, I'll update my comment and remove mentioning it as a requirement.
Posted latest version as of 2025-07-12
If anybody wants a pre-compiled
dnsmasq-fullwith IPSETS, i only currently build 3 different architectures (because I only have those types of routers hahaha). And I can provide a download links for those.