fi
}
-# convert chars
-#
-f_char() {
- local char="${1}"
-
- if [ "${char}" = "1" ]; then
- printf '%s' "✔"
- elif [ "${char}" = "0" ] || [ -z "${char}" ]; then
- printf '%s' "✘"
- else
- printf '%s' "${char}"
- fi
-}
-
# trim strings
#
f_trim() {
fi
{
- # nft header (tables, base and regular chains)
+ # nft header, optional table cleanup, base table, chains, counters and default rules
#
- printf '%s\n\n' "#!${ban_nftcmd} -f"
- if "${ban_nftcmd}" -t list table inet banIP >/dev/null 2>&1; then
+ printf '%s\n' "#!${ban_nftcmd} -f" ""
+ "${ban_nftcmd}" -t list table inet banIP >/dev/null 2>&1 &&
printf '%s\n' "delete table inet banIP"
- fi
- 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; }"
-
- # 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"
-
- # 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"
-
- # 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"
-
- # default pre-routing rules
- #
- printf '%s\n' "add rule inet banIP pre-routing iifname != { ${wan_dev} } counter accept"
+ printf '%s\n' \
+ "add table inet banIP" \
+ "add chain inet banIP pre-routing { type filter hook prerouting priority -175; policy accept; }" \
+ "add chain inet banIP wan-input { type filter hook input priority ${ban_nftpriority}; policy accept; }" \
+ "add chain inet banIP wan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }" \
+ "add chain inet banIP lan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }" \
+ "add chain inet banIP _inbound" \
+ "add chain inet banIP _outbound" \
+ "add chain inet banIP _reject" \
+ "add counter inet banIP cnt_icmpflood" \
+ "add counter inet banIP cnt_udpflood" \
+ "add counter inet banIP cnt_synflood" \
+ "add counter inet banIP cnt_tcpinvalid" \
+ "add counter inet banIP cnt_ctinvalid" \
+ "add counter inet banIP cnt_bcp38" \
+ "add rule inet banIP _reject iifname != { ${wan_dev} } meta l4proto tcp reject with tcp reset" \
+ "add rule inet banIP _reject reject with icmpx host-unreachable" \
+ "add rule inet banIP pre-routing iifname != { ${wan_dev} } counter accept"
# ct state invalid
#
- if [ "${ban_logprerouting}" = "1" ]; then
+ [ "${ban_logprerouting}" = "1" ] &&
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"
# ICMP Flood
#
if [ "${ban_icmplimit}" -gt "0" ]; then
- if [ "${ban_logprerouting}" = "1" ]; then
+ [ "${ban_logprerouting}" = "1" ] &&
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"
fi
# UDP Flood
#
if [ "${ban_udplimit}" -gt "0" ]; then
- if [ "${ban_logprerouting}" = "1" ]; then
+ [ "${ban_logprerouting}" = "1" ] &&
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"
fi
# SYN Flood
#
if [ "${ban_synlimit}" -gt "0" ]; then
- if [ "${ban_logprerouting}" = "1" ]; then
+ [ "${ban_logprerouting}" = "1" ] &&
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"
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}" \
+ "add rule inet banIP pre-routing tcp flags & (syn|rst) == (syn|rst) ${log_tcp}" \
+ "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) ${log_tcp}" \
+ "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" \
+ "add rule inet banIP pre-routing tcp flags & (syn|rst) == (syn|rst) counter name cnt_tcpinvalid drop" \
+ "add rule inet banIP pre-routing tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) counter name cnt_tcpinvalid drop" \
+ "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"
- if [ "${ban_bcp38}" = "1" ]; then
+ printf '%s\n' \
+ "add rule inet banIP wan-input ct state established,related counter accept" \
+ "add rule inet banIP wan-input iifname != { ${wan_dev} } counter accept" \
+ "add rule inet banIP wan-input meta nfproto ipv4 udp sport 67-68 udp dport 67-68 counter accept" \
+ "add rule inet banIP wan-input meta nfproto ipv6 udp sport 547 udp dport 546 counter accept" \
+ "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"
+ [ "${ban_bcp38}" = "1" ] &&
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"
else
# 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"
- if [ "${ban_bcp38}" = "1" ]; then
+ printf '%s\n' \
+ "add rule inet banIP wan-forward ct state established,related counter accept" \
+ "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"
+ [ "${ban_bcp38}" = "1" ] &&
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"
else
# 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"
- if [ "${ban_bcp38}" = "1" ]; then
+ printf '%s\n' \
+ "add rule inet banIP lan-forward ct state established,related counter accept" \
+ "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"
+ [ "${ban_bcp38}" = "1" ] &&
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"
} >"${file}"
# generate status information
#
f_genstatus() {
+ local s_auto s_v4 s_v6 s_bcp s_lpre s_lin s_lout s_cnt s_dedup s_split s_cf s_allow s_dbg runtime
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}"
+ # memory and nftables version information
+ #
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"]')"
+ # read config information if not already available
+ #
[ -z "${ban_dev}" ] && f_conf
+
+ # only gather detailed information if banIP is active
+ #
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')"
[ -s "${ban_customfeedfile}" ] && custom_feed="1"
[ "${ban_splitsize:-"0"}" -gt "0" ] && split="1"
+ # map flag values to status characters
+ #
+ case "${ban_autodetect}" in 1) s_auto="✔" ;; *) s_auto="✘" ;; esac
+ case "${ban_protov4}" in 1) s_v4="✔" ;; *) s_v4="✘" ;; esac
+ case "${ban_protov6}" in 1) s_v6="✔" ;; *) s_v6="✘" ;; esac
+ case "${ban_bcp38}" in 1) s_bcp="✔" ;; *) s_bcp="✘" ;; esac
+ case "${ban_logprerouting}" in 1) s_lpre="✔" ;; *) s_lpre="✘" ;; esac
+ case "${ban_loginbound}" in 1) s_lin="✔" ;; *) s_lin="✘" ;; esac
+ case "${ban_logoutbound}" in 1) s_lout="✔" ;; *) s_lout="✘" ;; esac
+ case "${ban_nftcount}" in 1) s_cnt="✔" ;; *) s_cnt="✘" ;; esac
+ case "${ban_deduplicate}" in 1) s_dedup="✔" ;; *) s_dedup="✘" ;; esac
+ case "${split}" in 1) s_split="✔" ;; *) s_split="✘" ;; esac
+ case "${custom_feed}" in 1) s_cf="✔" ;; *) s_cf="✘" ;; esac
+ case "${ban_allowlistonly}" in 1) s_allow="✔" ;; *) s_allow="✘" ;; esac
+ case "${ban_debug}" in 1) s_dbg="✔" ;; *) s_dbg="✘" ;; esac
+
+ # generate JSON status file
+ #
: >"${ban_rtfile}"
json_init
json_load_file "${ban_rtfile}" >/dev/null 2>&1
json_close_array
json_add_string "nft_info" "ver: ${nft_ver:-"-"}, priority: ${ban_nftpriority}, policy: ${ban_nftpolicy}, loglevel: ${ban_nftloglevel}, expiry: ${ban_nftexpiry:-"-"}, limit (icmp/syn/udp): ${ban_icmplimit}/${ban_synlimit}/${ban_udplimit}"
json_add_string "run_info" "base: ${ban_basedir}, backup: ${ban_backupdir}, report: ${ban_reportdir}, error: ${ban_errordir}"
- json_add_string "run_flags" "auto: $(f_char ${ban_autodetect}), proto (4/6): $(f_char ${ban_protov4})/$(f_char ${ban_protov6}), bcp38: $(f_char ${ban_bcp38}), log (pre/in/out): $(f_char ${ban_logprerouting})/$(f_char ${ban_loginbound})/$(f_char ${ban_logoutbound}), count: $(f_char ${ban_nftcount}), dedup: $(f_char ${ban_deduplicate}), split: $(f_char ${split}), custom feed: $(f_char ${custom_feed}), allowed only: $(f_char ${ban_allowlistonly}), debug: $(f_char ${ban_debug})"
+ json_add_string "run_flags" "auto: ${s_auto}, proto (4/6): ${s_v4}/${s_v6}, bcp38: ${s_bcp}, log (pre/in/out): ${s_lpre}/${s_lin}/${s_lout}, count: ${s_cnt}, dedup: ${s_dedup}, split: ${s_split}, custom feed: ${s_cf}, allowed only: ${s_allow}, debug: ${s_dbg}"
json_add_string "last_run" "${runtime:-"-"}"
json_add_string "system_info" "cores: ${ban_cores}, log: ${ban_logreadcmd##*/}, fetch: ${ban_fetchcmd##*/}, ${ban_sysver}"
json_dump >"${ban_rtfile}"
# domain lookup
#
f_lookup() {
- local cnt list domain lookup ip elementsv4 elementsv6 start_time end_time duration cnt_domain="0" cnt_ip="0" feed="${1}"
+ local cnt list timestamp domain lookup ip elementsv4 elementsv6 start_time end_time duration cnt_domain="0" cnt_ip="0" feed="${1}"
read -r start_time _ <"/proc/uptime"
start_time="${start_time%%.*}"
for domain in ${list}; do
lookup="$("${ban_lookupcmd}" "${domain}" ${ban_resolver} 2>>"${ban_errorlog}" | "${ban_awkcmd}" '/^Address[ 0-9]*: /{if(!seen[$NF]++)printf "%s ",$NF}' 2>>"${ban_errorlog}")"
+ [ -n "${lookup}" ] && timestamp="$(date "+%Y-%m-%d %H:%M:%S")"
for ip in ${lookup}; do
if [ "${ip%%.*}" = "127" ] || [ "${ip%%.*}" = "0" ] || [ -z "${ip%%::*}" ]; then
continue
else
[ "${ip##*:}" = "${ip}" ] && elementsv4="${elementsv4} ${ip}," || elementsv6="${elementsv6} ${ip},"
if [ "${feed}" = "allowlist" ] && [ "${ban_autoallowlist}" = "1" ] && ! "${ban_grepcmd}" -q "^${ip}[[:space:]]*#" "${ban_allowlist}"; then
- printf "%-45s%s\n" "${ip}" "# '${domain}' added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_allowlist}"
+ printf "%-45s%s\n" "${ip}" "# '${domain}' added on ${timestamp}" >>"${ban_allowlist}"
elif [ "${feed}" = "blocklist" ] && [ "${ban_autoblocklist}" = "1" ] && ! "${ban_grepcmd}" -q "^${ip}[[:space:]]*#" "${ban_blocklist}"; then
- printf "%-45s%s\n" "${ip}" "# '${domain}' added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_blocklist}"
+ printf "%-45s%s\n" "${ip}" "# '${domain}' added on ${timestamp}" >>"${ban_blocklist}"
fi
cnt_ip="$((cnt_ip + 1))"
fi
if [ "${rdap_rc}" = "0" ] && [ -s "${ban_rdapfile}.${ip}" ]; then
[ "${proto}" = ".v4" ] && rdap_idx="$("${ban_jsoncmd}" -i "${ban_rdapfile}.${ip}" -qe '@.cidr0_cidrs[@.v4prefix].*' | "${ban_awkcmd}" '{ORS=" "; print}')"
[ "${proto}" = ".v6" ] && rdap_idx="$("${ban_jsoncmd}" -i "${ban_rdapfile}.${ip}" -qe '@.cidr0_cidrs[@.v6prefix].*' | "${ban_awkcmd}" '{ORS=" "; print}')"
- rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}.${ip}" -qe '@.country' -qe '@.notices[@.title="Source"].description[1]' | "${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s",$1,$2}')"
- [ -z "${rdap_info}" ] && rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}.${ip}" -qe '@.notices[0].links[0].value' | "${ban_awkcmd}" 'BEGIN{FS="[/.]"}{printf"%s, %s","n/a",toupper($4)}')"
+ rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}.${ip}" -qe '@.country' -qe '@.notices[@.title="Source"].description[1]' | "${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{c=($1!=""?$1:"-"); s=($2!=""?$2:"-"); printf "%s, %s", c, s}')"
+ [ -z "${rdap_info}" ] || [ "${rdap_info}" = "-, -" ] && rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}.${ip}" -qe '@.notices[0].links[0].value' | "${ban_awkcmd}" 'BEGIN{FS="[/.]"}{printf"%s, %s","n/a",toupper($4)}')"
# if RDAP response contains (multiple) valid CIDR info,
# attempt to add entire range to blocklist set with same expiry as individual IP