Last active
October 20, 2025 16:37
-
-
Save AcidSlide/cd646a8cc81534ad4d3f48075310fe9b to your computer and use it in GitHub Desktop.
/etc/init.d/nft2ipset: An OPTIMIZED version for nftables set to ipset synchronizer for use with OpenWRT/mwan3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Posted latest version as of 2025-07-12