1 # banIP shared function library/include - ban incoming and outgoing IPs via named nftables Sets
2 # Copyright (c) 2018-2023 Dirk Brenken (dev@brenken.org)
3 # This is free software, licensed under the GNU General Public License v3.
5 # (s)hellcheck exceptions
6 # shellcheck disable=all
11 export PATH
="/usr/sbin:/usr/bin:/sbin:/bin"
14 ban_backupdir
="/tmp/banIP-backup"
15 ban_reportdir
="/tmp/banIP-report"
16 ban_feedfile
="/etc/banip/banip.feeds"
17 ban_customfeedfile
="/etc/banip/banip.custom.feeds"
18 ban_allowlist
="/etc/banip/banip.allowlist"
19 ban_blocklist
="/etc/banip/banip.blocklist"
20 ban_mailtemplate
="/etc/banip/banip.tpl"
21 ban_pidfile
="/var/run/banip.pid"
22 ban_rtfile
="/var/run/banip_runtime.json"
23 ban_rdapfile
="/var/run/banip_rdap.json"
24 ban_rdapurl
="https://rdap.db.ripe.net/ip/"
25 ban_lock
="/var/run/banip.lock"
26 ban_logreadcmd
="$(command -v logread)"
27 ban_logcmd
="$(command -v logger)"
28 ban_ubuscmd
="$(command -v ubus)"
29 ban_nftcmd
="$(command -v nft)"
30 ban_fw4cmd
="$(command -v fw4)"
31 ban_awkcmd
="$(command -v awk)"
32 ban_grepcmd
="$(command -v grep)"
33 ban_sedcmd
="$(command -v sed)"
34 ban_catcmd
="$(command -v cat)"
35 ban_zcatcmd
="$(command -v zcat)"
36 ban_lookupcmd
="$(command -v nslookup)"
37 ban_jsoncmd
="$(command -v jsonfilter)"
38 ban_mailcmd
="$(command -v msmtp)"
39 ban_mailsender
="no-reply@banIP"
41 ban_mailtopic
="banIP notification"
42 ban_mailprofile
="ban_notify"
43 ban_mailnotification
="0"
44 ban_reportelements
="1"
45 ban_nftloglevel
="warn"
46 ban_nftpriority
="-200"
47 ban_nftpolicy
="memory"
60 ban_autoallowuplink
="subnet"
62 ban_autoblocksubnet
="0"
70 ban_blockforwardwan
=""
71 ban_blockforwardlan
=""
94 # gather system information
99 if [ -z "${ban_dev}" ]; then
100 ban_debug
="$(uci_get banip global ban_debug)"
101 ban_cores
="$(uci_get banip global ban_cores)"
103 ban_packages
="$(${ban_ubuscmd} -S call rpc-sys packagelist '{ "all
": true }' 2>/dev/null)"
104 ban_memory
="$("${ban_awkcmd}" '/^MemAvailable/{printf "%s
",int($2/1000)}' "/proc
/meminfo
" 2>/dev/null)"
105 ban_ver
="$(printf "%s
" "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages.banip')"
106 ban_sysver
="$("${ban_ubuscmd}" -S call system board 2>/dev/null | "${ban_jsoncmd}" -ql1 -e '@.model' -e '@.release.description' |
107 "${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s
, %s
",$1,$2}')"
108 if [ -z "${ban_cores}" ]; then
109 cpu
="$("${ban_grepcmd}" -c '^processor' /proc/cpuinfo 2>/dev/null)"
110 core
="$("${ban_grepcmd}" -cm1 '^core id' /proc/cpuinfo 2>/dev/null)"
111 [ "${cpu}" = "0" ] && cpu
="1"
112 [ "${core}" = "0" ] && core
="1"
113 ban_cores
="$((cpu * core))"
122 if [ ! -d "${dir}" ]; then
125 f_log
"debug" "f_mkdir ::: directory: ${dir}"
134 if [ ! -f "${file}" ]; then
136 f_log
"debug" "f_mkfile ::: file: ${file}"
140 # create temporary files and directories
143 f_mkdir
"${ban_basedir}"
144 ban_tmpdir
="$(mktemp -p "${ban_basedir}" -d)"
145 ban_tmpfile
="$(mktemp -p "${ban_tmpdir}" -tu)"
147 f_log
"debug" "f_tmp ::: base_dir: ${ban_basedir:-"-"}, tmp_dir: ${ban_tmpdir:-"-"}"
155 if [ -d "${dir}" ]; then
157 f_log
"debug" "f_rmdir ::: directory: ${dir}"
166 if [ "${char}" = "1" ]; then
168 elif [ "${char}" = "0" ] ||
[ -z "${char}" ]; then
171 printf "%s" "${char}"
180 string
="${string#"${string%%[![:space:]]*}"}"
181 string
="${string%"${string##*[![:space:]]}"}"
182 printf "%s" "${string}"
190 ppid
="$("${ban_catcmd}" "${ban_pidfile}" 2>/dev/null)"
191 [ -n "${ppid}" ] && pids
="$(pgrep -P "${ppid}" 2>/dev/null)"
192 for pid
in ${pids}; do
193 kill -INT "${pid}" >/dev
/null
2>&1
202 local class
="${1}" log_msg
="${2}"
204 if [ -n "${log_msg}" ] && { [ "${class}" != "debug" ] || [ "${ban_debug}" = "1" ]; }; then
205 if [ -x "${ban_logcmd}" ]; then
206 "${ban_logcmd}" -p "${class}" -t "banIP-${ban_ver}[${$}]" "${log_msg}"
208 printf "%s
%s
%s
\n" "${class}" "banIP-${ban_ver}[${$}]" "${log_msg}"
211 if [ "${class}" = "err
" ]; then
212 "${ban_nftcmd}" delete table inet banIP >/dev/null 2>&1
213 if [ "${ban_enabled}" = "1" ]; then
215 [ "${ban_mailnotification}" = "1" ] && [ -n "${ban_mailreceiver}" ] && [ -x "${ban_mailcmd}" ] && f_mail
217 f_genstatus "disabled
"
219 f_rmdir "${ban_tmpdir}"
229 unset ban_dev ban_vlanallow ban_vlanblock ban_ifv4 ban_ifv6 ban_feed ban_allowurl ban_blockinput ban_blockforwardwan ban_blockforwardlan ban_logterm ban_country ban_asn
234 eval "${option}=\"${value}\""
241 eval "${option}=\"$(printf "%s" "${ban_ifv4}")${value} \""
244 eval "${option}=\"$(printf "%s" "${ban_ifv6}")${value} \""
247 eval "${option}=\"$(printf "%s" "${ban_dev}")${value} \""
250 eval "${option}=\"$(printf "%s" "${ban_vlanallow}")${value} \""
253 eval "${option}=\"$(printf "%s" "${ban_vlanblock}")${value} \""
256 eval "${option}=\"$(printf "%s" "${ban_trigger}")${value} \""
259 eval "${option}=\"$(printf "%s" "${ban_feed}")${value} \""
262 eval "${option}=\"$(printf "%s" "${ban_allowurl}")${value} \""
265 eval "${option}=\"$(printf "%s" "${ban_blockinput}")${value} \""
267 "ban_blockforwardwan
")
268 eval "${option}=\"$(printf "%s" "${ban_blockforwardwan}")${value} \""
270 "ban_blockforwardlan
")
271 eval "${option}=\"$(printf "%s" "${ban_blockforwardlan}")${value} \""
274 eval "${option}=\"$(printf "%s" "${ban_logterm}")${value}\\|
\""
277 eval "${option}=\"$(printf "%s" "${ban_country}")${value} \""
280 eval "${option}=\"$(printf "%s" "${ban_asn}")${value} \""
288 # get nft/monitor actuals
293 if "${ban_nftcmd}" -t list set inet banIP allowlistv4MAC >/dev/null 2>&1; then
298 if pgrep -f "${ban_logreadcmd##*/}" -P "$("${ban_catcmd}" "${ban_pidfile}" 2>/dev/null)" >/dev
/null
2>&1; then
299 monitor
="$(f_char "1")"
301 monitor
="$(f_char "0")"
303 printf "%s" "nft: ${nft}, monitor: ${monitor}"
309 local item utils insecure update
="0"
311 if { [ "${ban_fetchcmd}" = "uclient-fetch" ] && printf "%s" "${ban_packages}" | "${ban_grepcmd}" -q '"libustream-'; } ||
312 { [ "${ban_fetchcmd}" = "wget" ] && printf "%s" "${ban_packages}" | "${ban_grepcmd}" -q '"wget-ssl'; } ||
313 [ "${ban_fetchcmd}" = "curl" ] ||
[ "${ban_fetchcmd}" = "aria2c" ]; then
314 ban_fetchcmd
="$(command -v "${ban_fetchcmd}")"
319 if [ "${ban_autodetect}" = "1" ] && [ ! -x "${ban_fetchcmd}" ]; then
320 utils
="aria2c curl wget uclient-fetch"
321 for item
in ${utils}; do
322 if { [ "${item}" = "uclient-fetch" ] && printf "%s" "${ban_packages}" | "${ban_grepcmd}" -q '"libustream-'; } ||
323 { [ "${item}" = "wget" ] && printf "%s" "${ban_packages}" | "${ban_grepcmd}" -q '"wget-ssl'; } ||
324 [ "${item}" = "curl" ] ||
[ "${item}" = "aria2c" ]; then
325 ban_fetchcmd
="$(command -v "${item}")"
326 if [ -x "${ban_fetchcmd}" ]; then
328 uci_set banip global ban_fetchcmd
"${item}"
336 [ ! -x "${ban_fetchcmd}" ] && f_log
"err" "no download utility with SSL support"
337 case "${ban_fetchcmd##*/}" in
339 [ "${ban_fetchinsecure}" = "1" ] && insecure
="--check-certificate=false"
340 ban_fetchparm
="${ban_fetchparm:-"${insecure} --timeout=20 --retry-wait=10 --max-tries=${ban_fetchretry} --max-file-not-found=${ban_fetchretry} --allow-overwrite=true --auto-file-renaming=false --log-level=warn --dir=/ -o"}"
341 ban_rdapparm
="--timeout=5 --allow-overwrite=true --auto-file-renaming=false --dir=/ -o"
342 ban_etagparm
="--timeout=5 --allow-overwrite=true --auto-file-renaming=false --dir=/ --dry-run --log -"
345 [ "${ban_fetchinsecure}" = "1" ] && insecure
="--insecure"
346 ban_fetchparm
="${ban_fetchparm:-"${insecure} --connect-timeout 20 --retry-delay 10 --retry ${ban_fetchretry} --retry-max-time $((ban_fetchretry * 20)) --retry-all-errors --fail --silent --show-error --location -o"}"
347 ban_rdapparm
="--connect-timeout 5 --silent --location -o"
348 ban_etagparm
="--connect-timeout 5 --silent --location --head"
351 [ "${ban_fetchinsecure}" = "1" ] && insecure
="--no-check-certificate"
352 ban_fetchparm
="${ban_fetchparm:-"${insecure} --no-cache --no-cookies --timeout=20 --waitretry=10 --tries=${ban_fetchretry} --retry-connrefused -O"}"
353 ban_rdapparm
="--timeout=5 -O"
354 ban_etagparm
="--timeout=5 --spider --server-response"
357 [ "${ban_fetchinsecure}" = "1" ] && insecure
="--no-check-certificate"
358 ban_fetchparm
="${ban_fetchparm:-"${insecure} --timeout=20 -O"}"
359 ban_rdapparm
="--timeout=5 -O"
363 f_log
"debug" "f_getfetch ::: auto/update: ${ban_autodetect}/${update}, cmd: ${ban_fetchcmd:-"-"}, fetch_parm: ${ban_fetchparm:-"-"}, rdap_parm: ${ban_rdapparm:-"-"}, etag_parm: ${ban_etagparm:-"-"}"
369 local iface update
="0"
371 if [ "${ban_autodetect}" = "1" ]; then
372 if [ -z "${ban_ifv4}" ]; then
374 network_find_wan iface
375 if [ -n "${iface}" ] && "${ban_ubuscmd}" -t 10 wait_for network.interface."${iface}" >/dev
/null
2>&1; then
378 uci_set banip global ban_protov4
"1"
379 uci_add_list banip global ban_ifv4
"${iface}"
380 f_log
"info" "add IPv4 interface '${iface}' to config"
383 if [ -z "${ban_ifv6}" ]; then
385 network_find_wan6 iface
386 if [ -n "${iface}" ] && "${ban_ubuscmd}" -t 10 wait_for network.interface."${iface}" >/dev
/null
2>&1; then
389 uci_set banip global ban_protov6
"1"
390 uci_add_list banip global ban_ifv6
"${iface}"
391 f_log
"info" "add IPv6 interface '${iface}' to config"
395 if [ -n "$(uci -q changes "banip
")" ]; then
399 ban_ifv4
="${ban_ifv4%%?}"
400 ban_ifv6
="${ban_ifv6%%?}"
401 for iface
in ${ban_ifv4} ${ban_ifv6}; do
402 if ! "${ban_ubuscmd}" -t 10 wait_for network.interface.
"${iface}" >/dev
/null
2>&1; then
403 f_log
"err" "no wan interface '${iface}'"
407 [ -z "${ban_ifv4}" ] && [ -z "${ban_ifv6}" ] && f_log
"err" "no wan interfaces"
409 f_log
"debug" "f_getif ::: auto/update: ${ban_autodetect}/${update}, interfaces (4/6): ${ban_ifv4}/${ban_ifv6}, protocols (4/6): ${ban_protov4}/${ban_protov6}"
415 local dev iface update
="0" cnt
="0" cnt_max
="30"
417 if [ "${ban_autodetect}" = "1" ]; then
418 while [ "${cnt}" -lt "${cnt_max}" ] && [ -z "${ban_dev}" ]; do
420 for iface
in ${ban_ifv4} ${ban_ifv6}; do
421 network_get_device dev
"${iface}"
422 if [ -n "${dev}" ] && ! printf " %s " "${ban_dev}" | "${ban_grepcmd}" -q " ${dev} "; then
423 ban_dev
="${ban_dev}${dev} "
424 uci_add_list banip global ban_dev
"${dev}"
425 f_log
"info" "add device '${dev}' to config"
432 if [ -n "$(uci -q changes "banip
")" ]; then
436 ban_dev
="${ban_dev%%?}"
437 [ -z "${ban_dev}" ] && f_log
"err" "no wan devices"
439 f_log
"debug" "f_getdev ::: auto/update: ${ban_autodetect}/${update}, wan_devices: ${ban_dev}, cnt: ${cnt}"
445 local uplink iface ip update
="0"
447 if [ "${ban_autoallowlist}" = "1" ] && [ "${ban_autoallowuplink}" != "disable" ]; then
448 for iface
in ${ban_ifv4} ${ban_ifv6}; do
450 if [ "${ban_autoallowuplink}" = "subnet" ]; then
451 network_get_subnet uplink
"${iface}"
452 elif [ "${ban_autoallowuplink}" = "ip" ]; then
453 network_get_ipaddr uplink
"${iface}"
455 if [ -n "${uplink}" ] && ! printf " %s " "${ban_uplink}" | "${ban_grepcmd}" -q " ${uplink} "; then
456 ban_uplink
="${ban_uplink}${uplink} "
458 if [ "${ban_autoallowuplink}" = "subnet" ]; then
459 network_get_subnet6 uplink
"${iface}"
460 elif [ "${ban_autoallowuplink}" = "ip" ]; then
461 network_get_ipaddr6 uplink
"${iface}"
463 if [ -n "${uplink}" ] && ! printf " %s " "${ban_uplink}" | "${ban_grepcmd}" -q " ${uplink} "; then
464 ban_uplink
="${ban_uplink}${uplink} "
467 for ip
in ${ban_uplink}; do
468 if ! "${ban_grepcmd}" -q "${ip} " "${ban_allowlist}"; then
469 if [ "${update}" = "0" ]; then
470 "${ban_sedcmd}" -i "/# uplink added on /d" "${ban_allowlist}"
472 printf "%-42s%s\n" "${ip}" "# uplink added on $(date "+%Y-
%m-
%d
%H
:%M
:%S
")" >>"${ban_allowlist}"
473 f_log
"info" "add uplink '${ip}' to local allowlist"
477 ban_uplink
="${ban_uplink%%?}"
478 elif [ "${ban_autoallowlist}" = "1" ] && [ "${ban_autoallowuplink}" = "disable" ]; then
479 "${ban_sedcmd}" -i "/# uplink added on /d" "${ban_allowlist}"
483 f_log
"debug" "f_getuplink ::: auto/update: ${ban_autoallowlist}/${update}, uplink: ${ban_uplink:-"-"}"
486 # get feed information
490 if [ -s "${ban_customfeedfile}" ]; then
491 if json_load_file
"${ban_customfeedfile}" >/dev
/null
2>&1; then
494 f_log
"info" "can't load banIP custom feed file"
497 if [ -s "${ban_feedfile}" ] && json_load_file
"${ban_feedfile}" >/dev
/null
2>&1; then
500 f_log
"err" "can't load banIP feed file"
509 [ -s "${file}" ] && printf "%s" "elements={ $("${ban_catcmd}" "${file}" 2>/dev/null) };"
512 # handle etag http header
515 local http_head http_code etag_id etag_rc out_rc
="4" feed
="${1}" feed_url="${2}" feed_suffix="${3}"
517 if [ -n "${ban_etagparm}" ]; then
518 [ ! -f "${ban_backupdir}/banIP.etag" ] && : >"${ban_backupdir}/banIP.etag"
519 http_head
="$("${ban_fetchcmd}" ${ban_etagparm} "${feed_url}" 2>&1)"
520 http_code
="$(printf "%s
" "${http_head}" | "${ban_awkcmd}" 'tolower($0)~/^http\/[0123\.]+ /{printf "%s",$2}')"
521 etag_id="$(printf "%s" "${http_head}" | "${ban_awkcmd}" 'tolower($0)~/^[[:space:]]*etag: /{gsub("\"","");printf "%s",$2}')"
524 if [ "${http_code}" = "404" ] || { [ "${etag_rc}" = "0" ] && [ -n "${etag_id}" ] && "${ban_grepcmd}" -q "^${feed}${feed_suffix}[[:space:]]\+${etag_id}\$" "${ban_backupdir}/banIP.etag"; }; then
526 elif [ "${etag_rc}" = "0" ] && [ -n "${etag_id}" ] && ! "${ban_grepcmd}" -q "^${feed}${feed_suffix}[[:space:]]\+${etag_id}\$" "${ban_backupdir}/banIP.etag"; then
527 "${ban_sedcmd}" -i "/^${feed}${feed_suffix}/d" "${ban_backupdir}/banIP.etag"
528 printf "%-20s%s\n" "${feed}${feed_suffix}" "${etag_id}" >>"${ban_backupdir}/banIP.etag"
533 f_log
"debug" "f_etag ::: feed: ${feed}, suffix: ${feed_suffix:-"-"}, http_code: ${http_code:-"-"}, etag_id: ${etag_id:-"-"} , etag_rc: ${etag_rc:-"-"}, rc: ${out_rc}"
537 # build initial nft file with base table, chains and rules
540 local wan_dev vlan_allow vlan_block feed_log feed_rc
file="${1}"
542 wan_dev
="$(printf "%s
" "${ban_dev}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
543 [ -n "${ban_vlanallow}" ] && vlan_allow="$(printf "%s" "${ban_vlanallow%%?}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
544 [ -n "${ban_vlanblock}" ] && vlan_block="$(printf "%s" "${ban_vlanblock%%?}" | "${ban_sedcmd}" 's/^/\"/;s/$/\"/;s/ /\", \"/g')"
547 # nft header (tables and chains)
549 printf "%s\n\n" "#!/usr/sbin/nft -f"
550 if "${ban_nftcmd}" -t list
set inet banIP allowlistv4MAC
>/dev
/null
2>&1; then
551 printf "%s\n" "delete table inet banIP"
553 printf "%s\n" "add table inet banIP"
554 printf "%s\n" "add chain inet banIP wan-input { type filter hook input priority ${ban_nftpriority}; policy accept; }"
555 printf "%s\n" "add chain inet banIP wan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }"
556 printf "%s\n" "add chain inet banIP lan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }"
557 printf "%s\n" "add chain inet banIP reject-chain"
559 # default reject rules
561 printf "%s\n" "add rule inet banIP reject-chain meta l4proto tcp reject with tcp reset"
562 printf "%s\n" "add rule inet banIP reject-chain reject"
564 # default wan-input rules
566 printf "%s\n" "add rule inet banIP wan-input ct state established,related counter accept"
567 printf "%s\n" "add rule inet banIP wan-input iifname != { ${wan_dev} } counter accept"
568 printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv4 udp sport 67-68 udp dport 67-68 counter accept"
569 printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 udp sport 547 udp dport 546 counter accept"
570 printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv4 icmp type { echo-request } limit rate 1000/second counter accept"
571 printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { echo-request } limit rate 1000/second counter accept"
572 printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert} limit rate 1000/second ip6 hoplimit 1 counter accept"
573 printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert} limit rate 1000/second ip6 hoplimit 255 counter accept"
575 # default wan-forward rules
577 printf "%s\n" "add rule inet banIP wan-forward ct state established,related counter accept"
578 printf "%s\n" "add rule inet banIP wan-forward iifname != { ${wan_dev} } counter accept"
580 # default lan-forward rules
582 printf "%s\n" "add rule inet banIP lan-forward ct state established,related counter accept"
583 printf "%s\n" "add rule inet banIP lan-forward oifname != { ${wan_dev} } counter accept"
584 [ -n "${vlan_allow}" ] && printf "%s\n" "add rule inet banIP lan-forward iifname { ${vlan_allow} } counter accept"
585 [ -n "${vlan_block}" ] && printf "%s\n" "add rule inet banIP lan-forward iifname { ${vlan_block} } counter goto reject-chain"
588 # load initial banIP table within nft (atomic load)
590 feed_log
="$("${ban_nftcmd}" -f "${file}" 2>&1)"
593 f_log
"debug" "f_nftinit ::: wan_dev: ${wan_dev}, vlan_allow: ${vlan_allow:-"-"}, vlan_block: ${vlan_block:-"-"}, priority: ${ban_nftpriority}, policy: ${ban_nftpolicy}, loglevel: ${ban_nftloglevel}, rc: ${feed_rc:-"-"}, log: ${feed_log:-"-"}"
600 local log_input log_forwardwan log_forwardlan start_ts end_ts tmp_raw tmp_load tmp_file split_file ruleset_raw handle rc etag_rc
601 local cnt_set cnt_dl restore_rc feed_direction feed_rc feed_log feed
="${1}" proto="${2}" feed_url="${3}" feed_rule="${4}" feed_flag="${5}"
603 start_ts
="$(date +%s)"
604 feed
="${feed}v${proto}"
605 tmp_load
="${ban_tmpfile}.${feed}.load"
606 tmp_raw
="${ban_tmpfile}.${feed}.raw"
607 tmp_split
="${ban_tmpfile}.${feed}.split"
608 tmp_file
="${ban_tmpfile}.${feed}.file"
609 tmp_flush
="${ban_tmpfile}.${feed}.flush"
610 tmp_nft
="${ban_tmpfile}.${feed}.nft"
611 tmp_allow
="${ban_tmpfile}.${feed%v*}"
613 [ "${ban_loginput}" = "1" ] && log_input="log level ${ban_nftloglevel} prefix \"banIP/inp-wan/${ban_blocktype}/${feed}: \""
614 [ "${ban_logforwardwan}" = "1" ] && log_forwardwan="log level ${ban_nftloglevel} prefix \"banIP/fwd-wan/${ban_blocktype}/${feed}: \""
615 [ "${ban_logforwardlan}" = "1" ] && log_forwardlan="log level ${ban_nftloglevel} prefix \"banIP/fwd-lan/reject/${feed}: \""
617 # set feed block direction
619 if [ "${ban_blockpolicy}" = "input" ]; then
620 if ! printf "%s" "${ban_blockinput}" | "${ban_grepcmd}" -q "${feed%v*}" &&
621 ! printf "%s" "${ban_blockforwardwan}" | "${ban_grepcmd}" -q "${feed%v*}" &&
622 ! printf "%s" "${ban_blockforwardlan}" | "${ban_grepcmd}" -q "${feed%v*}"; then
623 ban_blockinput
="${ban_blockinput} ${feed%v*}"
625 elif [ "${ban_blockpolicy}" = "forwardwan" ]; then
626 if ! printf "%s" "${ban_blockinput}" | "${ban_grepcmd}" -q "${feed%v*}" &&
627 ! printf "%s" "${ban_blockforwardwan}" | "${ban_grepcmd}" -q "${feed%v*}" &&
628 ! printf "%s" "${ban_blockforwardlan}" | "${ban_grepcmd}" -q "${feed%v*}"; then
629 ban_blockforwardwan
="${ban_blockforwardwan} ${feed%v*}"
631 elif [ "${ban_blockpolicy}" = "forwardlan" ]; then
632 if ! printf "%s" "${ban_blockinput}" | "${ban_grepcmd}" -q "${feed%v*}" &&
633 ! printf "%s" "${ban_blockforwardwan}" | "${ban_grepcmd}" -q "${feed%v*}" &&
634 ! printf "%s" "${ban_blockforwardlan}" | "${ban_grepcmd}" -q "${feed%v*}"; then
635 ban_blockforwardlan
="${ban_blockforwardlan} ${feed%v*}"
638 if printf "%s" "${ban_blockinput}" | "${ban_grepcmd}" -q "${feed%v*}"; then
639 feed_direction
="input"
641 if printf "%s" "${ban_blockforwardwan}" | "${ban_grepcmd}" -q "${feed%v*}"; then
642 feed_direction
="${feed_direction} forwardwan"
644 if printf "%s" "${ban_blockforwardlan}" | "${ban_grepcmd}" -q "${feed%v*}"; then
645 feed_direction
="${feed_direction} forwardlan"
648 # chain/rule maintenance
650 if [ "${ban_action}" = "reload" ] && "${ban_nftcmd}" -t list set inet banIP "${feed}" >/dev
/null
2>&1; then
651 ruleset_raw
="$("${ban_nftcmd}" -tj list ruleset 2>/dev/null)"
653 printf "%s\n" "flush set inet banIP ${feed}"
654 handle
="$(printf "%s
\n" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"wan-input\"][@.expr[0].match.right=\"@${feed}\"].handle
")"
655 [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP wan-input handle ${handle}"
656 handle
="$(printf "%s
\n" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"wan-forward\"][@.expr[0].match.right=\"@${feed}\"].handle
")"
657 [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP wan-forward handle ${handle}"
658 handle
="$(printf "%s
\n" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"lan-forward\"][@.expr[0].match.right=\"@${feed}\"].handle
")"
659 [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP lan-forward handle ${handle}"
663 # restore local backups
665 if { [ "${ban_action}" != "reload" ] || [ "${feed_url}" = "local" ] || [ -n "${ban_etagparm}" ]; } && [ "${feed%v*}" != "allowlist" ] && [ "${feed%v*}" != "blocklist" ]; then
666 if [ -n "${ban_etagparm}" ] && [ "${ban_action}" = "reload" ] && [ "${feed_url}" != "local" ]; then
668 if [ "${feed%v*}" = "country" ]; then
669 for country
in ${ban_country}; do
670 f_etag
"${feed}" "${feed_url}${country}-aggregated.zone" ".${country}"
672 [ "${rc}" = "4" ] && break
673 etag_rc
="$((etag_rc + rc))"
675 elif [ "${feed%v*}" = "asn" ]; then
676 for asn
in ${ban_asn}; do
677 f_etag
"${feed}" "${feed_url}AS${asn}" ".{asn}"
679 [ "${rc}" = "4" ] && break
680 etag_rc
="$((etag_rc + rc))"
683 f_etag
"${feed}" "${feed_url}"
687 if [ "${etag_rc}" = "0" ] || [ "${ban_action}" != "reload" ] || [ "${feed_url}" = "local" ]; then
688 f_restore
"${feed}" "${feed_url}" "${tmp_load}" "${etag_rc}"
690 feed_rc
="${restore_rc}"
694 # prepare local allowlist
696 if [ "${feed%v*}" = "allowlist" ] && [ ! -f "${tmp_allow}" ]; then
697 "${ban_catcmd}" "${ban_allowlist}" 2>/dev/null >"${tmp_allow}"
698 for feed_url
in ${ban_allowurl}; do
699 feed_log
="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_load}" "${feed_url}" 2>&1)"
701 if [ "${feed_rc}" = "0" ] && [ -s "${tmp_load}" ]; then
702 "${ban_catcmd}" "${tmp_load}" 2>/dev/null >>"${tmp_allow}"
704 f_log
"info" "download for feed '${feed%v*}' failed (rc: ${feed_rc:-"-"}/log: ${feed_log})"
711 if [ "${feed%v*}" = "allowlist" ]; then
713 printf "%s\n\n" "#!/usr/sbin/nft -f"
714 [ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
715 if [ "${proto}" = "4MAC" ]; then
716 "${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}(\/([0-9]|[1-3][0-9]|4[0-8]))?([[:space:]]+([0-9]{1,3}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?[[:space:]]*$|[[:space:]]+$|$)/{if(!$2)$2="0.0.0.0/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${tmp_allow}" >"${tmp_file}"
717 printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}") }"
718 [ -z "${feed_direction##*forwardlan*}" ] && printf "%s\n" "add rule inet banIP lan-forward ether saddr . ip saddr @${feed} counter accept"
719 elif [ "${proto}" = "6MAC" ]; then
720 "${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:]]+$|$)/{if(!$2)$2="::/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${tmp_allow}" >"${tmp_file}"
721 printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}") }"
722 [ -z "${feed_direction##*forwardlan*}" ] && printf "%s\n" "add rule inet banIP lan-forward ether saddr . ip6 saddr @${feed} counter accept"
723 elif [ "${proto}" = "4" ]; then
724 "${ban_awkcmd}" '/^(([0-9]{1,3}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]].*|$)/{printf "%s, ",$1}' "${tmp_allow}" >"${tmp_file}"
725 printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}") }"
726 if [ -z "${feed_direction##*input*}" ]; then
727 if [ "${ban_allowlistonly}" = "1" ]; then
728 if [ "${ban_blocktype}" = "reject" ]; then
729 printf "%s\n" "add rule inet banIP wan-input ip saddr != @${feed} ${log_input} counter goto reject-chain"
731 printf "%s\n" "add rule inet banIP wan-input ip saddr != @${feed} ${log_input} counter drop"
734 printf "%s\n" "add rule inet banIP wan-input ip saddr @${feed} counter accept"
737 if [ -z "${feed_direction##*forwardwan*}" ]; then
738 if [ "${ban_allowlistonly}" = "1" ]; then
739 if [ "${ban_blocktype}" = "reject" ]; then
740 printf "%s\n" "add rule inet banIP wan-forward ip saddr != @${feed} ${log_forwardwan} counter goto reject-chain"
742 printf "%s\n" "add rule inet banIP wan-forward ip saddr != @${feed} ${log_forwardwan} counter drop"
745 printf "%s\n" "add rule inet banIP wan-forward ip saddr @${feed} counter accept"
748 if [ -z "${feed_direction##*forwardlan*}" ]; then
749 if [ "${ban_allowlistonly}" = "1" ]; then
750 printf "%s\n" "add rule inet banIP lan-forward ip daddr != @${feed} ${log_forwardlan} counter goto reject-chain"
752 printf "%s\n" "add rule inet banIP lan-forward ip daddr @${feed} counter accept"
755 elif [ "${proto}" = "6" ]; then
756 "${ban_awkcmd}" '!/^([0-9A-f]{2}:){5}[0-9A-f]{2}.*/{printf "%s\n",$1}' "${tmp_allow}" |
757 "${ban_awkcmd}" '/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]].*|$)/{printf "%s, ",tolower($1)}' >"${tmp_file}"
758 printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}") }"
759 if [ -z "${feed_direction##*input*}" ]; then
760 if [ "${ban_allowlistonly}" = "1" ]; then
761 if [ "${ban_blocktype}" = "reject" ]; then
762 printf "%s\n" "add rule inet banIP wan-input ip6 saddr != @${feed} ${log_input} counter goto reject-chain"
764 printf "%s\n" "add rule inet banIP wan-input ip6 saddr != @${feed} ${log_input} counter drop"
767 printf "%s\n" "add rule inet banIP wan-input ip6 saddr @${feed} counter accept"
770 if [ -z "${feed_direction##*forwardwan*}" ]; then
771 if [ "${ban_allowlistonly}" = "1" ]; then
772 if [ "${ban_blocktype}" = "reject" ]; then
773 printf "%s\n" "add rule inet banIP wan-forward ip6 saddr != @${feed} ${log_forwardwan} counter goto reject-chain"
775 printf "%s\n" "add rule inet banIP wan-forward ip6 saddr != @${feed} ${log_forwardwan} counter drop"
778 printf "%s\n" "add rule inet banIP wan-forward ip6 saddr @${feed} counter accept"
781 if [ -z "${feed_direction##*forwardlan*}" ]; then
782 if [ "${ban_allowlistonly}" = "1" ]; then
783 printf "%s\n" "add rule inet banIP lan-forward ip6 daddr != @${feed} ${log_forwardlan} counter goto reject-chain"
785 printf "%s\n" "add rule inet banIP lan-forward ip6 daddr @${feed} counter accept"
791 elif [ "${feed%v*}" = "blocklist" ]; then
793 printf "%s\n\n" "#!/usr/sbin/nft -f"
794 [ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
795 if [ "${proto}" = "4MAC" ]; then
796 "${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}(\/([0-9]|[1-3][0-9]|4[0-8]))?([[:space:]]+([0-9]{1,3}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?[[:space:]]*$|[[:space:]]+$|$)/{if(!$2)$2="0.0.0.0/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${ban_blocklist}" >"${tmp_file}"
797 printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}") }"
798 [ -z "${feed_direction##*forwardlan*}" ] && printf "%s\n" "add rule inet banIP lan-forward ether saddr . ip saddr @${feed} counter goto reject-chain"
799 elif [ "${proto}" = "6MAC" ]; then
800 "${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:]]+$|$)/{if(!$2)$2="::/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${ban_blocklist}" >"${tmp_file}"
801 printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}") }"
802 [ -z "${feed_direction##*forwardlan*}" ] && printf "%s\n" "add rule inet banIP lan-forward ether saddr . ip6 saddr @${feed} counter goto reject-chain"
803 elif [ "${proto}" = "4" ]; then
804 if [ "${ban_deduplicate}" = "1" ]; then
805 "${ban_awkcmd}" '/^(([0-9]{1,3}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]].*|$)/{printf "%s,\n",$1}' "${ban_blocklist}" >"${tmp_raw}"
806 "${ban_awkcmd}" 'NR==FNR{member[$0];next}!($0 in member)' "${ban_tmpfile}.deduplicate" "${tmp_raw}" 2>/dev/null >"${tmp_split}"
807 "${ban_awkcmd}" 'BEGIN{FS="[ ,]"}NR==FNR{member[$1];next}!($1 in member)' "${ban_tmpfile}.deduplicate" "${ban_blocklist}" 2>/dev/null >"${tmp_raw}"
808 "${ban_catcmd}" "${tmp_raw}" 2>/dev/null >"${ban_blocklist}"
810 "${ban_awkcmd}" '/^(([0-9]{1,3}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]].*|$)/{printf "%s,\n",$1}' "${ban_blocklist}" >"${tmp_split}"
812 "${ban_awkcmd}" '{ORS=" ";print}' "${tmp_split}" 2>/dev/null >"${tmp_file}"
813 printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval, timeout; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}") }"
814 if [ "${ban_blocktype}" = "reject" ]; then
815 [ -z "${feed_direction##*input*}" ] && printf "%s\n" "add rule inet banIP wan-input ip saddr @${feed} ${log_input} counter goto reject-chain"
816 [ -z "${feed_direction##*forwardwan*}" ] && printf "%s\n" "add rule inet banIP wan-forward ip saddr @${feed} ${log_forwardwan} counter goto reject-chain"
818 [ -z "${feed_direction##*input*}" ] && printf "%s\n" "add rule inet banIP wan-input ip saddr @${feed} ${log_input} counter drop"
819 [ -z "${feed_direction##*forwardwan*}" ] && printf "%s\n" "add rule inet banIP wan-forward ip saddr @${feed} ${log_forwardwan} counter drop"
821 [ -z "${feed_direction##*forwardlan*}" ] && printf "%s\n" "add rule inet banIP lan-forward ip daddr @${feed} ${log_forwardlan} counter goto reject-chain"
822 elif [ "${proto}" = "6" ]; then
823 if [ "${ban_deduplicate}" = "1" ]; then
824 "${ban_awkcmd}" '!/^([0-9A-f]{2}:){5}[0-9A-f]{2}.*/{printf "%s\n",$1}' "${ban_blocklist}" |
825 "${ban_awkcmd}" '/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]].*|$)/{printf "%s,\n",tolower($1)}' >"${tmp_raw}"
826 "${ban_awkcmd}" 'NR==FNR{member[$0];next}!($0 in member)' "${ban_tmpfile}.deduplicate" "${tmp_raw}" 2>/dev/null >"${tmp_split}"
827 "${ban_awkcmd}" 'BEGIN{FS="[ ,]"}NR==FNR{member[$1];next}!($1 in member)' "${ban_tmpfile}.deduplicate" "${ban_blocklist}" 2>/dev/null >"${tmp_raw}"
828 "${ban_catcmd}" "${tmp_raw}" 2>/dev/null >"${ban_blocklist}"
830 "${ban_awkcmd}" '!/^([0-9A-f]{2}:){5}[0-9A-f]{2}.*/{printf "%s\n",$1}' "${ban_blocklist}" |
831 "${ban_awkcmd}" '/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]].*|$)/{printf "%s,\n",tolower($1)}' >"${tmp_split}"
833 "${ban_awkcmd}" '{ORS=" ";print}' "${tmp_split}" 2>/dev/null >"${tmp_file}"
834 printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval, timeout; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}") }"
835 if [ "${ban_blocktype}" = "reject" ]; then
836 [ -z "${feed_direction##*input*}" ] && printf "%s\n" "add rule inet banIP wan-input ip6 saddr @${feed} ${log_input} counter goto reject-chain"
837 [ -z "${feed_direction##*forwardwan*}" ] && printf "%s\n" "add rule inet banIP wan-forward ip6 saddr @${feed} ${log_forwardwan} counter goto reject-chain"
839 [ -z "${feed_direction##*input*}" ] && printf "%s\n" "add rule inet banIP wan-input ip6 saddr @${feed} ${log_input} counter drop"
840 [ -z "${feed_direction##*forwardwan*}" ] && printf "%s\n" "add rule inet banIP wan-forward ip6 saddr @${feed} ${log_forwardwan} counter drop"
842 [ -z "${feed_direction##*forwardlan*}" ] && printf "%s\n" "add rule inet banIP lan-forward ip6 daddr @${feed} ${log_forwardlan} counter goto reject-chain"
847 # handle external feeds
849 elif [ "${restore_rc}" != "0" ] && [ "${feed_url}" != "local" ]; then
850 # handle country downloads
852 if [ "${feed%v*}" = "country" ]; then
853 for country
in ${ban_country}; do
854 feed_log
="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_raw}" "${feed_url}${country}-aggregated.zone
" 2>&1)"
856 [ "${feed_rc}" = "0" ] && "${ban_catcmd}" "${tmp_raw}" 2>/dev/null >>"${tmp_load}"
860 # handle asn downloads
862 elif [ "${feed%v*}" = "asn" ]; then
863 for asn
in ${ban_asn}; do
864 feed_log
="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_raw}" "${feed_url}AS${asn}" 2>&1)"
866 [ "${feed_rc}" = "0" ] && "${ban_catcmd}" "${tmp_raw}" 2>/dev/null >>"${tmp_load}"
870 # handle compressed downloads
872 elif [ -n "${feed_flag}" ]; then
873 case "${feed_flag}" in
875 feed_log
="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_raw}" "${feed_url}" 2>&1)"
877 [ "${feed_rc}" = "0" ] && "${ban_zcatcmd}" "${tmp_raw}" 2>/dev/null >"${tmp_load}"
882 # handle normal downloads
885 feed_log
="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_load}" "${feed_url}" 2>&1)"
889 [ "${feed_rc}" != "0" ] && f_log "info" "download for feed '${feed}' failed (rc: ${feed_rc:-"-"}/log: ${feed_log})"
893 if [ "${restore_rc}" != "0" ] && [ "${feed_rc}" = "0" ] && [ "${feed_url}" != "local" ] && [ ! -s "${tmp_nft}" ]; then
894 f_backup
"${feed}" "${tmp_load}"
896 elif [ -z "${restore_rc}" ] && [ "${feed_rc}" != "0" ] && [ "${feed_url}" != "local" ] && [ ! -s "${tmp_nft}" ]; then
897 f_restore
"${feed}" "${feed_url}" "${tmp_load}" "${feed_rc}"
901 # build nft file with Sets and rules for regular downloads
903 if [ "${feed_rc}" = "0" ] && [ ! -s "${tmp_nft}" ]; then
906 if [ "${ban_deduplicate}" = "1" ] && [ "${feed_url}" != "local" ]; then
907 "${ban_awkcmd}" "${feed_rule}" "${tmp_load}" 2>/dev/null >"${tmp_raw}"
908 "${ban_awkcmd}" 'NR==FNR{member[$0];next}!($0 in member)' "${ban_tmpfile}.deduplicate" "${tmp_raw}" 2>/dev/null | tee -a "${ban_tmpfile}.deduplicate" >"${tmp_split}"
910 "${ban_awkcmd}" "${feed_rule}" "${tmp_load}" 2>/dev/null >"${tmp_split}"
915 if [ "${feed_rc}" = "0" ]; then
916 if [ -n "${ban_splitsize//[![:digit]]/}" ] && [ "${ban_splitsize//[![:digit]]/}" -gt "0" ]; then
917 if ! "${ban_awkcmd}" "NR%${ban_splitsize//[![:digit]]/}==1{file=\"${tmp_file}.\"++i;}{ORS=\" \";print > file}" "${tmp_split}" 2>/dev
/null
; then
918 rm -f "${tmp_file}".
*
919 f_log
"info" "can't split Set '${feed}' to size '${ban_splitsize//[![:digit]]/}'"
922 "${ban_awkcmd}" '{ORS=" ";print}' "${tmp_split}" 2>/dev/null >"${tmp_file}.1"
926 rm -f "${tmp_raw}" "${tmp_load}"
927 if [ "${feed_rc}" = "0" ] && [ "${proto}" = "4" ]; then
929 # nft header (IPv4 Set)
931 printf "%s\n\n" "#!/usr/sbin/nft -f"
932 [ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
933 printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}.1") }"
935 # input and forward rules
937 if [ "${ban_blocktype}" = "reject" ]; then
938 [ -z "${feed_direction##*input*}" ] && printf "%s\n" "add rule inet banIP wan-input ip saddr @${feed} ${log_input} counter goto reject-chain"
939 [ -z "${feed_direction##*forwardwan*}" ] && printf "%s\n" "add rule inet banIP wan-forward ip saddr @${feed} ${log_forwardwan} counter goto reject-chain"
941 [ -z "${feed_direction##*input*}" ] && printf "%s\n" "add rule inet banIP wan-input ip saddr @${feed} ${log_input} counter drop"
942 [ -z "${feed_direction##*forwardwan*}" ] && printf "%s\n" "add rule inet banIP wan-forward ip saddr @${feed} ${log_forwardwan} counter drop"
944 [ -z "${feed_direction##*forwardlan*}" ] && printf "%s\n" "add rule inet banIP lan-forward ip daddr @${feed} ${log_forwardlan} counter goto reject-chain"
946 elif [ "${feed_rc}" = "0" ] && [ "${proto}" = "6" ]; then
948 # nft header (IPv6 Set)
950 printf "%s\n\n" "#!/usr/sbin/nft -f"
951 [ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
952 printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; $(f_getelements "${tmp_file}.1") }"
954 # input and forward rules
956 if [ "${ban_blocktype}" = "reject" ]; then
957 [ -z "${feed_direction##*input*}" ] && printf "%s\n" "add rule inet banIP wan-input ip6 saddr @${feed} ${log_input} counter goto reject-chain"
958 [ -z "${feed_direction##*forwardwan*}" ] && printf "%s\n" "add rule inet banIP wan-forward ip6 saddr @${feed} ${log_forwardwan} counter goto reject-chain"
960 [ -z "${feed_direction##*input*}" ] && printf "%s\n" "add rule inet banIP wan-input ip6 saddr @${feed} ${log_input} counter drop"
961 [ -z "${feed_direction##*forwardwan*}" ] && printf "%s\n" "add rule inet banIP wan-forward ip6 saddr @${feed} ${log_forwardwan} counter drop"
963 [ -z "${feed_direction##*forwardlan*}" ] && printf "%s\n" "add rule inet banIP lan-forward ip6 daddr @${feed} ${log_forwardlan} counter goto reject-chain"
968 # load generated nft file in banIP table
970 if [ "${feed_rc}" = "0" ]; then
971 cnt_dl
="$("${ban_awkcmd}" 'END{printf "%d
",NR}' "${tmp_split}" 2>/dev/null)"
972 if [ "${cnt_dl:-"0"}" -gt "0" ] || [ "${feed_url}" = "local" ] || [ "${feed%v*}" = "allowlist" ] || [ "${feed%v*}" = "blocklist" ]; then
973 feed_log
="$("${ban_nftcmd}" -f "${tmp_nft}" 2>&1)"
976 # load additional split files
978 if [ "${feed_rc}" = "0" ]; then
979 for split_file
in "${tmp_file}".
*; do
980 [ ! -f "${split_file}" ] && break
981 if [ "${split_file##*.}" = "1" ]; then
982 rm -f "${split_file}"
985 if ! "${ban_nftcmd}" add element inet banIP "${feed}" "{ $("${ban_catcmd}" "${split_file}") }" >/dev
/null
2>&1; then
986 f_log
"info" "can't add split file '${split_file##*.}' to Set '${feed}'"
988 rm -f "${split_file}"
990 if [ "${ban_debug}" = "1" ] && [ "${ban_reportelements}" = "1" ]; then
991 cnt_set
="$("${ban_nftcmd}" -j list set inet banIP "${feed}" 2>/dev/null | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*]' | wc -l 2>/dev/null)"
995 f_log
"info" "skip empty feed '${feed}'"
998 rm -f "${tmp_split}" "${tmp_nft}"
1001 f_log
"debug" "f_down ::: feed: ${feed}, cnt_dl: ${cnt_dl:-"-"}, cnt_set: ${cnt_set:-"-"}, split_size: ${ban_splitsize:-"-"}, time: $((end_ts - start_ts)), rc: ${feed_rc:-"-"}, log: ${feed_log:-"-"}"
1007 local backup_rc
="4" feed
="${1}" feed_file
="${2}"
1009 if [ -s "${feed_file}" ]; then
1010 gzip -cf "${feed_file}" >"${ban_backupdir}/banIP.${feed}.gz"
1014 f_log
"debug" "f_backup ::: feed: ${feed}, file: banIP.${feed}.gz, rc: ${backup_rc}"
1015 return "${backup_rc}"
1021 local tmp_feed restore_rc
="4" feed
="${1}" feed_url="${2}" feed_file="${3}" in_rc="${4}"
1023 [ "${feed_url}" = "local" ] && tmp_feed="${feed%v*}v4" || tmp_feed="${feed}"
1024 if [ -s "${ban_backupdir}/banIP.${tmp_feed}.gz" ]; then
1025 "${ban_zcatcmd}" "${ban_backupdir}/banIP.${tmp_feed}.gz" 2>/dev/null >"${feed_file}"
1029 f_log
"debug" "f_restore ::: feed: ${feed}, file: banIP.${tmp_feed}.gz, in_rc: ${in_rc:-"-"}, rc: ${restore_rc}"
1030 return "${restore_rc}"
1033 # remove disabled Sets
1036 local feedlist tmp_del ruleset_raw item table_sets handle del_set feed_log feed_rc
1039 json_get_keys feedlist
1040 tmp_del
="${ban_tmpfile}.final.delete"
1041 ruleset_raw
="$("${ban_nftcmd}" -tj list ruleset 2>/dev/null)"
1042 table_sets
="$(printf "%s
\n" "${ruleset_raw}" | "${ban_jsoncmd}" -qe '@.nftables[@.set.table="banIP
"].set.name')"
1044 printf "%s\n\n" "#!/usr/sbin/nft -f"
1045 for item
in ${table_sets}; do
1046 if ! printf "%s" "allowlist blocklist ${ban_feed}" | "${ban_grepcmd}" -q "${item%v*}" ||
1047 ! printf "%s" "allowlist blocklist ${feedlist}" | "${ban_grepcmd}" -q "${item%v*}"; then
1048 del_set
="${del_set}${item}, "
1049 rm -f "${ban_backupdir}/banIP.${item}.gz"
1050 printf "%s\n" "flush set inet banIP ${item}"
1051 handle
="$(printf "%s
\n" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"wan-input\"][@.expr[0].match.right=\"@${item}\"].handle
")"
1052 [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP wan-input handle ${handle}"
1053 handle
="$(printf "%s
\n" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"wan-forward\"][@.expr[0].match.right=\"@${item}\"].handle
")"
1054 [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP wan-forward handle ${handle}"
1055 handle
="$(printf "%s
\n" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"lan-forward\"][@.expr[0].match.right=\"@${item}\"].handle
")"
1056 [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP lan-forward handle ${handle}"
1057 printf "%s\n\n" "delete set inet banIP ${item}"
1062 if [ -n "${del_set}" ]; then
1063 del_set
="${del_set%%??}"
1064 feed_log
="$("${ban_nftcmd}" -f "${tmp_del}" 2>&1)"
1069 f_log
"debug" "f_rmset ::: sets: ${del_set:-"-"}, rc: ${feed_rc:-"-"}, log: ${feed_log:-"-"}"
1072 # generate status information
1075 local object end_time duration table_sets cnt_elements
="0" custom_feed
="0" split="0" status
="${1}"
1077 [ -z "${ban_dev}" ] && f_conf
1078 if [ "${status}" = "active" ]; then
1079 if [ -n "${ban_starttime}" ] && [ "${ban_action}" != "boot" ]; then
1080 end_time
="$(date "+%s
")"
1081 duration
="$(((end_time - ban_starttime) / 60))m $(((end_time - ban_starttime) % 60))s"
1083 table_sets
="$("${ban_nftcmd}" -tj list ruleset 2>/dev/null | "${ban_jsoncmd}" -qe '@.nftables[@.set.table="banIP
"].set.name')"
1084 if [ "${ban_reportelements}" = "1" ]; then
1085 for object
in ${table_sets}; do
1086 cnt_elements
="$((cnt_elements + $("${ban_nftcmd}" -j list set inet banIP "${object}" 2>/dev/null | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*]' | wc -l 2>/dev/null)))"
1089 runtime
="action: ${ban_action:-"-"}, fetch: ${ban_fetchcmd##*/}, duration: ${duration:-"-"}, date: $(date "+%Y-
%m-
%d
%H
:%M
:%S
")"
1091 [ -s "${ban_customfeedfile}" ] && custom_feed
="1"
1092 [ "${ban_splitsize:-"0"}" -gt "0" ] && split="1"
1096 json_load_file
"${ban_rtfile}" >/dev
/null
2>&1
1097 json_add_string
"status" "${status}"
1098 json_add_string
"version" "${ban_ver}"
1099 json_add_string
"element_count" "${cnt_elements}"
1100 json_add_array
"active_feeds"
1101 for object
in ${table_sets:-"-"}; do
1102 json_add_string
"${object}" "${object}"
1105 json_add_array
"wan_devices"
1106 for object
in ${ban_dev:-"-"}; do
1107 json_add_string
"${object}" "${object}"
1110 json_add_array
"wan_interfaces"
1111 for object
in ${ban_ifv4:-"-"} ${ban_ifv6:-"-"}; do
1112 json_add_string
"${object}" "${object}"
1115 json_add_array
"vlan_allow"
1116 for object
in ${ban_vlanallow:-"-"}; do
1117 json_add_string
"${object}" "${object}"
1120 json_add_array
"vlan_block"
1121 for object
in ${ban_vlanblock:-"-"}; do
1122 json_add_string
"${object}" "${object}"
1125 json_add_array
"active_uplink"
1126 for object
in ${ban_uplink:-"-"}; do
1127 json_add_string
"${object}" "${object}"
1130 json_add_string
"nft_info" "priority: ${ban_nftpriority}, policy: ${ban_nftpolicy}, loglevel: ${ban_nftloglevel}, expiry: ${ban_nftexpiry:-"-"}"
1131 json_add_string
"run_info" "base: ${ban_basedir}, backup: ${ban_backupdir}, report: ${ban_reportdir}"
1132 json_add_string
"run_flags" "auto: $(f_char ${ban_autodetect}), proto (4/6): $(f_char ${ban_protov4})/$(f_char ${ban_protov6}), log (wan-inp/wan-fwd/lan-fwd): $(f_char ${ban_loginput})/$(f_char ${ban_logforwardwan})/$(f_char ${ban_logforwardlan}), dedup: $(f_char ${ban_deduplicate}), split: $(f_char ${split}), custom feed: $(f_char ${custom_feed}), allowed only: $(f_char ${ban_allowlistonly})"
1133 json_add_string
"last_run" "${runtime:-"-"}"
1134 json_add_string
"system_info" "cores: ${ban_cores}, memory: ${ban_memory}, device: ${ban_sysver}"
1135 json_dump
>"${ban_rtfile}"
1138 # get status information
1141 local key keylist value values
1143 [ -z "${ban_dev}" ] && f_conf
1144 json_load_file
"${ban_rtfile}" >/dev
/null
2>&1
1145 if json_get_keys keylist
; then
1146 printf "%s\n" "::: banIP runtime information"
1147 for key
in ${keylist}; do
1148 if [ "${key}" = "active_feeds" ] ||
[ "${key}" = "active_uplink" ]; then
1149 json_get_values values
"${key}" >/dev
/null
2>&1
1150 value
="${values// /, }"
1151 elif [ "${key}" = "wan_devices" ]; then
1152 json_get_values values
"${key}" >/dev
/null
2>&1
1153 value
="wan: ${values// /, } / "
1154 json_get_values values
"wan_interfaces" >/dev
/null
2>&1
1155 value
="${value}wan-if: ${values// /, } / "
1156 json_get_values values
"vlan_allow" >/dev
/null
2>&1
1157 value
="${value}vlan-allow: ${values// /, } / "
1158 json_get_values values
"vlan_block" >/dev
/null
2>&1
1159 value
="${value}vlan-block: ${values// /, }"
1160 key
="active_devices"
1162 json_get_var value
"${key}" >/dev
/null
2>&1
1163 if [ "${key}" = "status" ]; then
1164 value
="${value} ($(f_actual))"
1167 if [ "${key}" != "wan_interfaces" ] && [ "${key}" != "vlan_allow" ] && [ "${key}" != "vlan_block" ]; then
1168 printf " + %-17s : %s\n" "${key}" "${value:-"-"}"
1172 printf "%s\n" "::: no banIP runtime information available"
1179 local cnt list domain lookup ip elementsv4 elementsv6 start_time end_time duration cnt_domain
="0" cnt_ip
="0" feed
="${1}"
1181 [ -z "${ban_dev}" ] && f_conf
1182 start_time
="$(date "+%s
")"
1183 if [ "${feed}" = "allowlist" ]; then
1184 list
="$("${ban_awkcmd}" '/^([[:alnum:]_-]{1,63}\.)+[[:alpha:]]+([[:space:]]|$)/{printf "%s
",tolower($1)}' "${ban_allowlist}" 2>/dev/null)"
1185 elif [ "${feed}" = "blocklist" ]; then
1186 list
="$("${ban_awkcmd}" '/^([[:alnum:]_-]{1,63}\.)+[[:alpha:]]+([[:space:]]|$)/{printf "%s
",tolower($1)}' "${ban_blocklist}" 2>/dev/null)"
1189 for domain
in ${list}; do
1190 lookup
="$("${ban_lookupcmd}" "${domain}" ${ban_resolver} 2>/dev/null | "${ban_awkcmd}" '/^Address[ 0-9]*: /{if(!seen[$NF]++)printf "%s ",$NF}' 2>/dev/null)"
1191 for ip in ${lookup}; do
1192 if [ "${ip%%.*}" = "0" ] || [ -z "${ip%%::*}" ]; then
1195 if { [ "${feed}" = "allowlist" ] && ! "${ban_grepcmd}" -q "^${ip}" "${ban_allowlist}"; } ||
1196 { [ "${feed}" = "blocklist" ] && ! "${ban_grepcmd}" -q "^${ip}" "${ban_blocklist}"; }; then
1197 if [ "${ip##*:}" = "${ip}" ]; then
1198 elementsv4="${elementsv4} ${ip},"
1200 elementsv6="${elementsv6} ${ip},"
1202 if [ "${feed}" = "allowlist" ] && [ "${ban_autoallowlist}" = "1" ]; then
1203 printf "%-42s%s\n" "${ip}" "# '${domain}' added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_allowlist}"
1204 elif [ "${feed}" = "blocklist" ] && [ "${ban_autoblocklist}" = "1" ]; then
1205 printf "%-42s%s\n" "${ip}" "# '${domain}' added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_blocklist}"
1207 cnt_ip="$((cnt_ip + 1))"
1211 cnt_domain="$((cnt_domain + 1))"
1213 if [ -n "${elementsv4}" ]; then
1214 if ! "${ban_nftcmd}" add element inet banIP "${feed}v4" "{ ${elementsv4} }" >/dev/null 2>&1; then
1215 f_log "info" "can't add lookup
file to Set
'${feed}v4'"
1218 if [ -n "${elementsv6}" ]; then
1219 if ! "${ban_nftcmd}" add element inet banIP "${feed}v6" "{ ${elementsv6} }" >/dev/null 2>&1; then
1220 f_log "info
" "can
't add lookup file to Set '${feed}v6
'"
1223 end_time="$(date "+%s")"
1224 duration="$(((end_time - start_time) / 60))m $(((end_time - start_time) % 60))s"
1226 f_log "debug" "f_lookup ::: feed: ${feed}, domains: ${cnt_domain}, IPs: ${cnt_ip}, duration: ${duration}"
1232 local report_jsn report_txt tmp_val ruleset_raw item table_sets set_cnt set_input set_forwardwan set_forwardlan set_cntinput set_cntforwardwan set_cntforwardlan output="${1}"
1233 local detail set_details jsnval timestamp autoadd_allow autoadd_block sum_sets sum_setinput sum_setforwardwan sum_setforwardlan sum_setelements sum_cntinput sum_cntforwardwan sum_cntforwardlan
1235 [ -z "${ban_dev}" ] && f_conf
1236 f_mkdir "${ban_reportdir}"
1237 report_jsn="${ban_reportdir}/ban_report.jsn"
1238 report_txt="${ban_reportdir}/ban_report.txt"
1240 # json output preparation
1242 ruleset_raw="$("${ban_nftcmd}" -tj list ruleset 2>/dev/null)"
1243 table_sets="$(printf "%s" "${ruleset_raw}" | "${ban_jsoncmd}" -qe '@.nftables
[@.
set.table
="banIP"].
set.name
')"
1246 sum_setforwardwan="0"
1247 sum_setforwardlan="0"
1250 sum_cntforwardwan="0"
1251 sum_cntforwardlan="0"
1252 timestamp="$(date "+%Y-%m-%d %H:%M:%S")"
1256 printf "\t%s\n" '"sets":{'
1257 for item in ${table_sets}; do
1258 set_cntinput="$(printf "%s" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"wan-input\"][@.expr[0].match.right=\"@${item}\"].expr[*].counter.packets")"
1259 set_cntforwardwan="$(printf "%s" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"wan-forward\"][@.expr[0].match.right=\"@${item}\"].expr[*].counter.packets")"
1260 set_cntforwardlan="$(printf "%s" "${ruleset_raw}" | "${ban_jsoncmd}" -ql1 -e "@.nftables[@.rule.table=\"banIP\"&&@.rule.chain=\"lan-forward\"][@.expr[0].match.right=\"@${item}\"].expr[*].counter.packets")"
1261 if [ "${ban_reportelements}" = "1" ]; then
1262 set_cnt="$("${ban_nftcmd}" -j list set inet banIP "${item}" 2>/dev/null | "${ban_jsoncmd}" -qe '@.nftables
[*].
set.elem
[*]' | wc -l 2>/dev/null)"
1263 sum_setelements="$((sum_setelements + set_cnt))"
1266 sum_setelements="n/a"
1268 if [ -n "${set_cntinput}" ]; then
1270 sum_setinput="$((sum_setinput + 1))"
1271 sum_cntinput="$((sum_cntinput + set_cntinput))"
1276 if [ -n "${set_cntforwardwan}" ]; then
1278 sum_setforwardwan="$((sum_setforwardwan + 1))"
1279 sum_cntforwardwan="$((sum_cntforwardwan + set_cntforwardwan))"
1282 set_cntforwardwan=""
1284 if [ -n "${set_cntforwardlan}" ]; then
1286 sum_setforwardlan="$((sum_setforwardlan + 1))"
1287 sum_cntforwardlan="$((sum_cntforwardlan + set_cntforwardlan))"
1290 set_cntforwardlan=""
1292 [ "${sum_sets}" -gt "0" ] && printf "%s\n" ","
1293 printf "\t\t%s\n" "\"${item}\":{"
1294 printf "\t\t\t%s\n" "\"cnt_elements\": \"${set_cnt}\","
1295 printf "\t\t\t%s\n" "\"cnt_input\": \"${set_cntinput}\","
1296 printf "\t\t\t%s\n" "\"input\": \"${set_input}\","
1297 printf "\t\t\t%s\n" "\"cnt_forwardwan\": \"${set_cntforwardwan}\","
1298 printf "\t\t\t%s\n" "\"wan_forward\": \"${set_forwardwan}\","
1299 printf "\t\t\t%s\n" "\"cnt_forwardlan\": \"${set_cntforwardlan}\","
1300 printf "\t\t\t%s\n" "\"lan_forward\": \"${set_forwardlan}\""
1302 sum_sets="$((sum_sets + 1))"
1304 printf "\n\t%s\n" "},"
1305 printf "\t%s\n" "\"timestamp\": \"${timestamp}\","
1306 printf "\t%s\n" "\"autoadd_allow\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_allowlist}")\","
1307 printf "\t%s\n" "\"autoadd_block\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_blocklist}")\","
1308 printf "\t%s\n" "\"sum_sets\": \"${sum_sets}\","
1309 printf "\t%s\n" "\"sum_setinput\": \"${sum_setinput}\","
1310 printf "\t%s\n" "\"sum_setforwardwan\": \"${sum_setforwardwan}\","
1311 printf "\t%s\n" "\"sum_setforwardlan\": \"${sum_setforwardlan}\","
1312 printf "\t%s\n" "\"sum_setelements\": \"${sum_setelements}\","
1313 printf "\t%s\n" "\"sum_cntinput\": \"${sum_cntinput}\","
1314 printf "\t%s\n" "\"sum_cntforwardwan\": \"${sum_cntforwardwan}\","
1315 printf "\t%s\n" "\"sum_cntforwardlan\": \"${sum_cntforwardlan}\""
1319 # text output preparation
1321 if [ "${output}" != "json" ] && [ -s "${report_jsn}" ]; then
1324 if json_load_file "${report_jsn}" >/dev/null 2>&1; then
1325 json_get_var timestamp "timestamp" >/dev/null 2>&1
1326 json_get_var autoadd_allow "autoadd_allow" >/dev/null 2>&1
1327 json_get_var autoadd_block "autoadd_block" >/dev/null 2>&1
1328 json_get_var sum_sets "sum_sets" >/dev/null 2>&1
1329 json_get_var sum_setinput "sum_setinput" >/dev/null 2>&1
1330 json_get_var sum_setforwardwan "sum_setforwardwan" >/dev/null 2>&1
1331 json_get_var sum_setforwardlan "sum_setforwardlan" >/dev/null 2>&1
1332 json_get_var sum_setelements "sum_setelements" >/dev/null 2>&1
1333 json_get_var sum_cntinput "sum_cntinput" >/dev/null 2>&1
1334 json_get_var sum_cntforwardwan "sum_cntforwardwan" >/dev/null 2>&1
1335 json_get_var sum_cntforwardlan "sum_cntforwardlan" >/dev/null 2>&1
1337 printf "%s\n%s\n%s\n" ":::" "::: banIP Set Statistics" ":::"
1338 printf "%s\n" " Timestamp: ${timestamp}"
1339 printf "%s\n" " ------------------------------"
1340 printf "%s\n" " auto-added to allowlist today: ${autoadd_allow}"
1341 printf "%s\n\n" " auto-added to blocklist today: ${autoadd_block}"
1342 json_select "sets" >/dev/null 2>&1
1343 json_get_keys table_sets >/dev/null 2>&1
1344 if [ -n "${table_sets}" ]; then
1345 printf "%-25s%-15s%-24s%-24s%s\n" " Set" "| Elements" "| WAN-Input (packets)" "| WAN-Forward (packets)" "| LAN-Forward (packets)"
1346 printf "%s\n" " ---------------------+--------------+-----------------------+-----------------------+------------------------"
1347 for item in ${table_sets}; do
1348 printf " %-21s" "${item}"
1349 json_select "${item}"
1350 json_get_keys set_details
1351 for detail in ${set_details}; do
1352 json_get_var jsnval "${detail}" >/dev/null 2>&1
1355 printf "%-15s" "| ${jsnval}"
1357 "cnt_input" | "cnt_forwardwan" | "cnt_forwardlan")
1358 [ -n "${jsnval}" ] && tmp_val=": ${jsnval}"
1361 printf "%-24s" "| ${jsnval}${tmp_val}"
1369 printf "%s\n" " ---------------------+--------------+-----------------------+-----------------------+------------------------"
1370 printf "%-25s%-15s%-24s%-24s%s\n" " ${sum_sets}" "| ${sum_setelements}" "| ${sum_setinput} (${sum_cntinput})" "| ${sum_setforwardwan} (${sum_cntforwardwan})" "| ${sum_setforwardlan} (${sum_cntforwardlan})"
1376 # output channel (text|json|mail)
1380 [ -s "${report_txt}" ] && "${ban_catcmd}" "${report_txt}"
1383 [ -s "${report_jsn}" ] && "${ban_catcmd}" "${report_jsn}"
1386 [ -n "${ban_mailreceiver}" ] && [ -x "${ban_mailcmd}" ] && f_mail
1389 rm -f "${report_txt}"
1395 local item table_sets ip proto hold cnt result_flag="/var/run/banIP.search" input="${1}"
1397 if [ -n "${input}" ]; then
1398 ip="$(printf "%s" "${input}" | "${ban_awkcmd}" 'BEGIN{RS="(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?[[:space:]]*$)"}{printf "%s",RT}')"
1399 [ -n "${ip}" ] && proto="v4
"
1400 if [ -z "${proto}" ]; then
1401 ip="$
(printf "%s" "${input}" | "${ban_awkcmd}" 'BEGIN{RS="(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]].*|$)"}{printf "%s",RT
}')"
1402 [ -n "${ip}" ] && proto="v6"
1405 if [ -n "${proto}" ]; then
1406 table_sets="$("${ban_nftcmd}" -tj list ruleset 2>/dev/null | "${ban_jsoncmd}" -qe "@.nftables[@.set.table=\"banIP\"&&@.set.type=\"ip${proto}_addr\"].set.name")"
1408 printf "%s\n%s\n%s\n" ":::" "::: no valid search input" ":::"
1411 printf "%s\n%s\n%s\n" ":::" "::: banIP Search" ":::"
1412 printf " %s\n" "Looking for IP '${ip}' on $(date "+%Y-%m-%d %H:%M:%S")"
1413 printf " %s\n" "---"
1415 for item in ${table_sets}; do
1416 [ -f "${result_flag}" ] && break
1418 if "${ban_nftcmd}" get element inet banIP "${item}" "{ ${ip} }" >/dev/null 2>&1; then
1419 printf " %s\n" "IP found in Set '${item}'"
1423 hold="$((cnt % ban_cores))"
1424 [ "${hold}" = "0" ] && wait
1428 [ -f "${result_flag}" ] && rm -f "${result_flag}" || printf " %s\n" "IP not found"
1434 local set_elements input="${1}"
1436 if [ -z "${input}" ]; then
1437 printf "%s\n%s\n%s\n" ":::" "::: no valid survey input" ":::"
1440 set_elements="$("${ban_nftcmd}" -j list set inet banIP "${input}" 2>/dev/null | "${ban_jsoncmd}" -qe '@.nftables
[*].
set.elem
[*]')"
1441 printf "%s\n%s\n%s\n" ":::" "::: banIP Survey" ":::"
1442 printf " %s\n" "List of elements in the Set '${input}' on $(date "+%Y-%m-%d %H:%M:%S")"
1443 printf " %s\n" "---"
1444 [ -n "${set_elements}" ] && printf "%s\n" "${set_elements}" || printf " %s\n" "empty Set"
1452 # load mail template
1454 if [ -r "${ban_mailtemplate}" ]; then
1455 . "${ban_mailtemplate}"
1457 f_log "info" "no mail template"
1459 [ -z "${mail_text}" ] && f_log "info" "no mail content"
1460 [ "${ban_debug}" = "1" ] && msmtp_debug="--debug"
1464 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"
1465 printf "%b" "${ban_mailhead}${mail_text}" | "${ban_mailcmd}" --timeout=10 ${msmtp_debug} -a "${ban_mailprofile}" "${ban_mailreceiver}" >/dev/null 2>&1
1466 f_log "info" "send status mail (${?})"
1468 f_log "debug" "f_mail ::: notification: ${ban_mailnotification}, template: ${ban_mailtemplate}, profile: ${ban_mailprofile}, receiver: ${ban_mailreceiver}, rc: ${?}"
1474 local nft_expiry line proto ip log_raw log_count rdap_log rdap_rc rdap_elements rdap_info
1476 if [ -x "${ban_logreadcmd}" ] && [ -n "${ban_logterm%%??}" ] && [ "${ban_loglimit}" != "0" ]; then
1477 f_log "info" "start detached banIP log service"
1478 [ -n "${ban_nftexpiry}" ] && nft_expiry="timeout $(printf "%s" "${ban_nftexpiry}" | "${ban_grepcmd}" -oE "([0-9]+[d|h|m|s])+$")"
1479 "${ban_logreadcmd}" -fe "${ban_logterm%%??}" 2>/dev/null |
1480 while read -r line; do
1481 : >"${ban_rdapfile}"
1483 ip="$(printf "%s" "${line}" | "${ban_awkcmd}" 'BEGIN{RS="(([0-9]{1,3}\\.){3}[0-9]{1,3})+"}{if(!seen[RT]++)printf "%s ",RT}')"
1484 ip="$
(f_trim
"${ip}")"
1486 [ -n "${ip}" ] && proto="v4
"
1487 if [ -z "${proto}" ]; then
1488 ip="$
(printf "%s" "${line}" | "${ban_awkcmd}" 'BEGIN{RS="([A-Fa-f0-9]{1,4}::?){3,7}[A-Fa-f0-9]{1,4}"}{if(!seen
[RT
]++)printf "%s ",RT
}')"
1489 ip="$(f_trim "${ip}")"
1491 [ -n "${ip}" ] && proto="v6"
1493 if [ -n "${proto}" ] && ! "${ban_nftcmd}" get element inet banIP blocklist"${proto}" "{ ${ip} }" >/dev/null 2>&1 && ! "${ban_grepcmd}" -q "^${ip}" "${ban_allowlist}"; then
1494 f_log "info" "suspicious IP '${ip}'"
1495 log_raw="$("${ban_logreadcmd}" -l "${ban_loglimit}" 2>/dev/null)"
1496 log_count="$(printf "%s\n" "${log_raw}" | "${ban_grepcmd}" -c "suspicious IP '${ip}'")"
1497 if [ "${log_count}" -ge "${ban_logcount}" ]; then
1498 if [ "${ban_autoblocksubnet}" = "1" ]; then
1499 rdap_log
="$("${ban_fetchcmd}" ${ban_rdapparm} "${ban_rdapfile}" "${ban_rdapurl}${ip}" 2>&1)"
1501 if [ "${rdap_rc}" = "0" ] && [ -s "${ban_rdapfile}" ]; then
1502 rdap_elements
="$(jsonfilter -i "${ban_rdapfile}" -qe '@.cidr0_cidrs.*' | awk 'BEGIN{FS="[\" ]"}{printf "%s
/%s
, ",$6,$11}')"
1503 rdap_info
="$(jsonfilter -i "${ban_rdapfile}" -qe '@.country' -qe '@.notices[@.title="Source
"].description[1]' | awk 'BEGIN{RS="";FS="\n"}{printf "%s
, %s
",$1,$2}')"
1504 if [ -n "${rdap_elements//\/*/}" ]; then
1505 if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" "{ ${rdap_elements%%??} ${nft_expiry} }" >/dev
/null
2>&1; then
1506 f_log
"info" "add IP range '${rdap_elements%%??}' (source: ${rdap_info:-"-"} ::: expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set"
1510 f_log
"info" "rdap request failed (rc: ${rdap_rc:-"-"}/log: ${rdap_log})"
1513 if [ "${ban_autoblocksubnet}" = "0" ] || [ "${rdap_rc}" != "0" ] || [ ! -s "${ban_rdapfile}" ] || [ -z "${rdap_elements//\/*/}" ]; then
1514 if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" "{ ${ip} ${nft_expiry} }" >/dev
/null
2>&1; then
1515 f_log
"info" "add IP '${ip}' (expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set"
1518 if [ -z "${ban_nftexpiry}" ] && [ "${ban_autoblocklist}" = "1" ] && ! "${ban_grepcmd}" -q "^${ip}" "${ban_blocklist}"; then
1519 printf "%-42s%s\n" "${ip}" "# added on $(date "+%Y-
%m-
%d
%H
:%M
:%S
")" >>"${ban_blocklist}"
1520 f_log
"info" "add IP '${ip}' to local blocklist"
1526 f_log
"info" "start detached no-op banIP service"
1533 if [ -r "/lib/functions.sh" ] && [ -r "/lib/functions/network.sh" ] && [ -r "/usr/share/libubox/jshn.sh" ]; then
1534 .
"/lib/functions.sh"
1535 .
"/lib/functions/network.sh"
1536 .
"/usr/share/libubox/jshn.sh"
1538 rm -rf "${ban_lock}"
1542 # check banIP availability
1545 if [ "${ban_action}" != "stop" ]; then
1546 [ ! -d "/etc/banip" ] && f_log
"err" "no banIP config directory"
1547 [ ! -r "/etc/config/banip" ] && f_log
"err" "no banIP config"
1548 [ "$(uci_get banip global ban_enabled)" = "0" ] && f_log
"err" "banIP is disabled"