banip: update 1.8.5-2
authorDirk Brenken <redacted>
Sat, 11 Apr 2026 16:43:09 +0000 (18:43 +0200)
committerDirk Brenken <redacted>
Sat, 11 Apr 2026 16:43:50 +0000 (18:43 +0200)
* fixed two issues in the mail template, reported in the forum
* tweak the f_report function
* changed the f_actual function to reduce subshell calls
* further optimize the monitor function:
  * fixed a possible RDAP rate-limit race condition,
    serialize the rdap_tsfile via flock
  * block_cache bounded growth, when the cache reaches 500
    entries it resets to empty, preventing unbounded string growth
    in the monitor loop
* set the printf format string in single quotes (overall)

Signed-off-by: Dirk Brenken <redacted>
net/banip/Makefile
net/banip/files/banip-functions.sh
net/banip/files/banip-service.sh
net/banip/files/banip.tpl

index d4e2b22aabf6b40da54c80efd176f5b69a347f71..a935801d6105ec97ecdbfcb57efcdaf0b5b67491 100644 (file)
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=banip
 PKG_VERSION:=1.8.5
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 PKG_LICENSE:=GPL-3.0-or-later
 PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
 
index a661264d853bd9e74d97bbe8faba687e19e1c166..67b3a404306e995e599326400babb88c158b1022 100644 (file)
@@ -119,8 +119,8 @@ f_system() {
        # get banIP version and system information
        #
        ban_packages="$("${ban_ubuscmd}" -S call rpc-sys packagelist '{ "all": true }' 2>>"${ban_errorlog}")"
-       ban_bver="$(printf "%s" "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages.banip')"
-       ban_fver="$(printf "%s" "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages["luci-app-banip"]')"
+       ban_bver="$(printf '%s' "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages.banip')"
+       ban_fver="$(printf '%s' "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages["luci-app-banip"]')"
        ban_sysver="$("${ban_ubuscmd}" -S call system board 2>>"${ban_errorlog}" | "${ban_jsoncmd}" -ql1 -e '@.model' -e '@.release.target' -e '@.release.distribution' -e '@.release.version' -e '@.release.revision' |
                "${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s, %s %s (%s)",$1,$2,$3,$4,$5}')"
 
@@ -146,12 +146,12 @@ f_cmd() {
                        cmd="$(command -v "${sec_cmd}" 2>>"${ban_errorlog}")"
                fi
                if [ -x "${cmd}" ]; then
-                       printf "%s" "${cmd}"
+                       printf '%s' "${cmd}"
                else
                        f_log "emerg" "command '${pri_cmd:-"-"}'/'${sec_cmd:-"-"}' not found"
                fi
        else
-               printf "%s" "${cmd}"
+               printf '%s' "${cmd}"
        fi
 }
 
@@ -206,11 +206,11 @@ f_char() {
        local char="${1}"
 
        if [ "${char}" = "1" ]; then
-               printf "%s" "✔"
+               printf '%s' "✔"
        elif [ "${char}" = "0" ] || [ -z "${char}" ]; then
-               printf "%s" "✘"
+               printf '%s' "✘"
        else
-               printf "%s" "${char}"
+               printf '%s' "${char}"
        fi
 }
 
@@ -221,7 +221,7 @@ f_trim() {
 
        string="${string#"${string%%[![:space:]]*}"}"
        string="${string%"${string##*[![:space:]]}"}"
-       printf "%s" "${string}"
+       printf '%s' "${string}"
 }
 
 # remove log monitor
@@ -265,7 +265,7 @@ f_log() {
                if [ -x "${ban_logcmd}" ]; then
                        "${ban_logcmd}" -p "${class}" -t "banIP-${ban_bver}[${$}]" "${log_msg::256}"
                else
-                       printf "%s %s %s\n" "${class}" "banIP-${ban_bver}[${$}]" "${log_msg::256}"
+                       printf '%s %s %s\n' "${class}" "banIP-${ban_bver}[${$}]" "${log_msg::256}"
                fi
        fi
        if [ "${class}" = "err" ] || [ "${class}" = "emerg" ]; then
@@ -490,25 +490,23 @@ f_actual() {
        local nft monitor ppid pids pid
 
        if "${ban_nftcmd}" -t list table inet banIP >/dev/null 2>&1; then
-               nft="$(f_char "1")"
+               nft=""
        else
-               nft="$(f_char "0")"
+               nft=""
        fi
 
+       monitor="✘"
        ppid="$("${ban_catcmd}" "${ban_pidfile}" 2>>"${ban_errorlog}")"
        if [ -n "${ppid}" ]; then
-               monitor="$(f_char "0")"
                pids="${ppid} $("${ban_pgrepcmd}" -P "${ppid}" 2>>"${ban_errorlog}")"
                for pid in ${pids}; do
                        if "${ban_pgrepcmd}" -f "${ban_logreadcmd##*/}" -P "${pid}" >/dev/null 2>&1; then
-                               monitor="$(f_char "1")"
+                               monitor=""
                                break
                        fi
                done
-       else
-               monitor="$(f_char "0")"
        fi
-       printf "%s" "nft: ${nft}, monitor: ${monitor}"
+       printf '%s' "nft: ${nft}, monitor: ${monitor}"
 }
 
 # get fetch utility
@@ -703,7 +701,7 @@ f_getup() {
                timestamp="$(date "+%Y-%m-%d %H:%M:%S")"
                for ip in ${ban_uplink}; do
                        if ! "${ban_grepcmd}" -q "${ip} " "${ban_allowlist}"; then
-                               printf "%-45s%s\n" "${ip}" "# uplink added on ${timestamp}" >>"${ban_allowlist}"
+                               printf '%-45s%s\n' "${ip}" "# uplink added on ${timestamp}" >>"${ban_allowlist}"
                                f_log "info" "add uplink '${ip}' to local allowlist"
                        fi
                done
@@ -737,7 +735,7 @@ f_getfeed() {
 f_getelements() {
        local file="${1}"
 
-       [ -s "${file}" ] && printf "%s" "elements={ $("${ban_catcmd}" "${file}" 2>>"${ban_errorlog}") };"
+       [ -s "${file}" ] && printf '%s' "elements={ $("${ban_catcmd}" "${file}" 2>>"${ban_errorlog}") };"
 }
 
 # handle etag http header
@@ -748,10 +746,10 @@ f_etag() {
        if [ -n "${ban_etagparm}" ]; then
                [ ! -f "${ban_backupdir}/banIP.etag" ] && : >"${ban_backupdir}/banIP.etag"
                http_head="$("${ban_fetchcmd}" ${ban_etagparm} "${feed_url}" 2>&1)"
-               http_code="$(printf "%s" "${http_head}" | "${ban_awkcmd}" 'tolower($0)~/^http\/[0123\.]+ /{printf "%s",$2}')"
-               etag_id="$(printf "%s" "${http_head}" | "${ban_awkcmd}" 'tolower($0)~/^[[:space:]]*etag: /{gsub("\"","");printf "%s",$2}')"
+               http_code="$(printf '%s' "${http_head}" | "${ban_awkcmd}" 'tolower($0)~/^http\/[0123\.]+ /{printf "%s",$2}')"
+               etag_id="$(printf '%s' "${http_head}" | "${ban_awkcmd}" 'tolower($0)~/^[[:space:]]*etag: /{gsub("\"","");printf "%s",$2}')"
                if [ -z "${etag_id}" ]; then
-                       etag_id="$(printf "%s" "${http_head}" | "${ban_awkcmd}" 'tolower($0)~/^[[:space:]]*last-modified: /{gsub(/[Ll]ast-[Mm]odified:|[[:space:]]|,|:/,"");printf "%s\n",$1}')"
+                       etag_id="$(printf '%s' "${http_head}" | "${ban_awkcmd}" 'tolower($0)~/^[[:space:]]*last-modified: /{gsub(/[Ll]ast-[Mm]odified:|[[:space:]]|,|:/,"");printf "%s\n",$1}')"
                fi
                etag_cnt="$("${ban_grepcmd}" -c "^${feed} " "${ban_backupdir}/banIP.etag")"
                if [ "${http_code}" = "200" ] && [ "${etag_cnt}" = "${feed_cnt}" ] && [ -n "${etag_id}" ] &&
@@ -763,7 +761,7 @@ f_etag() {
                        else
                                "${ban_sedcmd}" -i "/^${feed} ${feed_suffix//\//\\/}/d" "${ban_backupdir}/banIP.etag"
                        fi
-                       printf "%-50s%s\n" "${feed} ${feed_suffix}" "${etag_id}" >>"${ban_backupdir}/banIP.etag"
+                       printf '%-50s%s\n' "${feed} ${feed_suffix}" "${etag_id}" >>"${ban_backupdir}/banIP.etag"
                        out_rc="2"
                fi
        fi
@@ -800,9 +798,9 @@ f_nftload() {
 f_nftinit() {
        local wan_dev vlan_allow vlan_block log_ct log_icmp log_syn log_udp log_tcp flag tmp_proto tmp_port allow_dport feed_rc="0" file="${1}"
 
-       wan_dev="$(printf "%s" "${ban_dev}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
-       [ -n "${ban_vlanallow}" ] && vlan_allow="$(printf "%s" "${ban_vlanallow%%?}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
-       [ -n "${ban_vlanblock}" ] && vlan_block="$(printf "%s" "${ban_vlanblock%%?}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
+       wan_dev="$(printf '%s' "${ban_dev}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
+       [ -n "${ban_vlanallow}" ] && vlan_allow="$(printf '%s' "${ban_vlanallow%%?}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
+       [ -n "${ban_vlanblock}" ] && vlan_block="$(printf '%s' "${ban_vlanblock%%?}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
 
        for flag in ${ban_allowflag}; do
                case "${flag}" in
@@ -849,131 +847,131 @@ f_nftinit() {
        {
                # nft header (tables, base and regular chains)
                #
-               printf "%s\n\n" "#!${ban_nftcmd} -f"
+               printf '%s\n\n' "#!${ban_nftcmd} -f"
                if "${ban_nftcmd}" -t list table inet banIP >/dev/null 2>&1; then
-                       printf "%s\n" "delete table inet banIP"
+                       printf '%s\n' "delete table inet banIP"
                fi
-               printf "%s\n" "add table inet banIP"
+               printf '%s\n' "add table inet banIP"
 
                # base chains
                #
-               printf "%s\n" "add chain inet banIP pre-routing { type filter hook prerouting priority -175; policy accept; }"
-               printf "%s\n" "add chain inet banIP wan-input { type filter hook input priority ${ban_nftpriority}; policy accept; }"
-               printf "%s\n" "add chain inet banIP wan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }"
-               printf "%s\n" "add chain inet banIP lan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }"
+               printf '%s\n' "add chain inet banIP pre-routing { type filter hook prerouting priority -175; policy accept; }"
+               printf '%s\n' "add chain inet banIP wan-input { type filter hook input priority ${ban_nftpriority}; policy accept; }"
+               printf '%s\n' "add chain inet banIP wan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }"
+               printf '%s\n' "add chain inet banIP lan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }"
 
                # regular chains
                #
-               printf "%s\n" "add chain inet banIP _inbound"
-               printf "%s\n" "add chain inet banIP _outbound"
-               printf "%s\n" "add chain inet banIP _reject"
+               printf '%s\n' "add chain inet banIP _inbound"
+               printf '%s\n' "add chain inet banIP _outbound"
+               printf '%s\n' "add chain inet banIP _reject"
 
                # named counter
                #
-               printf "%s\n" "add counter inet banIP cnt_icmpflood"
-               printf "%s\n" "add counter inet banIP cnt_udpflood"
-               printf "%s\n" "add counter inet banIP cnt_synflood"
-               printf "%s\n" "add counter inet banIP cnt_tcpinvalid"
-               printf "%s\n" "add counter inet banIP cnt_ctinvalid"
-               printf "%s\n" "add counter inet banIP cnt_bcp38"
+               printf '%s\n' "add counter inet banIP cnt_icmpflood"
+               printf '%s\n' "add counter inet banIP cnt_udpflood"
+               printf '%s\n' "add counter inet banIP cnt_synflood"
+               printf '%s\n' "add counter inet banIP cnt_tcpinvalid"
+               printf '%s\n' "add counter inet banIP cnt_ctinvalid"
+               printf '%s\n' "add counter inet banIP cnt_bcp38"
 
                # default reject chain rules
                #
-               printf "%s\n" "add rule inet banIP _reject iifname != { ${wan_dev} } meta l4proto tcp reject with tcp reset"
-               printf "%s\n" "add rule inet banIP _reject reject with icmpx host-unreachable"
+               printf '%s\n' "add rule inet banIP _reject iifname != { ${wan_dev} } meta l4proto tcp reject with tcp reset"
+               printf '%s\n' "add rule inet banIP _reject reject with icmpx host-unreachable"
 
                # default pre-routing rules
                #
-               printf "%s\n" "add rule inet banIP pre-routing iifname != { ${wan_dev} } counter accept"
+               printf '%s\n' "add rule inet banIP pre-routing iifname != { ${wan_dev} } counter accept"
 
                # ct state invalid
                #
                if [ "${ban_logprerouting}" = "1" ]; then
-                       printf "%s\n" "add rule inet banIP pre-routing ct state invalid ${log_ct}"
+                       printf '%s\n' "add rule inet banIP pre-routing ct state invalid ${log_ct}"
                fi
-               printf "%s\n" "add rule inet banIP pre-routing ct state invalid counter name cnt_ctinvalid drop"
+               printf '%s\n' "add rule inet banIP pre-routing ct state invalid counter name cnt_ctinvalid drop"
 
                # ICMP Flood
                #
                if [ "${ban_icmplimit}" -gt "0" ]; then
                        if [ "${ban_logprerouting}" = "1" ]; then
-                               printf "%s\n" "add rule inet banIP pre-routing meta nfproto . meta l4proto { ipv4 . icmp , ipv6 . icmpv6 } limit rate over ${ban_icmplimit}/second ${log_icmp}"
+                               printf '%s\n' "add rule inet banIP pre-routing meta nfproto . meta l4proto { ipv4 . icmp , ipv6 . icmpv6 } limit rate over ${ban_icmplimit}/second ${log_icmp}"
                        fi
-                       printf "%s\n" "add rule inet banIP pre-routing meta nfproto . meta l4proto { ipv4 . icmp , ipv6 . icmpv6 } limit rate over ${ban_icmplimit}/second counter name cnt_icmpflood drop"
+                       printf '%s\n' "add rule inet banIP pre-routing meta nfproto . meta l4proto { ipv4 . icmp , ipv6 . icmpv6 } limit rate over ${ban_icmplimit}/second counter name cnt_icmpflood drop"
                fi
 
                # UDP Flood
                #
                if [ "${ban_udplimit}" -gt "0" ]; then
                        if [ "${ban_logprerouting}" = "1" ]; then
-                               printf "%s\n" "add rule inet banIP pre-routing meta l4proto udp ct state new limit rate over ${ban_udplimit}/second ${log_udp}"
+                               printf '%s\n' "add rule inet banIP pre-routing meta l4proto udp ct state new limit rate over ${ban_udplimit}/second ${log_udp}"
                        fi
-                       printf "%s\n" "add rule inet banIP pre-routing meta l4proto udp ct state new limit rate over ${ban_udplimit}/second counter name cnt_udpflood drop"
+                       printf '%s\n' "add rule inet banIP pre-routing meta l4proto udp ct state new limit rate over ${ban_udplimit}/second counter name cnt_udpflood drop"
                fi
 
                # SYN Flood
                #
                if [ "${ban_synlimit}" -gt "0" ]; then
                        if [ "${ban_logprerouting}" = "1" ]; then
-                               printf "%s\n" "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|ack) == syn limit rate over ${ban_synlimit}/second ${log_syn}"
+                               printf '%s\n' "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|ack) == syn limit rate over ${ban_synlimit}/second ${log_syn}"
                        fi
-                       printf "%s\n" "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|ack) == syn limit rate over ${ban_synlimit}/second counter name cnt_synflood drop"
+                       printf '%s\n' "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|ack) == syn limit rate over ${ban_synlimit}/second counter name cnt_synflood drop"
                fi
 
                # TCP Invalid
                #
                if [ "${ban_logprerouting}" = "1" ]; then
-                       printf "%s\n" "add rule inet banIP pre-routing tcp flags & (fin|syn) == (fin|syn) ${log_tcp}"
-                       printf "%s\n" "add rule inet banIP pre-routing tcp flags & (syn|rst) == (syn|rst) ${log_tcp}"
-                       printf "%s\n" "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) ${log_tcp}"
-                       printf "%s\n" "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) ${log_tcp}"
+                       printf '%s\n' "add rule inet banIP pre-routing tcp flags & (fin|syn) == (fin|syn) ${log_tcp}"
+                       printf '%s\n' "add rule inet banIP pre-routing tcp flags & (syn|rst) == (syn|rst) ${log_tcp}"
+                       printf '%s\n' "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) ${log_tcp}"
+                       printf '%s\n' "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) ${log_tcp}"
                fi
-               printf "%s\n" "add rule inet banIP pre-routing tcp flags & (fin|syn) == (fin|syn) counter name cnt_tcpinvalid drop"
-               printf "%s\n" "add rule inet banIP pre-routing tcp flags & (syn|rst) == (syn|rst) counter name cnt_tcpinvalid drop"
-               printf "%s\n" "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) counter name cnt_tcpinvalid drop"
-               printf "%s\n" "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) counter name cnt_tcpinvalid drop"
+               printf '%s\n' "add rule inet banIP pre-routing tcp flags & (fin|syn) == (fin|syn) counter name cnt_tcpinvalid drop"
+               printf '%s\n' "add rule inet banIP pre-routing tcp flags & (syn|rst) == (syn|rst) counter name cnt_tcpinvalid drop"
+               printf '%s\n' "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) counter name cnt_tcpinvalid drop"
+               printf '%s\n' "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) counter name cnt_tcpinvalid drop"
 
                # default wan-input rules
                #
-               printf "%s\n" "add rule inet banIP wan-input ct state established,related counter accept"
-               printf "%s\n" "add rule inet banIP wan-input iifname != { ${wan_dev} } counter accept"
-               printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv4 udp sport 67-68 udp dport 67-68 counter accept"
-               printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 udp sport 547 udp dport 546 counter accept"
-               printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } ip6 hoplimit 255 counter accept"
-               [ -n "${allow_dport}" ] && printf "%s\n" "add rule inet banIP wan-input ${allow_dport} counter accept"
+               printf '%s\n' "add rule inet banIP wan-input ct state established,related counter accept"
+               printf '%s\n' "add rule inet banIP wan-input iifname != { ${wan_dev} } counter accept"
+               printf '%s\n' "add rule inet banIP wan-input meta nfproto ipv4 udp sport 67-68 udp dport 67-68 counter accept"
+               printf '%s\n' "add rule inet banIP wan-input meta nfproto ipv6 udp sport 547 udp dport 546 counter accept"
+               printf '%s\n' "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } ip6 hoplimit 255 counter accept"
+               [ -n "${allow_dport}" ] && printf '%s\n' "add rule inet banIP wan-input ${allow_dport} counter accept"
                if [ "${ban_bcp38}" = "1" ]; then
-                       printf "%s\n" "add rule inet banIP wan-input fib saddr . iif oif missing counter name cnt_bcp38 drop"
+                       printf '%s\n' "add rule inet banIP wan-input fib saddr . iif oif missing counter name cnt_bcp38 drop"
                fi
                if [ "${ban_loginbound}" = "1" ]; then
-                       printf "%s\n" "add rule inet banIP wan-input meta mark set 1 counter jump _inbound"
+                       printf '%s\n' "add rule inet banIP wan-input meta mark set 1 counter jump _inbound"
                else
-                       printf "%s\n" "add rule inet banIP wan-input counter jump _inbound"
+                       printf '%s\n' "add rule inet banIP wan-input counter jump _inbound"
                fi
 
                # default wan-forward rules
                #
-               printf "%s\n" "add rule inet banIP wan-forward ct state established,related counter accept"
-               printf "%s\n" "add rule inet banIP wan-forward iifname != { ${wan_dev} } counter accept"
-               [ -n "${allow_dport}" ] && printf "%s\n" "add rule inet banIP wan-forward ${allow_dport} counter accept"
+               printf '%s\n' "add rule inet banIP wan-forward ct state established,related counter accept"
+               printf '%s\n' "add rule inet banIP wan-forward iifname != { ${wan_dev} } counter accept"
+               [ -n "${allow_dport}" ] && printf '%s\n' "add rule inet banIP wan-forward ${allow_dport} counter accept"
                if [ "${ban_bcp38}" = "1" ]; then
-                       printf "%s\n" "add rule inet banIP wan-forward fib saddr . iif oif missing counter name cnt_bcp38 drop"
+                       printf '%s\n' "add rule inet banIP wan-forward fib saddr . iif oif missing counter name cnt_bcp38 drop"
                fi
                if [ "${ban_loginbound}" = "1" ]; then
-                       printf "%s\n" "add rule inet banIP wan-forward meta mark set 2 counter jump _inbound"
+                       printf '%s\n' "add rule inet banIP wan-forward meta mark set 2 counter jump _inbound"
                else
-                       printf "%s\n" "add rule inet banIP wan-forward counter jump _inbound"
+                       printf '%s\n' "add rule inet banIP wan-forward counter jump _inbound"
                fi
 
                # default lan-forward rules
                #
-               printf "%s\n" "add rule inet banIP lan-forward ct state established,related counter accept"
-               printf "%s\n" "add rule inet banIP lan-forward oifname != { ${wan_dev} } counter accept"
-               [ -n "${vlan_allow}" ] && printf "%s\n" "add rule inet banIP lan-forward iifname { ${vlan_allow} } counter accept"
-               [ -n "${vlan_block}" ] && printf "%s\n" "add rule inet banIP lan-forward iifname { ${vlan_block} } counter goto _reject"
+               printf '%s\n' "add rule inet banIP lan-forward ct state established,related counter accept"
+               printf '%s\n' "add rule inet banIP lan-forward oifname != { ${wan_dev} } counter accept"
+               [ -n "${vlan_allow}" ] && printf '%s\n' "add rule inet banIP lan-forward iifname { ${vlan_allow} } counter accept"
+               [ -n "${vlan_block}" ] && printf '%s\n' "add rule inet banIP lan-forward iifname { ${vlan_block} } counter goto _reject"
                if [ "${ban_bcp38}" = "1" ]; then
-                       printf "%s\n" "add rule inet banIP lan-forward fib saddr . iif oif missing counter name cnt_bcp38 drop"
+                       printf '%s\n' "add rule inet banIP lan-forward fib saddr . iif oif missing counter name cnt_bcp38 drop"
                fi
-               printf "%s\n" "add rule inet banIP lan-forward counter jump _outbound"
+               printf '%s\n' "add rule inet banIP lan-forward counter jump _outbound"
        } >"${file}"
 
        # load initial banIP table/rules to nftset
@@ -1024,7 +1022,7 @@ f_down() {
                element_count="counter"
        fi
 
-# set feed complete flag
+       # set feed complete flag
        #
        case " ${ban_feedcomplete} " in
                *" ${feed%%.*} "*)
@@ -1086,7 +1084,7 @@ f_down() {
                esac
        fi
 
-# prepare feed flags
+       # prepare feed flags
        #
        for flag in ${feed_flag}; do
                case "${flag}" in
@@ -1139,14 +1137,14 @@ f_down() {
                {
                        for chain in _inbound _outbound; do
                                for expr in 0 1 2; do
-                                       handles="$(printf "%s\n" "${table_json}" | "${ban_jsoncmd}" -q -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[${expr}].match.right=\"@${feed}\"].handle" | "${ban_xargscmd}")"
+                                       handles="$(printf '%s\n' "${table_json}" | "${ban_jsoncmd}" -q -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[${expr}].match.right=\"@${feed}\"].handle" | "${ban_xargscmd}")"
                                        for handle in ${handles}; do
-                                               printf "%s\n" "delete rule inet banIP ${chain} handle ${handle}"
+                                               printf '%s\n' "delete rule inet banIP ${chain} handle ${handle}"
                                        done
                                done
                        done
-                       printf "%s\n" "flush set inet banIP ${feed}"
-                       printf "%s\n\n" "delete set inet banIP ${feed}"
+                       printf '%s\n' "flush set inet banIP ${feed}"
+                       printf '%s\n\n' "delete set inet banIP ${feed}"
                } >"${tmp_flush}"
        fi
 
@@ -1164,7 +1162,7 @@ f_down() {
                                                etag_rc="${?}"
                                        else
                                                etag_rc="0"
-                                               etag_cnt="$(printf "%s" "${ban_country}" | "${ban_wccmd}" -w)"
+                                               etag_cnt="$(printf '%s' "${ban_country}" | "${ban_wccmd}" -w)"
                                                for country in ${ban_country}; do
                                                        if ! f_etag "${feed}" "${feed_url}${country}-aggregated.zone" ".${country}" "${etag_cnt}"; then
                                                                etag_rc="$((etag_rc + 1))"
@@ -1180,7 +1178,7 @@ f_down() {
                                                etag_rc="${?}"
                                        else
                                                etag_rc="0"
-                                               etag_cnt="$(printf "%s" "${ban_asn}" | "${ban_wccmd}" -w)"
+                                               etag_cnt="$(printf '%s' "${ban_asn}" | "${ban_wccmd}" -w)"
                                                for asn in ${ban_asn}; do
                                                        if ! f_etag "${feed}" "${feed_url}AS${asn}" ".${asn}" "${etag_cnt}"; then
                                                                etag_rc="$((etag_rc + 1))"
@@ -1236,64 +1234,64 @@ f_down() {
        #
        if [ "${feed%%.*}" = "allowlist" ]; then
                {
-                       printf "%s\n\n" "#!${ban_nftcmd} -f"
+                       printf '%s\n\n' "#!${ban_nftcmd} -f"
                        [ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
                        case "${feed_ipv}" in
                                "4MAC")
                                        "${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}(\/([0-9]|[1-3][0-9]|4[0-8]))?([[:space:]]+([1-9][0-9]?[0-9]?\.){1}([0-9]{1,3}\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?([[:space:]]+#.*$|[[:space:]]*$)|[[:space:]]+#.*$|$)/{if(!$2||$2~/#/)$2="0.0.0.0/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${tmp_allow}" >"${tmp_file}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
-                                       [ -z "${feed_direction##*outbound*}" ] && printf "%s\n" "add rule inet banIP _outbound ether saddr . ip saddr @${feed} counter accept"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ether_addr . ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
+                                       [ -z "${feed_direction##*outbound*}" ] && printf '%s\n' "add rule inet banIP _outbound ether saddr . ip saddr @${feed} counter accept"
                                        ;;
                                "6MAC")
                                        "${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}(\/([0-9]|[1-3][0-9]|4[0-8]))?([[:space:]]+([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?([[:space:]]+#.*$|[[:space:]]*$)|[[:space:]]+#.*$|$)/{if(!$2||$2~/#/)$2="::/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${tmp_allow}" >"${tmp_file}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
-                                       [ -z "${feed_direction##*outbound*}" ] && printf "%s\n" "add rule inet banIP _outbound ether saddr . ip6 saddr @${feed} counter accept"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ether_addr . ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
+                                       [ -z "${feed_direction##*outbound*}" ] && printf '%s\n' "add rule inet banIP _outbound ether saddr . ip6 saddr @${feed} counter accept"
                                        ;;
                                "4")
                                        f_chkip ${feed_ipv} local 1 < "${tmp_allow}" >"${tmp_file}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
                                        if [ -z "${feed_direction##*inbound*}" ]; then
                                                if [ "${ban_allowlistonly}" = "1" ]; then
                                                        if [ "${ban_loginbound}" = "1" ]; then
-                                                               printf "%s\n" "add rule inet banIP _inbound ip saddr != @${feed} ${log_inbound}"
+                                                               printf '%s\n' "add rule inet banIP _inbound ip saddr != @${feed} ${log_inbound}"
                                                        fi
-                                                       printf "%s\n" "add rule inet banIP _inbound ip saddr != @${feed} counter ${feed_target}"
+                                                       printf '%s\n' "add rule inet banIP _inbound ip saddr != @${feed} counter ${feed_target}"
                                                else
-                                                       printf "%s\n" "add rule inet banIP _inbound ip saddr @${feed} counter accept"
+                                                       printf '%s\n' "add rule inet banIP _inbound ip saddr @${feed} counter accept"
                                                fi
                                        fi
                                        if [ -z "${feed_direction##*outbound*}" ]; then
                                                if [ "${ban_allowlistonly}" = "1" ]; then
                                                        if [ "${ban_logoutbound}" = "1" ]; then
-                                                               printf "%s\n" "add rule inet banIP _outbound ip daddr != @${feed} ${log_outbound}"
+                                                               printf '%s\n' "add rule inet banIP _outbound ip daddr != @${feed} ${log_outbound}"
                                                        fi
-                                                       printf "%s\n" "add rule inet banIP _outbound ip daddr != @${feed} counter goto _reject"
+                                                       printf '%s\n' "add rule inet banIP _outbound ip daddr != @${feed} counter goto _reject"
                                                else
-                                                       printf "%s\n" "add rule inet banIP _outbound ip daddr @${feed} counter accept"
+                                                       printf '%s\n' "add rule inet banIP _outbound ip daddr @${feed} counter accept"
                                                fi
                                        fi
                                        ;;
                                "6")
                                        f_chkip ${feed_ipv} local 1 < "${tmp_allow}" >"${tmp_file}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
                                        if [ -z "${feed_direction##*inbound*}" ]; then
                                                if [ "${ban_allowlistonly}" = "1" ]; then
                                                        if [ "${ban_loginbound}" = "1" ]; then
-                                                               printf "%s\n" "add rule inet banIP _inbound ip6 saddr != @${feed} ${log_inbound}"
+                                                               printf '%s\n' "add rule inet banIP _inbound ip6 saddr != @${feed} ${log_inbound}"
                                                        fi
-                                                       printf "%s\n" "add rule inet banIP _inbound ip6 saddr != @${feed} counter ${feed_target}"
+                                                       printf '%s\n' "add rule inet banIP _inbound ip6 saddr != @${feed} counter ${feed_target}"
                                                else
-                                                       printf "%s\n" "add rule inet banIP _inbound ip6 saddr @${feed} counter accept"
+                                                       printf '%s\n' "add rule inet banIP _inbound ip6 saddr @${feed} counter accept"
                                                fi
                                        fi
                                        if [ -z "${feed_direction##*outbound*}" ]; then
                                                if [ "${ban_allowlistonly}" = "1" ]; then
                                                        if [ "${ban_logoutbound}" = "1" ]; then
-                                                               printf "%s\n" "add rule inet banIP _outbound ip6 daddr != @${feed} ${log_outbound}"
+                                                               printf '%s\n' "add rule inet banIP _outbound ip6 daddr != @${feed} ${log_outbound}"
                                                        fi
-                                                       printf "%s\n" "add rule inet banIP _outbound ip6 daddr != @${feed} counter ${feed_target}"
+                                                       printf '%s\n' "add rule inet banIP _outbound ip6 daddr != @${feed} counter ${feed_target}"
                                                else
-                                                       printf "%s\n" "add rule inet banIP _outbound ip6 daddr @${feed} counter accept"
+                                                       printf '%s\n' "add rule inet banIP _outbound ip6 daddr @${feed} counter accept"
                                                fi
                                        fi
                                        ;;
@@ -1303,49 +1301,49 @@ f_down() {
                feed_rc="0"
        elif [ "${feed%%.*}" = "blocklist" ]; then
                {
-                       printf "%s\n\n" "#!${ban_nftcmd} -f"
+                       printf '%s\n\n' "#!${ban_nftcmd} -f"
                        [ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
                        case "${feed_ipv}" in
                                "4MAC")
                                        "${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}(\/([0-9]|[1-3][0-9]|4[0-8]))?([[:space:]]+([1-9][0-9]?[0-9]?\.){1}([0-9]{1,3}\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?([[:space:]]+#.*$|[[:space:]]*$)|[[:space:]]+#.*$|$)/{if(!$2||$2~/#/)$2="0.0.0.0/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${ban_blocklist}" >"${tmp_file}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
-                                       [ -z "${feed_direction##*outbound*}" ] && printf "%s\n" "add rule inet banIP _outbound ether saddr . ip saddr @${feed} counter goto _reject"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ether_addr . ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
+                                       [ -z "${feed_direction##*outbound*}" ] && printf '%s\n' "add rule inet banIP _outbound ether saddr . ip saddr @${feed} counter goto _reject"
                                        ;;
                                "6MAC")
                                        "${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}(\/([0-9]|[1-3][0-9]|4[0-8]))?([[:space:]]+([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?([[:space:]]+#.*$|[[:space:]]*$)|[[:space:]]+#.*$|$)/{if(!$2||$2~/#/)$2="::/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${ban_blocklist}" >"${tmp_file}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
-                                       [ -z "${feed_direction##*outbound*}" ] && printf "%s\n" "add rule inet banIP _outbound ether saddr . ip6 saddr @${feed} counter goto _reject"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ether_addr . ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
+                                       [ -z "${feed_direction##*outbound*}" ] && printf '%s\n' "add rule inet banIP _outbound ether saddr . ip6 saddr @${feed} counter goto _reject"
                                        ;;
                                "4")
                                        f_chkip ${feed_ipv} local 1 < "${ban_blocklist}" >"${tmp_file}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval, timeout; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ipv4_addr; flags interval, timeout; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
                                        if [ -z "${feed_direction##*inbound*}" ]; then
                                                if [ "${ban_loginbound}" = "1" ]; then
-                                                       printf "%s\n" "add rule inet banIP _inbound ip saddr @${feed} ${log_inbound}"
+                                                       printf '%s\n' "add rule inet banIP _inbound ip saddr @${feed} ${log_inbound}"
                                                fi
-                                               printf "%s\n" "add rule inet banIP _inbound ip saddr @${feed} counter ${feed_target}"
+                                               printf '%s\n' "add rule inet banIP _inbound ip saddr @${feed} counter ${feed_target}"
                                        fi
                                        if [ -z "${feed_direction##*outbound*}" ]; then
                                                if [ "${ban_logoutbound}" = "1" ]; then
-                                                       printf "%s\n" "add rule inet banIP _outbound ip daddr @${feed} ${log_outbound}"
+                                                       printf '%s\n' "add rule inet banIP _outbound ip daddr @${feed} ${log_outbound}"
                                                fi
-                                               printf "%s\n" "add rule inet banIP _outbound ip daddr @${feed} counter goto _reject"
+                                               printf '%s\n' "add rule inet banIP _outbound ip daddr @${feed} counter goto _reject"
                                        fi
                                        ;;
                                "6")
                                        f_chkip ${feed_ipv} local 1 < "${ban_blocklist}" >"${tmp_file}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval, timeout; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ipv6_addr; flags interval, timeout; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
                                        if [ -z "${feed_direction##*inbound*}" ]; then
                                                if [ "${ban_loginbound}" = "1" ]; then
-                                                       printf "%s\n" "add rule inet banIP _inbound ip6 saddr @${feed} ${log_inbound}"
+                                                       printf '%s\n' "add rule inet banIP _inbound ip6 saddr @${feed} ${log_inbound}"
                                                fi
-                                               printf "%s\n" "add rule inet banIP _inbound ip6 saddr @${feed} counter ${feed_target}"
+                                               printf '%s\n' "add rule inet banIP _inbound ip6 saddr @${feed} counter ${feed_target}"
                                        fi
                                        if [ -z "${feed_direction##*outbound*}" ]; then
                                                if [ "${ban_logoutbound}" = "1" ]; then
-                                                       printf "%s\n" "add rule inet banIP _outbound ip6 daddr @${feed} ${log_outbound}"
+                                                       printf '%s\n' "add rule inet banIP _outbound ip6 daddr @${feed} ${log_outbound}"
                                                fi
-                                               printf "%s\n" "add rule inet banIP _outbound ip6 daddr @${feed} counter goto _reject"
+                                               printf '%s\n' "add rule inet banIP _outbound ip6 daddr @${feed} counter goto _reject"
                                        fi
                                        ;;
                        esac
@@ -1480,40 +1478,40 @@ f_down() {
                                {
                                        # nft header (IPv4 Set) incl. inbound and outbound rules
                                        #
-                                       printf "%s\n\n" "#!${ban_nftcmd} -f"
+                                       printf '%s\n\n' "#!${ban_nftcmd} -f"
                                        [ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}.1") }"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}.1") }"
                                        if [ -z "${feed_direction##*inbound*}" ]; then
                                                if [ "${ban_loginbound}" = "1" ]; then
-                                                       printf "%s\n" "add rule inet banIP _inbound ${feed_dport} ip saddr @${feed} ${log_inbound}"
+                                                       printf '%s\n' "add rule inet banIP _inbound ${feed_dport} ip saddr @${feed} ${log_inbound}"
                                                fi
-                                               printf "%s\n" "add rule inet banIP _inbound ${feed_dport} ip saddr @${feed} counter ${feed_target}"
+                                               printf '%s\n' "add rule inet banIP _inbound ${feed_dport} ip saddr @${feed} counter ${feed_target}"
                                        fi
                                        if [ -z "${feed_direction##*outbound*}" ]; then
                                                if [ "${ban_logoutbound}" = "1" ]; then
-                                                       printf "%s\n" "add rule inet banIP _outbound ${feed_dport} ip daddr @${feed} ${log_outbound}"
+                                                       printf '%s\n' "add rule inet banIP _outbound ${feed_dport} ip daddr @${feed} ${log_outbound}"
                                                fi
-                                               printf "%s\n" "add rule inet banIP _outbound ${feed_dport} ip daddr @${feed} counter goto _reject"
+                                               printf '%s\n' "add rule inet banIP _outbound ${feed_dport} ip daddr @${feed} counter goto _reject"
                                        fi
                                } >"${tmp_nft}"
                        elif [ "${feed_ipv}" = "6" ]; then
                                {
                                        # nft header (IPv6 Set) incl. inbound and outbound rules
                                        #
-                                       printf "%s\n\n" "#!${ban_nftcmd} -f"
+                                       printf '%s\n\n' "#!${ban_nftcmd} -f"
                                        [ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
-                                       printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}.1") }"
+                                       printf '%s\n' "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}.1") }"
                                        if [ -z "${feed_direction##*inbound*}" ]; then
                                                if [ "${ban_loginbound}" = "1" ]; then
-                                                       printf "%s\n" "add rule inet banIP _inbound ${feed_dport} ip6 saddr @${feed} ${log_inbound}"
+                                                       printf '%s\n' "add rule inet banIP _inbound ${feed_dport} ip6 saddr @${feed} ${log_inbound}"
                                                fi
-                                               printf "%s\n" "add rule inet banIP _inbound ${feed_dport} ip6 saddr @${feed} counter ${feed_target}"
+                                               printf '%s\n' "add rule inet banIP _inbound ${feed_dport} ip6 saddr @${feed} counter ${feed_target}"
                                        fi
                                        if [ -z "${feed_direction##*outbound*}" ]; then
                                                if [ "${ban_logoutbound}" = "1" ]; then
-                                                       printf "%s\n" "add rule inet banIP _outbound ${feed_dport} ip6 daddr @${feed} ${log_outbound}"
+                                                       printf '%s\n' "add rule inet banIP _outbound ${feed_dport} ip6 daddr @${feed} ${log_outbound}"
                                                fi
-                                               printf "%s\n" "add rule inet banIP _outbound ${feed_dport} ip6 daddr @${feed} counter goto _reject"
+                                               printf '%s\n' "add rule inet banIP _outbound ${feed_dport} ip6 daddr @${feed} counter goto _reject"
                                        fi
                                } >"${tmp_nft}"
                        fi
@@ -1545,7 +1543,7 @@ f_down() {
                                for split_file in "${tmp_file}".*; do
                                        if [ -s "${split_file}" ]; then
                                                "${ban_sedcmd}" -i "1 i #!${ban_nftcmd} -f\nadd element inet banIP ${feed} { " "${split_file}"
-                                               printf "%s\n" "}" >>"${split_file}"
+                                               printf '%s\n' "}" >>"${split_file}"
 
                                                # load split file to nftset
                                                #
@@ -1605,9 +1603,9 @@ f_rmset() {
        json_get_keys feedlist
        tmp_del="${ban_tmpfile}.final.delete"
        table_json="$("${ban_nftcmd}" -tj list table inet banIP 2>>"${ban_errorlog}")"
-       table_sets="$(printf "%s\n" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.set.family="inet"].set.name')"
+       table_sets="$(printf '%s\n' "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.set.family="inet"].set.name')"
        {
-               printf "%s\n\n" "#!${ban_nftcmd} -f"
+               printf '%s\n\n' "#!${ban_nftcmd} -f"
                for feed in ${table_sets}; do
                        _rmset_skip="0"
                        case " allowlist blocklist ${ban_feed} " in
@@ -1706,14 +1704,14 @@ f_rmset() {
                                "${ban_rmcmd}" -f "${ban_backupdir}/banIP.${feed}.gz"
                                for chain in _inbound _outbound; do
                                        for expr in 0 1 2; do
-                                               handles="$(printf "%s\n" "${table_json}" | "${ban_jsoncmd}" -q -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[${expr}].match.right=\"@${feed}\"].handle" | "${ban_xargscmd}")"
+                                               handles="$(printf '%s\n' "${table_json}" | "${ban_jsoncmd}" -q -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[${expr}].match.right=\"@${feed}\"].handle" | "${ban_xargscmd}")"
                                                for handle in ${handles}; do
-                                                       printf "%s\n" "delete rule inet banIP ${chain} handle ${handle}"
+                                                       printf '%s\n' "delete rule inet banIP ${chain} handle ${handle}"
                                                done
                                        done
                                done
-                               printf "%s\n" "flush set inet banIP ${feed}"
-                               printf "%s\n\n" "delete set inet banIP ${feed}"
+                               printf '%s\n' "flush set inet banIP ${feed}"
+                               printf '%s\n\n' "delete set inet banIP ${feed}"
                        fi
                done
        } >"${tmp_del}"
@@ -1736,25 +1734,25 @@ f_genstatus() {
        local mem_free nft_ver chain_cnt set_cnt rule_cnt object end_time duration table table_sets element_cnt="0" custom_feed="0" split="0" status="${1}"
 
        mem_free="$("${ban_awkcmd}" '/^MemAvailable/{printf "%.2f", $2/1024}' "/proc/meminfo" 2>>"${ban_errorlog}")"
-       nft_ver="$(printf "%s" "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages["nftables-json"]')"
+       nft_ver="$(printf '%s' "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages["nftables-json"]')"
 
        [ -z "${ban_dev}" ] && f_conf
        if [ "${status}" = "active" ]; then
                table="$("${ban_nftcmd}" -tj list table inet banIP 2>>"${ban_errorlog}")"
-               table_sets="$(printf "%s" "${table}" | "${ban_jsoncmd}" -qe '@.nftables[@.set.family="inet"].set.name')"
+               table_sets="$(printf '%s' "${table}" | "${ban_jsoncmd}" -qe '@.nftables[@.set.family="inet"].set.name')"
                for object in ${table_sets}; do
                        element_cnt="$((element_cnt + $("${ban_nftcmd}" -j list set inet banIP "${object}" 2>>"${ban_errorlog}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*]' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")))"
                done
-               chain_cnt="$(printf "%s" "${table}" | "${ban_jsoncmd}" -qe '@.nftables[*].chain.name' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")"
-               set_cnt="$(printf "%s" "${table}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.name' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")"
-               rule_cnt="$(printf "%s" "${table}" | "${ban_jsoncmd}" -qe '@.nftables[*].rule' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")"
+               chain_cnt="$(printf '%s' "${table}" | "${ban_jsoncmd}" -qe '@.nftables[*].chain.name' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")"
+               set_cnt="$(printf '%s' "${table}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.name' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")"
+               rule_cnt="$(printf '%s' "${table}" | "${ban_jsoncmd}" -qe '@.nftables[*].rule' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")"
                element_cnt="$("${ban_awkcmd}" -v cnt="${element_cnt}" 'BEGIN{res="";pos=0;for(i=length(cnt);i>0;i--){res=substr(cnt,i,1)res;pos++;if(pos==3&&i>1){res=" "res;pos=0;}}; printf"%s",res}')"
-               if [ -n "${ban_starttime}" ] && [ "${ban_action}" != "boot" ]; then
+               if [ -n "${ban_starttime}" ]; then
                        read -r end_time _ < "/proc/uptime"
                        end_time="${end_time%%.*}"
                        duration="$(((end_time - ban_starttime) / 60))m $(((end_time - ban_starttime) % 60))s"
                fi
-               runtime="mode: ${ban_action}, $(date "+%d/%m/%Y %H:%M:%S"), duration: ${duration:-"-"}, memory: ${mem_free} MB available"
+               runtime="mode: ${ban_action}, date / time: $(date "+%d/%m/%Y %H:%M:%S"), duration: ${duration:-"-"}, memory: ${mem_free} MB available"
        fi
        [ -s "${ban_customfeedfile}" ] && custom_feed="1"
        [ "${ban_splitsize:-"0"}" -gt "0" ] && split="1"
@@ -1812,7 +1810,7 @@ f_getstatus() {
        [ -z "${ban_dev}" ] && f_conf
        json_load_file "${ban_rtfile}" >/dev/null 2>&1
        if json_get_keys keylist; then
-               printf "%s\n" "::: banIP runtime information"
+               printf '%s\n' "::: banIP runtime information"
                for key in ${keylist}; do
                        if [ "${key}" = "active_feeds" ] || [ "${key}" = "active_uplink" ]; then
                                json_get_values values "${key}" >/dev/null 2>&1
@@ -1834,11 +1832,11 @@ f_getstatus() {
                                fi
                        fi
                        if [ "${key}" != "wan_interfaces" ] && [ "${key}" != "vlan_allow" ] && [ "${key}" != "vlan_block" ]; then
-                               printf "  + %-17s : %s\n" "${key}" "${value:-"-"}"
+                               printf '  + %-17s : %s\n' "${key}" "${value:-"-"}"
                        fi
                done
        else
-               printf "%s\n" "::: no banIP runtime information available"
+               printf '%s\n' "::: no banIP runtime information available"
        fi
 }
 
@@ -1892,7 +1890,7 @@ f_lookup() {
 # table statistics
 #
 f_report() {
-       local report_jsn report_txt tmp_val table_json item table_sets set_cnt set_inbound set_outbound set_cntinbound set_cntoutbound set_proto set_dport set_details
+       local report_jsn report_txt tmp_val table_json item sep table_sets set_cnt set_inbound set_outbound set_cntinbound set_cntoutbound set_proto set_dport set_details
        local expr detail jsnval timestamp autoadd_allow autoadd_block sum_sets sum_setinbound sum_setoutbound sum_cntelements sum_cntinbound sum_cntoutbound quantity
        local chunk map_jsn chain set_elements set_json sum_setelements sum_synflood sum_udpflood sum_icmpflood sum_ctinvalid sum_tcpinvalid sum_setports sum_bcp38 output="${1}"
 
@@ -1908,7 +1906,7 @@ f_report() {
                : >"${report_jsn}"
                : >"${map_jsn}"
                table_json="$("${ban_nftcmd}" -tj list table inet banIP 2>>"${ban_errorlog}")"
-               table_sets="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.set.family="inet"].set.name')"
+               table_sets="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.set.family="inet"].set.name')"
                sum_sets="0"
                sum_cntelements="0"
                sum_setinbound="0"
@@ -1917,19 +1915,19 @@ f_report() {
                sum_cntoutbound="0"
                sum_setports="0"
                sum_setelements="0"
-               sum_synflood="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_synflood"].*.packets')"
-               sum_udpflood="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_udpflood"].*.packets')"
-               sum_icmpflood="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_icmpflood"].*.packets')"
-               sum_ctinvalid="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_ctinvalid"].*.packets')"
-               sum_tcpinvalid="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_tcpinvalid"].*.packets')"
-               sum_bcp38="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_bcp38"].*.packets')"
+               sum_synflood="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_synflood"].*.packets')"
+               sum_udpflood="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_udpflood"].*.packets')"
+               sum_icmpflood="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_icmpflood"].*.packets')"
+               sum_ctinvalid="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_ctinvalid"].*.packets')"
+               sum_tcpinvalid="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_tcpinvalid"].*.packets')"
+               sum_bcp38="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_bcp38"].*.packets')"
                timestamp="$(date "+%Y-%m-%d %H:%M:%S")"
 
                cnt="1"
                for item in ${table_sets}; do
                        (
                                set_json="$("${ban_nftcmd}" -j list set inet banIP "${item}" 2>>"${ban_errorlog}")"
-                               set_cnt="$(printf "%s" "${set_json}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*]' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")"
+                               set_cnt="$(printf '%s' "${set_json}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*]' | "${ban_wccmd}" -l 2>>"${ban_errorlog}")"
                                set_cntinbound=""
                                set_cntoutbound=""
                                set_inbound=""
@@ -1940,16 +1938,16 @@ f_report() {
                                for chain in _inbound _outbound; do
                                        for expr in 0 1 2; do
                                                if [ "${chain}" = "_inbound" ] && [ -z "${set_cntinbound}" ]; then
-                                                       set_cntinbound="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[${expr}].match.right=\"@${item}\"].expr[*].counter.packets")"
+                                                       set_cntinbound="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[${expr}].match.right=\"@${item}\"].expr[*].counter.packets")"
                                                elif [ "${chain}" = "_outbound" ] && [ -z "${set_cntoutbound}" ]; then
-                                                       set_cntoutbound="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[${expr}].match.right=\"@${item}\"].expr[*].counter.packets")"
+                                                       set_cntoutbound="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[${expr}].match.right=\"@${item}\"].expr[*].counter.packets")"
                                                fi
-                                               [ -z "${set_proto}" ] && set_proto="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[2].match.right=\"@${item}\"].expr[0].match.right.set")"
-                                               [ -z "${set_proto}" ] && set_proto="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[1].match.right=\"@${item}\"].expr[0].match.left.payload.protocol")"
-                                               [ -z "${set_dport}" ] && set_dport="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[2].match.right=\"@${item}\"].expr[1].match.right.set")"
-                                               [ -z "${set_dport}" ] && set_dport="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[2].match.right=\"@${item}\"].expr[1].match.right")"
-                                               [ -z "${set_dport}" ] && set_dport="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[1].match.right=\"@${item}\"].expr[0].match.right.set")"
-                                               [ -z "${set_dport}" ] && set_dport="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[1].match.right=\"@${item}\"].expr[0].match.right")"
+                                               [ -z "${set_proto}" ] && set_proto="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[2].match.right=\"@${item}\"].expr[0].match.right.set")"
+                                               [ -z "${set_proto}" ] && set_proto="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[1].match.right=\"@${item}\"].expr[0].match.left.payload.protocol")"
+                                               [ -z "${set_dport}" ] && set_dport="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[2].match.right=\"@${item}\"].expr[1].match.right.set")"
+                                               [ -z "${set_dport}" ] && set_dport="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[2].match.right=\"@${item}\"].expr[1].match.right")"
+                                               [ -z "${set_dport}" ] && set_dport="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[1].match.right=\"@${item}\"].expr[0].match.right.set")"
+                                               [ -z "${set_dport}" ] && set_dport="$(printf '%s' "${table_json}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.chain=\"${chain}\"][@.expr[1].match.right=\"@${item}\"].expr[0].match.right")"
                                        done
                                done
                                if [ -n "${set_proto}" ] && [ -n "${set_dport}" ]; then
@@ -1962,7 +1960,7 @@ f_report() {
                                        set_dport="${set_proto}: $(f_trim "${set_dport}")"
                                fi
                                if [ "${ban_nftcount}" = "1" ]; then
-                                       set_elements="$(printf "%s" "${set_json}" | "${ban_jsoncmd}" -l50 -qe '@.nftables[*].set.elem[*][@.counter.packets>0].val' |
+                                       set_elements="$(printf '%s' "${set_json}" | "${ban_jsoncmd}" -l50 -qe '@.nftables[*].set.elem[*][@.counter.packets>0].val' |
                                                "${ban_awkcmd}" -F '[ ,]' '{ORS=" ";if($2=="\"range\":"||$2=="\"concat\":")printf"%s, ",$4;else if($2=="\"prefix\":")printf"%s, ",$5;else printf"\"%s\", ",$1}')"
                                fi
                                if [ -n "${set_cntinbound}" ]; then
@@ -1977,33 +1975,33 @@ f_report() {
                                        set_outbound="-"
                                        set_cntoutbound=""
                                fi
-                               if [ "${cnt}" = "1" ]; then
-                                       printf "%s\n" "{ \
-                                               \"sets\":{ \"${item}\":{ \"cnt_elements\": \"${set_cnt}\", \
-                                               \"cnt_inbound\": \"${set_cntinbound}\", \
-                                               \"inbound\": \"${set_inbound}\", \
-                                               \"cnt_outbound\": \"${set_cntoutbound}\", \
-                                               \"outbound\": \"${set_outbound}\", \
-                                               \"port\": \"${set_dport:-"-"}\", \
-                                               \"set_elements\": [ ${set_elements%%??} ] \
-                                       }" >>"${report_jsn}"
-                               else
-                                       printf "%s\n" ", \
-                                               \"${item}\":{ \"cnt_elements\": \"${set_cnt}\", \
-                                               \"cnt_inbound\": \"${set_cntinbound}\", \
-                                               \"inbound\": \"${set_inbound}\", \
-                                               \"cnt_outbound\": \"${set_cntoutbound}\", \
-                                               \"outbound\": \"${set_outbound}\", \
-                                               \"port\": \"${set_dport:-"-"}\", \
-                                               \"set_elements\": [ ${set_elements%%??} ] \
-                                       }" >>"${report_jsn}"
-                               fi
+                               printf '%s\n' "\"${item}\":{ \"cnt_elements\": \"${set_cnt}\", \
+                                       \"cnt_inbound\": \"${set_cntinbound}\", \
+                                       \"inbound\": \"${set_inbound}\", \
+                                       \"cnt_outbound\": \"${set_cntoutbound}\", \
+                                       \"outbound\": \"${set_outbound}\", \
+                                       \"port\": \"${set_dport:-"-"}\", \
+                                       \"set_elements\": [ ${set_elements%%??} ] \
+                               }" >"${report_jsn}.${item}"
                        ) &
-                       [ "${cnt}" -eq "1" ] || [ "${cnt}" -gt "${ban_cores}" ] && wait -n
+                       [ "${cnt}" -gt "${ban_cores}" ] && wait -n
                        cnt="$((cnt + 1))"
                done
                wait
-               printf "\n%s\n" "} }" >>"${report_jsn}"
+
+               # assemble JSON from per-set fragments
+               #
+               printf '%s' "{ \"sets\":{ " >"${report_jsn}"
+               sep=""
+               for item in ${table_sets}; do
+                       if [ -s "${report_jsn}.${item}" ]; then
+                               printf '%s' "${sep}" >>"${report_jsn}"
+                               "${ban_catcmd}" "${report_jsn}.${item}" >>"${report_jsn}"
+                               "${ban_rmcmd}" -f "${report_jsn}.${item}"
+                               sep=", "
+                       fi
+               done
+               printf '\n%s\n' "} }" >>"${report_jsn}"
 
                # add sum statistics
                #
@@ -2025,7 +2023,7 @@ f_report() {
                                                        "set_elements")
                                                                json_get_values jsnval "${detail}" >/dev/null 2>&1
                                                                if [ -n "${jsnval}" ]; then
-                                                                       jsnval="$(printf "%s" "${jsnval}" | "${ban_wccmd}" -w)"
+                                                                       jsnval="$(printf '%s' "${jsnval}" | "${ban_wccmd}" -w)"
                                                                        sum_setelements="$((sum_setelements + jsnval))"
                                                                fi
                                                                ;;
@@ -2057,7 +2055,7 @@ f_report() {
                                                                json_get_var jsnval "${detail}" >/dev/null 2>&1
                                                                if [ "${jsnval}" != "-" ]; then
                                                                        jsnval="${jsnval//[^0-9 ]/}"
-                                                                       jsnval="$(printf "%s" "${jsnval}" | "${ban_wccmd}" -w)"
+                                                                       jsnval="$(printf '%s' "${jsnval}" | "${ban_wccmd}" -w)"
                                                                        sum_setports="$((sum_setports + jsnval))"
                                                                fi
                                                                ;;
@@ -2066,7 +2064,7 @@ f_report() {
                                        json_select ".."
                                done
                                "${ban_sedcmd}" -i ':a;$!N;1,1ba;P;$d;D' "${report_jsn}"
-                               printf "%s\n" "}, \
+                               printf '%s\n' "}, \
                                        \"timestamp\": \"${timestamp}\", \
                                        \"autoadd_allow\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_allowlist}")\", \
                                        \"autoadd_block\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_blocklist}")\", \
@@ -2101,7 +2099,7 @@ f_report() {
                                jsnval="\"${jsnval// /\", \"}\""
                                if [ "${jsnval}" != '""' ]; then
                                        {
-                                               printf "%s" ",[{}"
+                                               printf '%s' ",[{}"
                                                "${ban_fetchcmd}" ${ban_geoparm} "[ ${jsnval} ]" "${ban_geourl}" 2>>"${ban_errorlog}" |
                                                        "${ban_jsoncmd}" -qe '@[*&&@.status="success"]' | "${ban_awkcmd}" -v feed="homeIP" '{printf ",{\"%s\": %s}\n",feed,$0}'
                                        } >>"${map_jsn}"
@@ -2124,22 +2122,22 @@ f_report() {
                                                                fi
                                                        done
                                                        if [ "${jsnval}" != '""' ]; then
-                                                               quantity="0"
-                                                               chunk=""
                                                                (
+                                                                       quantity="0"
+                                                                       chunk=""
                                                                        for ip in ${jsnval}; do
                                                                                chunk="${chunk} ${ip}"
                                                                                quantity="$((quantity + 1))"
                                                                                if [ "${quantity}" -eq "100" ]; then
                                                                                        "${ban_fetchcmd}" ${ban_geoparm} "[ ${chunk%%?} ]" "${ban_geourl}" 2>>"${ban_errorlog}" |
-                                                                                               "${ban_jsoncmd}" -qe '@[*&&@.status="success"]' | "${ban_awkcmd}" -v feed="${item//_v/.v}" '{printf ",{\"%s\": %s}\n",feed,$0}' >>"${map_jsn}"
+                                                                                               "${ban_jsoncmd}" -qe '@[*&&@.status="success"]' | "${ban_awkcmd}" -v feed="${item//_v/.v}" '{printf ",{\"%s\": %s}\n",feed,$0}' >"${map_jsn}.${item}"
                                                                                        chunk=""
                                                                                        quantity="0"
                                                                                fi
                                                                        done
                                                                        if [ "${quantity}" -gt "0" ]; then
                                                                                "${ban_fetchcmd}" ${ban_geoparm} "[ ${chunk} ]" "${ban_geourl}" 2>>"${ban_errorlog}" |
-                                                                                       "${ban_jsoncmd}" -qe '@[*&&@.status="success"]' | "${ban_awkcmd}" -v feed="${item//_v/.v}" '{printf ",{\"%s\": %s}\n",feed,$0}' >>"${map_jsn}"
+                                                                                       "${ban_jsoncmd}" -qe '@[*&&@.status="success"]' | "${ban_awkcmd}" -v feed="${item//_v/.v}" '{printf ",{\"%s\": %s}\n",feed,$0}' >>"${map_jsn}.${item}"
                                                                        fi
                                                                ) &
                                                                [ "${cnt}" -gt "${ban_cores}" ] && wait -n
@@ -2148,6 +2146,15 @@ f_report() {
                                                        json_select ".."
                                                done
                                                wait
+
+                                               # assemble map data from per-set fragments
+                                               #
+                                               for item in ${table_sets}; do
+                                                       if [ -s "${map_jsn}.${item}" ]; then
+                                                               "${ban_catcmd}" "${map_jsn}.${item}" >>"${map_jsn}"
+                                                               "${ban_rmcmd}" -f "${map_jsn}.${item}"
+                                                       fi
+                                               done
                                        fi
                                fi
                        fi
@@ -2176,33 +2183,33 @@ f_report() {
                                json_get_var sum_setports "sum_setports" >/dev/null 2>&1
                                json_get_var sum_setelements "sum_setelements" >/dev/null 2>&1
                                {
-                                       printf "%s\n%s\n%s\n" ":::" "::: banIP Set Statistics" ":::"
-                                       printf "%s\n" "    Timestamp: ${timestamp}"
-                                       printf "%s\n" "    ------------------------------"
-                                       printf "%s\n" "    blocked syn-flood packets  : ${sum_synflood}"
-                                       printf "%s\n" "    blocked udp-flood packets  : ${sum_udpflood}"
-                                       printf "%s\n" "    blocked icmp-flood packets : ${sum_icmpflood}"
-                                       printf "%s\n" "    blocked invalid ct packets : ${sum_ctinvalid}"
-                                       printf "%s\n" "    blocked invalid tcp packets: ${sum_tcpinvalid}"
-                                       printf "%s\n" "    blocked bcp38 packets      : ${sum_bcp38}"
-                                       printf "%s\n" "    ---"
-                                       printf "%s\n" "    auto-added IPs to allowlist: ${autoadd_allow}"
-                                       printf "%s\n\n" "    auto-added IPs to blocklist: ${autoadd_block}"
+                                       printf '%s\n%s\n%s\n' ":::" "::: banIP Set Statistics" ":::"
+                                       printf '%s\n' "    Timestamp: ${timestamp}"
+                                       printf '%s\n' "    ------------------------------"
+                                       printf '%s\n' "    blocked syn-flood packets  : ${sum_synflood}"
+                                       printf '%s\n' "    blocked udp-flood packets  : ${sum_udpflood}"
+                                       printf '%s\n' "    blocked icmp-flood packets : ${sum_icmpflood}"
+                                       printf '%s\n' "    blocked invalid ct packets : ${sum_ctinvalid}"
+                                       printf '%s\n' "    blocked invalid tcp packets: ${sum_tcpinvalid}"
+                                       printf '%s\n' "    blocked bcp38 packets      : ${sum_bcp38}"
+                                       printf '%s\n' "    ---"
+                                       printf '%s\n' "    auto-added IPs to allowlist: ${autoadd_allow}"
+                                       printf '%s\n\n' "    auto-added IPs to blocklist: ${autoadd_block}"
                                        json_select "sets" >/dev/null 2>&1
                                        json_get_keys table_sets >/dev/null 2>&1
-                                       table_sets="$(printf "%s\n" ${table_sets} | "${ban_sortcmd}")"
+                                       table_sets="$(printf '%s\n' ${table_sets} | "${ban_sortcmd}")"
                                        if [ -n "${table_sets}" ]; then
-                                               printf "%-25s%-15s%-24s%-24s%-24s%-24s\n" "    Set" "| Count   " "| Inbound (packets)" "| Outbound (packets)" "| Port/Protocol      " "| Elements (max. 50) "
-                                               printf "%s\n" "    ---------------------+--------------+-----------------------+-----------------------+-----------------------+------------------------"
+                                               printf '%-25s%-15s%-24s%-24s%-24s%-24s\n' "    Set" "| Count   " "| Inbound (packets)" "| Outbound (packets)" "| Port/Protocol      " "| Elements (max. 50) "
+                                               printf '%s\n' "    ---------------------+--------------+-----------------------+-----------------------+-----------------------+------------------------"
                                                for item in ${table_sets}; do
-                                                       printf "    %-21s" "${item//_v/.v}"
+                                                       printf '    %-21s' "${item//_v/.v}"
                                                        json_select "${item}"
                                                        json_get_keys set_details
                                                        for detail in ${set_details}; do
                                                                case "${detail}" in
                                                                        "cnt_elements")
                                                                                json_get_var jsnval "${detail}" >/dev/null 2>&1
-                                                                               printf "%-15s" "| ${jsnval}"
+                                                                               printf '%-15s' "| ${jsnval}"
                                                                                ;;
                                                                        "cnt_inbound" | "cnt_outbound")
                                                                                json_get_var jsnval "${detail}" >/dev/null 2>&1
@@ -2211,25 +2218,25 @@ f_report() {
                                                                        "set_elements")
                                                                                json_get_values jsnval "${detail}" >/dev/null 2>&1
                                                                                jsnval="${jsnval// /, }"
-                                                                               printf "%-24s" "| ${jsnval:0:24}"
+                                                                               printf '%-24s' "| ${jsnval:0:24}"
                                                                                jsnval="${jsnval:24}"
                                                                                while [ -n "${jsnval}" ]; do
-                                                                                       printf "\n%-25s%-15s%-24s%-24s%-24s%-24s" "" "|" "|" "|" "|" "| ${jsnval:0:24}"
+                                                                                       printf '\n%-25s%-15s%-24s%-24s%-24s%-24s' "" "|" "|" "|" "|" "| ${jsnval:0:24}"
                                                                                        jsnval="${jsnval:24}"
                                                                                done
                                                                                ;;
                                                                        *)
                                                                                json_get_var jsnval "${detail}" >/dev/null 2>&1
-                                                                               printf "%-24s" "| ${jsnval}${tmp_val}"
+                                                                               printf '%-24s' "| ${jsnval}${tmp_val}"
                                                                                tmp_val=""
                                                                                ;;
                                                                esac
                                                        done
-                                                       printf "\n"
+                                                       printf '\n'
                                                        json_select ".."
                                                done
-                                               printf "%s\n" "    ---------------------+--------------+-----------------------+-----------------------+-----------------------+------------------------"
-                                               printf "%-25s%-15s%-24s%-24s%-24s%-24s\n" "    ${sum_sets}" "| ${sum_cntelements}" "| ${sum_setinbound} (${sum_cntinbound})" "| ${sum_setoutbound} (${sum_cntoutbound})" "| ${sum_setports}" "| ${sum_setelements}"
+                                               printf '%s\n' "    ---------------------+--------------+-----------------------+-----------------------+-----------------------+------------------------"
+                                               printf '%-25s%-15s%-24s%-24s%-24s%-24s\n' "    ${sum_sets}" "| ${sum_cntelements}" "| ${sum_setinbound} (${sum_cntinbound})" "| ${sum_setoutbound} (${sum_cntoutbound})" "| ${sum_setports}" "| ${sum_setelements}"
                                        fi
                                } >>"${report_txt}"
                        fi
@@ -2246,10 +2253,10 @@ f_report() {
                "json")
                        if [ "${ban_nftcount}" = "1" ] && [ "${ban_map}" = "1" ]; then
                                jsn="$("${ban_catcmd}" ${report_jsn} ${map_jsn} 2>>"${ban_errorlog}")"
-                               [ -n "${jsn}" ] && printf "[%s]]\n" "${jsn}"
+                               [ -n "${jsn}" ] && printf '[%s]]\n' "${jsn}"
                        else
                                jsn="$("${ban_catcmd}" ${report_jsn} 2>>"${ban_errorlog}")"
-                               [ -n "${jsn}" ] && printf "[%s]\n" "${jsn}"
+                               [ -n "${jsn}" ] && printf '[%s]\n' "${jsn}"
                        fi
                        ;;
                "mail")
@@ -2257,7 +2264,7 @@ f_report() {
                        : >"${report_txt}"
                        ;;
                "gen")
-                       printf "%s\n" "1" >"/var/run/banIP/banIP.report"
+                       printf '%s\n' "1" >"/var/run/banIP/banIP.report"
                        ;;
                *)
                        : >"${report_txt}"
@@ -2277,15 +2284,15 @@ f_search() {
        #
        case "${input}" in
                ''|*[!0-9A-Fa-f:/.]*)
-                       printf "%s\n%s\n%s\n" ":::" "::: no valid search input" ":::"
-                       printf "%s\n%s\n%s\n" ":::" "::: no valid search input" ":::" >"${result}"
+                       printf '%s\n%s\n%s\n' ":::" "::: no valid search input" ":::"
+                       printf '%s\n%s\n%s\n' ":::" "::: no valid search input" ":::" >"${result}"
                        return
                        ;;
        esac
 
        # determine protocol via awk
        #
-       res="$(printf "%s" "${input}" | "${ban_awkcmd}" '
+       res="$(printf '%s' "${input}" | "${ban_awkcmd}" '
        {
                if (match($0,/([1-9][0-9]{0,2}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/([12]?[0-9]|3[012]))?[[:space:]]*$/)) {
                        printf "v4 %s",substr($0,RSTART,RLENGTH)
@@ -2303,17 +2310,17 @@ f_search() {
                table_sets="$("${ban_nftcmd}" -tj list table inet banIP 2>>"${ban_errorlog}" | \
                        "${ban_jsoncmd}" -qe "@.nftables[@.set.type=\"ip${proto}_addr\"].set.name")"
        else
-               printf "%s\n%s\n%s\n" ":::" "::: no valid search input" ":::"
-               printf "%s\n%s\n%s\n" ":::" "::: no valid search input" ":::" >"${result}"
+               printf '%s\n%s\n%s\n' ":::" "::: no valid search input" ":::"
+               printf '%s\n%s\n%s\n' ":::" "::: no valid search input" ":::" >"${result}"
                return
        fi
 
        # initial output
        #
        {
-               printf "%s\n%s\n%s\n" ":::" "::: banIP Search" ":::"
-               printf "    %s\n" "Looking for IP '${ip}' on $(date "+%Y-%m-%d %H:%M:%S")"
-               printf "    %s\n" "---"
+               printf '%s\n%s\n%s\n' ":::" "::: banIP Search" ":::"
+               printf '    %s\n' "Looking for IP '${ip}' on $(date "+%Y-%m-%d %H:%M:%S")"
+               printf '    %s\n' "---"
        } >"${tmp_result}"
 
        # search for IP in Sets
@@ -2327,7 +2334,7 @@ f_search() {
                esac
                (
                        if "${ban_nftcmd}" get element inet banIP "${item}" "{ ${ip} }" >/dev/null 2>&1; then
-                               printf "    %s\n" "IP found in Set '${item}'" >>"${tmp_result}"
+                               printf '    %s\n' "IP found in Set '${item}'" >"${tmp_result}.${item}"
                        fi
                ) &
                [ "${cnt}" -gt "${ban_cores}" ] && wait -n
@@ -2335,10 +2342,19 @@ f_search() {
        done
        wait
 
+       # assemble search results from per-set fragments
+       #
+       for item in ${table_sets}; do
+               if [ -s "${tmp_result}.${item}" ]; then
+                       "${ban_catcmd}" "${tmp_result}.${item}" >>"${tmp_result}"
+                       "${ban_rmcmd}" -f "${tmp_result}.${item}"
+               fi
+       done
+
        # output result
        #
        if ! "${ban_grepcmd}" -qm1 "found" "${tmp_result}"; then
-               printf "    %s\n" "IP not found" >>"${tmp_result}"
+               printf '    %s\n' "IP not found" >>"${tmp_result}"
        fi
        "${ban_mvcmd}" -f "${tmp_result}" "${result}"
        "${ban_catcmd}" "${result}"
@@ -2353,7 +2369,7 @@ f_content() {
        #
        case "${input}" in
                ""|*[!a-zA-Z0-9_.]*)
-                       printf "%s\n%s\n%s\n" ":::" "::: no valid Set input" ":::"
+                       printf '%s\n%s\n%s\n' ":::" "::: no valid Set input" ":::"
                        return
                        ;;
        esac
@@ -2366,7 +2382,7 @@ f_content() {
                        filter="true"
                        ;;
                *)
-                       printf "%s\n%s\n%s\n" ":::" "::: no valid filter input" ":::"
+                       printf '%s\n%s\n%s\n' ":::" "::: no valid filter input" ":::"
                        return
                        ;;
        esac
@@ -2374,7 +2390,7 @@ f_content() {
        # check if Set exists
        #
        if ! "${ban_nftcmd}" -t list set inet banIP "${input}" >/dev/null 2>&1; then
-               printf "%s\n%s\n%s\n" ":::" "::: Set '${input}' not found" ":::"
+               printf '%s\n%s\n%s\n' ":::" "::: Set '${input}' not found" ":::"
                return
        fi
 
@@ -2383,22 +2399,22 @@ f_content() {
        set_raw="$("${ban_nftcmd}" -j list set inet banIP "${input}" 2>>"${ban_errorlog}")"
        if [ "$(uci_get banip global ban_nftcount)" = "1" ]; then
                if [ "${filter}" = "true" ]; then
-                       set_elements="$(printf "%s" "${set_raw}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*][@.counter.packets>0].*' |
+                       set_elements="$(printf '%s' "${set_raw}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*][@.counter.packets>0].*' |
                                "${ban_awkcmd}" 'NR%2==1{ip=$0;next}BEGIN{FS="[:,{}\"]+"}{print ip ", packets: "$4 }')"
                else
-                       set_elements="$(printf "%s" "${set_raw}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*].elem["val","counter"]' |
+                       set_elements="$(printf '%s' "${set_raw}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*].elem["val","counter"]' |
                                "${ban_awkcmd}" 'NR%2==1{ip=$0;next}BEGIN{FS="[:,{}\"]+"}{print ip ", packets: "$4 }')"
                fi
        else
-               set_elements="$(printf "%s" "${set_raw}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*]')"
+               set_elements="$(printf '%s' "${set_raw}" | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*]')"
        fi
 
        # output result
        #
-       printf "%s\n%s\n%s\n" ":::" "::: banIP Set Content" ":::"
-       printf "    %s\n" "List elements of the Set '${input}' on $(date "+%Y-%m-%d %H:%M:%S")"
-       printf "    %s\n" "---"
-       [ -n "${set_elements}" ] && printf "%s\n" "${set_elements}" || printf "    %s\n" "empty Set"
+       printf '%s\n%s\n%s\n' ":::" "::: banIP Set Content" ":::"
+       printf '    %s\n' "List elements of the Set '${input}' on $(date "+%Y-%m-%d %H:%M:%S")"
+       printf '    %s\n' "---"
+       [ -n "${set_elements}" ] && printf '%s\n' "${set_elements}" || printf '    %s\n' "no elements in Set"
 }
 
 # send status mail
@@ -2419,7 +2435,7 @@ f_mail() {
        # send mail
        #
        ban_mailhead="From: ${ban_mailsender}\nTo: ${ban_mailreceiver}\nSubject: ${ban_mailtopic}\nReply-to: ${ban_mailsender}\nMime-Version: 1.0\nContent-Type: text/html;charset=utf-8\nContent-Disposition: inline\n\n"
-       printf "%b" "${ban_mailhead}${mail_text}" | "${ban_mailcmd}" --timeout=10 ${msmtp_debug} -a "${ban_mailprofile}" "${ban_mailreceiver}" >/dev/null 2>&1
+       printf '%b' "${ban_mailhead}${mail_text}" | "${ban_mailcmd}" --timeout=10 ${msmtp_debug} -a "${ban_mailprofile}" "${ban_mailreceiver}" >/dev/null 2>&1
 
        f_log "debug" "f_mail    ::: notification: ${ban_mailnotification}, template: ${ban_mailtemplate}, profile: ${ban_mailprofile}, receiver: ${ban_mailreceiver}, rc: ${?}"
 }
@@ -2428,14 +2444,15 @@ f_mail() {
 #
 f_monitor() {
        local nft_expiry ip proto idx base cidr rdap_log rdap_rc rdap_idx rdap_info log_type allow_v4 allow_v6 block_v4 block_v6
-       local block_cache file cache_ts date_stamp time_now time_elapsed cache_interval rdap_interval rdap_tsfile rdap_lock rdap_jobs
+       local file cache_ts date_stamp time_now time_elapsed cache_interval rdap_interval rdap_tsfile rdap_lock rdap_jobs
+       local block_cache block_cache_limit block_cache_cnt
 
        # intervals for periodic cache refresh and RDAP queries
        #
        cache_interval=300
        rdap_interval=2
        rdap_tsfile="/var/run/banIP/banIP_rdap_ts"
-       printf "%s" "0" > "${rdap_tsfile}"
+       printf '%s' "0" > "${rdap_tsfile}"
 
        # determine log reader type
        #
@@ -2452,9 +2469,9 @@ f_monitor() {
 
                # determine nft timeout expression and cache interval
                #
-               if printf "%s" "${ban_nftexpiry}" | grep -qE '^([1-9][0-9]*(ms|s|m|h|d|w))+$'; then
+               if printf '%s' "${ban_nftexpiry}" | grep -qE '^([1-9][0-9]*(ms|s|m|h|d|w))+$'; then
                        nft_expiry="timeout ${ban_nftexpiry}"
-                       cache_interval="$(printf "%s" "${ban_nftexpiry}" | "${ban_awkcmd}" '{
+                       cache_interval="$(printf '%s' "${ban_nftexpiry}" | "${ban_awkcmd}" '{
                                s = 0
                                str = $0
                                while (match(str, /([0-9]+)(ms|s|m|h|d|w)/, a)) {
@@ -2493,6 +2510,8 @@ f_monitor() {
                cache_ts="${cache_ts%%.*}"
                date_stamp="$(date "+%Y-%m-%d %H:%M:%S")"
                block_cache=""
+               block_cache_limit="500"
+               block_cache_cnt="0"
 
                # clean up stale RDAP lock/done markers from previous runs
                #
@@ -2571,6 +2590,7 @@ f_monitor() {
                                                date_stamp="$(date "+%Y-%m-%d %H:%M:%S")"
                                                cache_ts="${time_now}"
                                                block_cache=""
+                                               block_cache_cnt="0"
                                                "${ban_rmcmd}" -f "${ban_rdapfile}".*.done >/dev/null 2>&1
                                                f_log "debug" "f_monitor ::: refreshed monitor cache at ${date_stamp}"
                                        fi
@@ -2599,6 +2619,12 @@ f_monitor() {
                                        # CIDR-aware allowlist lookup (only at block-time, not every IP)
                                        #
                                        if "${ban_nftcmd}" get element inet banIP "allowlist${proto}" { ${ip} } >/dev/null 2>&1; then
+                                               block_cache_cnt="$((block_cache_cnt + 1))"
+                                               if [ "${block_cache_cnt}" -ge "${block_cache_limit}" ]; then
+                                                       block_cache=""
+                                                       block_cache_cnt="1"
+                                                       f_log "debug" "f_monitor ::: refreshed local monitor cache at ${date_stamp}"
+                                               fi
                                                block_cache="${block_cache} ${ip} "
                                                f_log "debug" "f_monitor ::: skip IP '${ip}', found via allowlist CIDR lookup"
                                                continue
@@ -2607,6 +2633,12 @@ f_monitor() {
                                        # try to add IP to the blocklist Set with appropriate expiry
                                        #
                                        if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" { ${ip} ${nft_expiry} } >/dev/null 2>&1; then
+                                               block_cache_cnt="$((block_cache_cnt + 1))"
+                                               if [ "${block_cache_cnt}" -ge "${block_cache_limit}" ]; then
+                                                       block_cache=""
+                                                       block_cache_cnt="1"
+                                                       f_log "debug" "f_monitor ::: refreshed local monitor cache at ${date_stamp}"
+                                               fi
                                                block_cache="${block_cache} ${ip} "
                                                f_log "info" "add IP '${ip}' (cnt: ${ban_logcount}, expiry: ${ban_nftexpiry:-"0"}) to blocklist${proto} Set"
                                        else
@@ -2639,18 +2671,20 @@ f_monitor() {
                                                                # rate limiting via shared timestamp file
                                                                #
                                                                : >"${rdap_lock}"
-                                                               read -r rdap_ts < "${rdap_tsfile}" 2>/dev/null
-                                                               rdap_ts="${rdap_ts:-0}"
-                                                               read -r time_now _ < "/proc/uptime"
-                                                               time_now="${time_now%%.*}"
-                                                               time_elapsed=$((time_now - rdap_ts))
-                                                               if [ "${time_elapsed}" -lt "${rdap_interval}" ]; then
-                                                                       sleep "$((rdap_interval - time_elapsed))"
-                                                               fi
-                                                               read -r rdap_ts _ < "/proc/uptime"
-                                                               rdap_ts="${rdap_ts%%.*}"
-                                                               printf '%s' "${rdap_ts}" > "${rdap_tsfile}"
-
+                                                               (
+                                                                       flock -x 9
+                                                                       read -r rdap_ts < "${rdap_tsfile}" 2>/dev/null
+                                                                       rdap_ts="${rdap_ts:-0}"
+                                                                       read -r time_now _ < "/proc/uptime"
+                                                                       time_now="${time_now%%.*}"
+                                                                       time_elapsed=$((time_now - rdap_ts))
+                                                                       if [ "${time_elapsed}" -lt "${rdap_interval}" ]; then
+                                                                               sleep "$((rdap_interval - time_elapsed))"
+                                                                       fi
+                                                                       read -r rdap_ts _ < "/proc/uptime"
+                                                                       rdap_ts="${rdap_ts%%.*}"
+                                                                       printf '%s' "${rdap_ts}" > "${rdap_tsfile}"
+                                                               ) 9>"${rdap_tsfile}.lock"
                                                                : >"${ban_rdapfile}.${ip}"
                                                                rdap_log="$("${ban_fetchcmd}" ${ban_rdapparm} "${ban_rdapfile}.${ip}" "${ban_rdapurl}${ip}" 2>&1)"
                                                                rdap_rc="${?}"
@@ -2694,7 +2728,7 @@ f_monitor() {
                                        # persist to local blocklist file if no expiry
                                        #
                                        if [ -z "${ban_nftexpiry}" ] && [ "${ban_autoblocklist}" = "1" ] && ! "${ban_grepcmd}" -q "^${ip}[[:space:]]" "${ban_blocklist}"; then
-                                               printf "%-45s%s\n" "${ip}" "# added on ${date_stamp}" >>"${ban_blocklist}"
+                                               printf '%-45s%s\n' "${ip}" "# added on ${date_stamp}" >>"${ban_blocklist}"
                                                f_log "info" "add IP '${ip}' to local blocklist"
                                        fi
                                ;;
@@ -2724,7 +2758,7 @@ fi
 
 # reference required system utilities
 #
-ban_awkcmd="$(f_cmd gawk awk)"
+ban_awkcmd="$(f_cmd gawk)"
 ban_catcmd="$(f_cmd cat)"
 ban_grepcmd="$(f_cmd grep)"
 ban_jsoncmd="$(f_cmd jsonfilter)"
index b0952f033075b07279cc2637645dcfc6fcb89cc1..4882bd373d27b12d8c8c85504422476b81b9f79c 100755 (executable)
@@ -44,7 +44,7 @@ fi
 #
 f_log "info" "start banIP download processes"
 f_getfeed
-[ "${ban_deduplicate}" = "1" ] && printf "\n" >"${ban_tmpfile}.deduplicate"
+[ "${ban_deduplicate}" = "1" ] && printf '\n' >"${ban_tmpfile}.deduplicate"
 
 # handle downloads
 #
index cd786a5d61b76c101945537eccd53bae5a177d5d..e46c859a33dd7beedb10e9938620d9d299a53d97 100644 (file)
@@ -7,7 +7,7 @@ local banip_info report_info log_info system_info mail_text
 # log info preparation
 #
 if [ -f "${ban_logreadfile}" ] && [ -x "${ban_logreadcmd}" ] && [ "${ban_logreadcmd##*/}" = "tail" ]; then
-       log_info="$("${ban_logreadcmd}" -qn "${ban_loglimit}" "${ban_logreadfile}" 2>/dev/null | "${ban_grepcmd}" -e "banIP/" 2>/dev/null)"
+       log_info="$("${ban_logreadcmd}" -qn "${ban_loglimit}" "${ban_logreadfile}" 2>/dev/null | "${ban_grepcmd}" -e "banIP-" 2>/dev/null)"
 elif [ -x "${ban_logreadcmd}" ] && [ "${ban_logreadcmd##*/}" = "logread" ]; then
        log_info="$("${ban_logreadcmd}" -l "${ban_loglimit}" -e "banIP-" 2>/dev/null)"
 fi
@@ -15,33 +15,33 @@ fi
 # banIP status and report info preparation
 #
 banip_info="$(/etc/init.d/banip status 2>/dev/null)"
-report_info="$(< "${ban_reportdir}/ban_report.txt")" 2>/dev/null
+report_info="$("${ban_catcmd}" "${ban_reportdir}/ban_report.txt" 2>/dev/null)"
 system_info="$(strings /etc/banner 2>/dev/null; "${ban_ubuscmd}" call system board | \
        "${ban_awkcmd}" 'BEGIN{FS="[{}\"]"}{if($2=="kernel"||$2=="hostname"||$2=="system"||$2=="model"||$2=="description")printf "  + %-12s: %s\n",$2,$4}')"
 
 # mail text preparation
 #
 mail_text="$(
-       printf "%s\n" "<html><body><pre style='font-family:monospace;padding:20;background-color:#f3eee5;white-space:pre-wrap;overflow-x:auto;' >"
-       printf "\n%s\n" "<strong>++
+       printf '%s\n' "<html><body><pre style='font-family:monospace;padding:20;background-color:#f3eee5;white-space:pre-wrap;overflow-x:auto;' >"
+       printf '\n%s\n' "<strong>++
 ++ System Information ++
 ++</strong>"
-       printf "%s\n" "${system_info:-"-"}"
-       printf "\n%s\n" "<strong>++
+       printf '%s\n' "${system_info:-"-"}"
+       printf '\n%s\n' "<strong>++
 ++ banIP Status ++
 ++</strong>"
-       printf "%s\n" "${banip_info:-"-"}"
+       printf '%s\n' "${banip_info:-"-"}"
        [ -n "${report_info}" ] && {
-               printf "\n%s\n" "<strong>++
+               printf '\n%s\n' "<strong>++
 ++ banIP Report ++
 ++</strong>"
-               printf "%s\n" "${report_info}"
+               printf '%s\n' "${report_info}"
        }
        [ -n "${log_info}" ] && {
-               printf "\n%s\n" "<strong>++
+               printf '\n%s\n' "<strong>++
 ++ Logfile Information ++
 ++</strong>"
-               printf "%s\n" "${log_info}"
+               printf '%s\n' "${log_info}"
        }
-       printf "%s\n" "</pre></body></html>"
+       printf '%s\n' "</pre></body></html>"
 )"
git clone https://git.99rst.org/PROJECT