Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Next revisionBoth sides next revision
docs:guide-user:network:wan:multiwan:mwan3 [2024/05/16 16:32] – Add nft2ipset init script credit to @Kishi jamesmacwhitedocs:guide-user:network:wan:multiwan:mwan3 [2024/05/17 08:30] – [nft2ipset init script] jamesmacwhite
Line 66: Line 66:
 **Known issues:** **Known issues:**
  
-   * [[https://github.com/openwrt/packages/issues/22474|mwan3: ipset functionality broken on 23.05]]+   * [[https://github.com/openwrt/packages/issues/22474|mwan3: ipset functionality broken on 23.05]]. [[docs:guide-user:network:wan:multiwan:mwan3#nft2ipset_init_script|Workaround init script available]].
  
 === 22.03 === === 22.03 ===
Line 623: Line 623:
  
 <WRAP center important 100%> <WRAP center important 100%>
-ipset functionality is broken in 23.05 due to the ''dnsmasq-full'' package no longer being compiled with ipset support in favour of nftables. As mwan3 does not currently support nftables natively, this functionality no longer works. [[https://forum.openwrt.org/t/23-05-dnsmasq-ipsets-and-mwan3-incompatibility/174926|More information and further discussion]].+ipset functionality is broken in 23.05 due to the ''dnsmasq-full'' package no longer being compiled with ipset support in favour of nftables. As mwan3 does not currently support nftables natively, this functionality no longer works. [[https://forum.openwrt.org/t/23-05-dnsmasq-ipsets-and-mwan3-incompatibility/174926|More information and further discussion]]. A [[docs:guide-user:network:wan:multiwan:mwan3#nft2ipset init script|workaround init script that converts nfset to ipset is available]] to use until mwan3 is updated to natively support nfset.
 </WRAP> </WRAP>
  
Line 1356: Line 1356:
 ==== nft2ipset init script ==== ==== nft2ipset init script ====
  
-Due to the default firewall now being nftablesrather than iptables, the ipset functionality used in conjunction dnsmasq and mwan3 no longer works in 23.02 versions. This is due to mwan3 not being fully compatible with nftables and requires iptables translation. In 23.02 an important dnsmasq compile flag was changed to basically remove all ipset support in various of nfsets. To restore like for like functionality a custom init script can be used, [[https://forum.openwrt.org/t/23-05-dnsmasq-ipsets-and-mwan3-incompatibility/174926/40|credit @Kishi on the OpenWrt community forum]].+Due to the default firewall (fw4) now being based on nftables (rather than iptables), the ipset functionality commonly used in conjunction with dnsmasq and mwan3 no longer works in 23.05 releases. This is due to mwan3 not being fully compatible with nftables and requiring iptables compatibility/translation packages (see installation steps)While ipset functionality works in 23.02 without any changes, since the 23.05 release an important dnsmasq compile flag was changed to remove all ipset support in favour of nfset. To restore near like for like functionality a custom init script can be used, [[https://forum.openwrt.org/t/23-05-dnsmasq-ipsets-and-mwan3-incompatibility/174926/40|credit @Kishi on the OpenWrt community forum]]. This script monitors changes to nftables/nfset and creates or updates ipset equivalents, essentially replicating the behaviour of what dnsmasq would do with ipset support enabled.
  
-<code sh> +You will need to use nfset with dnsmasq for ipset polices to be created, which mwan3 only supports at this time. mwan3 currently does not support nfset in rules directly, hence the need to create ipset policies.
-#!/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() { +For help with this init script, please message @Kishi on the forum thread and also thank them if you found this useful!
-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 () { +The script is [[https://gist.github.com/Kishi85/b7f379f9aa19f4878af28b8e1a8887ab|published as gist on GitHub]] so the full code can be inspected and reviewed before installing.
-  # 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" "WARNINGCould 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 +
-  create_or_update_ipset "$DEF" +
-done +
- +
-# Monitor nftables rule changes +
-nft -nT monitor > "$MONITORFIFO" 2>&1 & +
-echo $! > "$MONITORPIDFILE" +
-while read LINE; do +
-  if echo "$LINE" | grep -q "add element inet fw4"; then +
-    # Check if ipset exists or create otherwise +
-    NAME="$(echo "$LINE" | cut -d' ' -f 5)" +
-    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 +
-  elif echo "$LINE" | grep -q "add set inet fw4"; then +
-    # Create or update ipset  +
-    NAME="$(echo "$LINE" | cut -d' ' -f 5)" +
-    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" +
-  elif echo "$LINE" | grep -q "delete set inet fw4"; then +
-    # Clear and try to delete removed ipset (This will fail if it is in use by any iptables rule) +
-    NAME="$(echo "$LINE" | cut -d' ' -f 5)" +
-    ipset clear "$NAME" +
-    ipset destroy "$NAME" 2>&1 | logger -t "$SCRIPT" +
-  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() { +
-  rm "$SCRIPTPATH" +
-+
-# vim: ts=2 sw=2 et +
-</code>+
  
 Installation instructions: Installation instructions:
  
 <code> <code>
 +wget -O /etc/init.d/nft2ipset https://gist.github.com/Kishi85/b7f379f9aa19f4878af28b8e1a8887ab/raw/
 chmod +x /etc/init.d/nft2ipset chmod +x /etc/init.d/nft2ipset
 service nft2ipset enable service nft2ipset enable
  • Last modified: 2024/11/15 19:05
  • by jeperez