banip: release 1.8.12-1

* new option ban_monitorallowed: in allowlist-only mode
  the log monitor only honours the local allowlist, so attackers
  from an explicitly allowed segment can be banned (fixes openwrt/luci#8950)
* adds the allowlist.local.v4/.v6 Sets, built from /etc/banip/banip.allowlist only,
  referenced by no rule
* allowlist-only mode: skip only those external feeds whose direction is
  fully covered by the allowlist, instead of skipping all or none — split Sets included
* f_lookup keeps the monitor Set in sync with resolved domains
* f_restore: no more bogus per-proto restore attempts for the allowlist
* f_report: batched and deduplicated geo lookups, correct Set names in the report
* readme update

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken committed 2026-08-21 21:47:17 +02:00
1 parent b785b5c631
commit dd7b85bb24
4 files changed
+247 -165

No files matched your search

+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=banip
PKG_VERSION:=1.8.11
PKG_RELEASE:=2
PKG_VERSION:=1.8.12
PKG_RELEASE:=1
PKG_LICENSE:=GPL-3.0-or-later
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
+8
View File
@@ -111,6 +111,7 @@ For a typical setup these few steps are enough to get banIP up and running — s
* Automatically selects one of the following download utilities with ssl support: curl, uclient-fetch or full wget
* Provides HTTP ETag support to download only resources that have been updated on the server side, to speed up banIP reloads and to save bandwidth
* Supports an `allowlist only` mode, this option restricts the internet access only to specific, explicitly allowed IP segments
* Optionally screens the allowed IP segments in `allowlist only` mode as well, i.e. the log monitor may ban attackers from an explicitly allowed segment while the local allowlist entries stay exempt (see `ban_monitorallowed`)
* Supports external allowlist URLs to reference additional IPv4/IPv6 feeds
* Optionally always allow certain protocols/destination ports in the inbound chain
* Deduplicate IPs across all Sets (single IPs only, no intervals)
@@ -205,6 +206,7 @@ The `report` sub-command accepts an output mode: `text` (default, human-readable
| ban_autoblocksubnet | option | 0 | add entire subnets to the blocklist Sets based on a rate-limited, non-blocking RDAP lookup for the suspicious IP |
| ban_autoallowuplink | option | subnet | limit the uplink autoallow function to: `subnet`, `ip` or `disable` it at all |
| ban_allowlistonly | option | 0 | restrict the internet access only to specific, explicitly allowed IP segments |
| ban_monitorallowed | option | 0 | restrict the log monitor to the entries of the local allowlist (allowlist-only mode) |
| ban_allowflag | option | - | always allow certain protocols(tcp or udp) plus destination ports or port ranges, e.g.: `tcp 80 443-444` |
| ban_allowurl | list | - | external allowlist feed URLs, one or more references to simple remote IP lists |
| ban_basedir | option | /tmp | base working directory while banIP processing |
@@ -458,6 +460,10 @@ Both local lists also accept domain names as input to allow IP filtering based o
**Allowlist-only mode**
banIP supports an "allowlist only" mode. This option restricts Internet access only to certain, explicitly permitted IP segments - and blocks access to the rest of the Internet. All IPs that are _not_ listed in the allowlist or in the external allowlist URLs are blocked. In this mode it might be useful to limit the allowlist feed to the inbound chain, to still allow outbound communication to the rest of the world.
In this mode the allowlist Sets define the permitted address scope, they do not act as an accept precedence - the blocklist Set is still evaluated and still applies. By default the log monitor nevertheless treats every allowlisted IP as exempt, therefore attackers coming from a permitted segment (e.g. a country-wide external allowlist feed) are never banned. Enable the `ban_monitorallowed` option to restrict the log monitor to the entries of the local allowlist. banIP then processes an additional local feed which provides the `allowlist.local.v4`/`allowlist.local.v6` Sets, built from /etc/banip/banip.allowlist only - including the automatically added uplink. These Sets are not referenced by any rule, they are solely used by the log monitor: local entries stay exempt, IPs which are merely covered by an external allowlist feed can be banned. This allows a "permit my own country, but still screen it" setup. The option has no effect unless `ban_allowlistonly` is enabled, and the additional Sets are removed automatically as soon as it is switched off.
External feeds are skipped in this mode as far as they are redundant: the allowlist emits an inverted and therefore terminal drop rule in every chain it covers, so a feed rule in exactly these chains can never match. With the default allowlist direction all external feeds are skipped. If the allowlist is limited to a single chain - e.g. to the inbound chain - only the feeds of that chain are skipped, feeds which also cover the opposite chain are still processed.
**MAC/IP-binding**
banIP supports concatenation of local MAC addresses/ranges with IPv4/IPv6 addresses, e.g. to enforce dhcp assignments or to free connected clients from outbound blocking.
The following notations in the local allow- and block-list are supported:
@@ -531,6 +537,8 @@ To make this work, banIP uses the following external components:
* [CARTO basemap styles](https://github.com/CartoDB/basemap-styles) based on [OpenMapTiles](https://openmaptiles.org/schema)
* The free and quite fast [IP Geolocation API](https://ip-api.com/) to resolve the required IP/geolocation information
Please note: the free ip-api.com batch endpoint is rate limited to 15 requests per minute per source IP. Requests beyond that limit are throttled with HTTP 429, and constantly exceeding the limit gets the IP banned for an hour — in both cases the map stays empty and banIP logs an info message. To stay below the limit banIP collects the top listed elements of all Sets, deduplicates them and resolves them in as few batch requests as possible (100 IPs each, the maximum the endpoint accepts). A setup with up to ~1500 mapped elements therefore needs no more than 15 requests per report run. If you run a large number of Sets and regenerate the report frequently, lower `ban_map` to `0` or reduce the number of active feeds.
**CGI interface to receive remote logging events**
banIP ships a basic cgi interface in `/www/cgi-bin/banip` to receive remote logging events (disabled by default). The cgi interface evaluates logging events via GET or POST request (see examples below). To enable the cgi interface set the following options:
+223 -141
View File
@@ -69,6 +69,7 @@ ban_logoutbound="0"
ban_allowurl=""
ban_allowflag=""
ban_allowlistonly="0"
ban_monitorallowed="0"
ban_autoallowlist="1"
ban_autoallowuplink="subnet"
ban_autoblocklist="1"
@@ -801,6 +802,69 @@ f_getelements() {
[ -s "${file}" ] && printf '%s' "elements={ $("${ban_catcmd}" "${file}" 2>>"${ban_errorlog}") };"
}
# resolve the chain direction of a feed,
# an explicitly configured direction always wins over the feed default
#
f_direction() {
local feed_name="${1}" feed_chain="${2}"
if [ "${feed_chain}" = "none" ]; then
printf '%s' "none"
return 0
fi
case " ${ban_feedin} " in
*" ${feed_name} "*)
printf '%s' "inbound"
return 0
;;
esac
case " ${ban_feedout} " in
*" ${feed_name} "*)
printf '%s' "outbound"
return 0
;;
esac
case " ${ban_feedinout} " in
*" ${feed_name} "*)
printf '%s' "inbound outbound"
return 0
;;
esac
case "${feed_chain}" in
"in")
printf '%s' "inbound"
;;
"out")
printf '%s' "outbound"
;;
"inout")
printf '%s' "inbound outbound"
;;
*)
printf '%s' "inbound"
;;
esac
}
# check whether an external feed is redundant in allowlist-only mode
#
f_skipfeed() {
local direction allow_direction feed_direction="${1}"
[ "${ban_allowlistonly}" != "1" ] && return 1
allow_direction="$(f_direction "allowlist" "inout")"
for direction in ${feed_direction}; do
case " ${allow_direction} " in
*" ${direction} "*) ;;
*)
return 1
;;
esac
done
return 0
}
# handle etag http header
#
f_etag() {
@@ -1150,53 +1214,34 @@ f_down() {
# set feed direction
#
feed_name="${feed%%.*}"
if case " ${ban_feedin} " in
*" ${feed_name} "*)
true
;;
*)
false
;;
esac; then
feed_direction="$(f_direction "${feed_name}" "${feed_chain}")"
case "${feed_direction}" in
"inbound")
feed_policy="in"
feed_direction="inbound"
elif case " ${ban_feedout} " in
*" ${feed_name} "*)
true
;;
*)
false
;;
esac; then
;;
"outbound")
feed_policy="out"
feed_direction="outbound"
elif case " ${ban_feedinout} " in
*" ${feed_name} "*)
true
;;
*)
false
;;
esac; then
;;
"inbound outbound")
feed_policy="inout"
feed_direction="inbound outbound"
else
feed_policy="${feed_chain}"
case "${feed_chain}" in
"in")
feed_direction="inbound"
;;
"out")
feed_direction="outbound"
;;
"inout")
feed_direction="inbound outbound"
;;
*)
feed_direction="inbound"
;;
esac
fi
;;
*)
feed_policy="${feed_direction}"
;;
esac
# skip external feeds which are already covered by the allowlist in allowlist-only mode
#
case "${feed_name}" in
"allowlist" | "blocklist") ;;
*)
if f_skipfeed "${feed_direction}"; then
f_log "info" "skip feed '${feed}' in allowlistonly mode"
return 0
fi
;;
esac
# prepare feed flags
#
@@ -1264,7 +1309,7 @@ f_down() {
# restore local backups
#
if [ "${feed%%.*}" != "blocklist" ]; then
if [ "${feed%%.*}" != "blocklist" ] && [ "${feed%.*}" != "allowlist.local" ]; then
if [ -n "${ban_etagparm}" ] && [ "${ban_action}" = "reload" ] && [ "${feed_url}" != "local" ] && [ "${feed%%.*}" != "allowlist" ]; then
etag_rc="0"
case "${feed%%.*}" in
@@ -1307,20 +1352,31 @@ f_down() {
esac
fi
if [ "${etag_rc}" = "0" ] || [ "${ban_action}" != "reload" ] || [ "${feed_url}" = "local" ]; then
if [ "${feed%%.*}" = "allowlist" ] && [ ! -f "${tmp_allow}" ]; then
f_restore "allowlist" "-" "${tmp_allow}" "${etag_rc}"
restore_rc="${?}"
if [ "${feed%.*}" = "allowlist" ]; then
if [ ! -f "${tmp_allow}" ]; then
f_restore "allowlist" "-" "${tmp_allow}" "${etag_rc}"
restore_rc="${?}"
feed_rc="${restore_rc}"
fi
else
f_restore "${feed}" "${feed_url}" "${tmp_load}" "${etag_rc}"
restore_rc="${?}"
feed_rc="${restore_rc}"
fi
feed_rc="${restore_rc}"
fi
fi
# prepare the monitor-only allowlist, local entries only
#
if [ "${feed%.*}" = "allowlist.local" ] && [ ! -f "${tmp_allow}" ]; then
"${ban_catcmd}" "${ban_allowlist}" 2>>"${ban_errorlog}" >"${tmp_allow}"
feed_rc="${?}"
fi
# prepare local/remote allowlist
#
if [ "${feed%%.*}" = "allowlist" ] && [ ! -f "${tmp_allow}" ]; then
if [ "${feed%.*}" = "allowlist" ] && [ ! -f "${tmp_allow}" ]; then
"${ban_catcmd}" "${ban_allowlist}" 2>>"${ban_errorlog}" >"${tmp_allow}"
feed_rc="${?}"
for feed_url in ${ban_allowurl}; do
@@ -1330,7 +1386,7 @@ f_down() {
feed_rc="${?}"
fi
else
f_log "info" "download for feed '${feed%%.*}' failed"
f_log "info" "download for feed '${feed%.*}' failed"
feed_rc="4"
break
fi
@@ -1724,7 +1780,7 @@ f_restore() {
# remove staled Sets
#
f_rmset() {
local feedlist tmp_del table_json feed country asn table_sets handles handle expr del_set feed_rc
local feedlist tmp_del table_json feed country asn table_sets handles handle expr del_set chain feed_chain feed_covered feed_rc
f_getfeed
json_get_keys feedlist
@@ -1734,10 +1790,30 @@ f_rmset() {
{
printf '%s\n\n' "#!${ban_nftcmd} -f"
for feed in ${table_sets}; do
if [ "${feed%.*}" = "allowlist.local" ]; then
if [ "${ban_allowlistonly}" = "1" ] && [ "${ban_monitorallowed}" = "1" ]; then
continue
fi
fi
feed_covered="0"
if [ "${ban_allowlistonly}" = "1" ]; then
case "${feed%%.*}" in
"allowlist" | "blocklist") ;;
*)
feed_chain=""
if json_select "${feed%%.*}" >/dev/null 2>&1; then
json_get_var feed_chain "chain" >/dev/null 2>&1
json_select ".." >/dev/null 2>&1
fi
f_skipfeed "$(f_direction "${feed%%.*}" "${feed_chain:-"in"}")" && feed_covered="1"
;;
esac
fi
# keep: active country split sets
#
if [ "${feed%%.*}" = "country" ] && [ "${ban_countrysplit}" = "1" ]; then
if [ "${feed_covered}" = "0" ] && [ "${feed%%.*}" = "country" ] && [ "${ban_countrysplit}" = "1" ]; then
country="${feed%.*}"
country="${country#*.}"
case " ${ban_feed} " in
@@ -1751,7 +1827,7 @@ f_rmset() {
# keep: active asn split sets
#
if [ "${feed%%.*}" = "asn" ] && [ "${ban_asnsplit}" = "1" ]; then
if [ "${feed_covered}" = "0" ] && [ "${feed%%.*}" = "asn" ] && [ "${ban_asnsplit}" = "1" ]; then
asn="${feed%.*}"
asn="${asn#*.}"
case " ${ban_feed} " in
@@ -1771,12 +1847,9 @@ f_rmset() {
*" ${feed%.*} "*)
if [ "${feed%.*}" != "country" ] || [ "${ban_countrysplit}" != "1" ]; then
if [ "${feed%.*}" != "asn" ] || [ "${ban_asnsplit}" != "1" ]; then
if [ "${feed%.*}" = "allowlist" ] || [ "${feed%.*}" = "blocklist" ] || [ "${ban_allowlistonly}" != "1" ]; then
if [ "${feed_covered}" = "0" ]; then
continue
fi
case " ${ban_feedin} ${ban_feedout} " in
*" allowlist "*) continue ;;
esac
fi
fi
;;
@@ -1954,7 +2027,7 @@ f_getstatus() {
#
f_lookup() {
local cnt list domain lookup ip dom ts proto elementsv4 elementsv6 start_time end_time duration cnt_domain="0" cnt_ip="0" feed="${1}"
local record_file tmp_dir target_file auto_flag
local record_file tmp_dir target_file auto_flag set_list set_name
# measure runtime of lookup function for performance insights
#
@@ -2023,16 +2096,22 @@ f_lookup() {
# add resolved IPs to nftables Sets
#
if [ -n "${elementsv4}" ]; then
if ! "${ban_nftcmd}" add element inet banIP "${feed}.v4" { ${elementsv4} } 2>>"${ban_errorlog}"; then
f_log "info" "can't add lookup file to nfset '${feed}.v4'"
fi
set_list="${feed}"
if [ "${feed}" = "allowlist" ] && [ "${ban_allowlistonly}" = "1" ] && [ "${ban_monitorallowed}" = "1" ]; then
set_list="${set_list} allowlist.local"
fi
if [ -n "${elementsv6}" ]; then
if ! "${ban_nftcmd}" add element inet banIP "${feed}.v6" { ${elementsv6} } 2>>"${ban_errorlog}"; then
f_log "info" "can't add lookup file to nfset '${feed}.v6'"
for set_name in ${set_list}; do
if [ -n "${elementsv4}" ]; then
if ! "${ban_nftcmd}" add element inet banIP "${set_name}.v4" { ${elementsv4} } 2>>"${ban_errorlog}"; then
f_log "info" "can't add lookup file to nfset '${set_name}.v4'"
fi
fi
fi
if [ -n "${elementsv6}" ]; then
if ! "${ban_nftcmd}" add element inet banIP "${set_name}.v6" { ${elementsv6} } 2>>"${ban_errorlog}"; then
f_log "info" "can't add lookup file to nfset '${set_name}.v6'"
fi
fi
done
# measure end time and log performance insights
#
@@ -2047,8 +2126,8 @@ f_lookup() {
#
f_report() {
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 cnt ip expr detail jsnval timestamp autoadd_allow autoadd_block sum_sets sum_setinbound sum_setoutbound sum_cntelements sum_cntinbound sum_cntoutbound quantity
local chunk jsn table_jsn set_jsn map_jsn chain set_elements uplink_ip uplink_list sum_setelements sum_synflood sum_udpflood sum_icmpflood sum_ctinvalid sum_tcpinvalid sum_setports sum_bcp38 output="${1}"
local cnt ip expr detail jsnval timestamp autoadd_allow autoadd_block sum_sets sum_setinbound sum_setoutbound sum_cntelements sum_cntinbound sum_cntoutbound
local jsn table_jsn set_jsn map_jsn map_lookup chunk_no chain set_elements uplink_ip sum_setelements sum_synflood sum_udpflood sum_icmpflood sum_ctinvalid sum_tcpinvalid sum_setports sum_bcp38 output="${1}"
f_conf
f_mkdir "${ban_reportdir}"
@@ -2254,81 +2333,76 @@ f_report() {
# retrieve/prepare map data
#
if [ "${ban_nftcount}" = "1" ] && [ "${ban_map}" = "1" ] && [ -s "${report_jsn}" ]; then
cnt="1"
f_getdl
printf '%s' ",[{}" >>"${map_jsn}"
map_lookup="${ban_rundir}/report.map.lookup"
: >"${map_lookup}"
# collect the uplink IPs
#
json_init
if json_load_file "${ban_rtfile}" >/dev/null 2>&1; then
json_get_values jsnval "active_uplink" >/dev/null 2>&1
for uplink_ip in ${jsnval}; do
uplink_ip="${uplink_ip%%/*}"
if [ -n "${uplink_ip}" ] && [ "${uplink_ip}" != "-" ]; then
uplink_list="${uplink_list}${uplink_list:+, }\"${uplink_ip}\""
printf '%s\t%s\n' "${uplink_ip}" "homeIP" >>"${map_lookup}"
fi
done
fi
if [ -n "${uplink_list}" ]; then
"${ban_fetchcmd}" ${ban_geoparm} "[ ${uplink_list} ]" "${ban_geourl}" 2>>"${ban_errorlog}" |
"${ban_jsoncmd}" -qe '@[*&&@.status="success"]' |
"${ban_awkcmd}" -v feed="homeIP" '{printf ",{\"%s\": %s}\n",feed,$0}' >"${map_jsn}.home"
if [ -s "${map_jsn}.home" ]; then
"${ban_catcmd}" "${map_jsn}.home" >>"${map_jsn}"
fi
"${ban_rmcmd}" -f "${map_jsn}.home"
fi
if [ -s "${map_jsn}" ]; then
json_init
if json_load_file "${report_jsn}" >/dev/null 2>&1; then
json_select "sets" >/dev/null 2>&1
json_get_keys table_sets >/dev/null 2>&1
if [ -n "${table_sets}" ]; then
for item in ${table_sets}; do
[ "${item%%_*}" = "allowlist" ] && continue
json_select "${item}"
json_get_keys set_details
for detail in ${set_details}; do
if [ "${detail}" = "set_elements" ]; then
json_get_values jsnval "${detail}" >/dev/null 2>&1
jsnval="\"${jsnval// /\", \"}\""
fi
done
if [ "${jsnval}" != '""' ]; then
(
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}.${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}.${item}"
fi
) &
[ "${cnt}" -gt "${ban_cores}" ] && wait -n
cnt="$((cnt + 1))"
fi
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}"
fi
"${ban_rmcmd}" -f "${map_jsn}.${item}"
done
fi
fi
# collect the top listed IPs of all relevant Sets
#
json_init
if json_load_file "${report_jsn}" >/dev/null 2>&1; then
json_select "sets" >/dev/null 2>&1
json_get_keys table_sets >/dev/null 2>&1
for item in ${table_sets}; do
[ "${item%%_*}" = "allowlist" ] && continue
json_select "${item}"
jsnval=""
json_get_values jsnval "set_elements" >/dev/null 2>&1
for ip in ${jsnval}; do
printf '%s\t%s\n' "${ip}" "${item//_/.}" >>"${map_lookup}"
done
json_select ".."
done
fi
# split the deduplicated IPs into batch requests of 100 IPs each,
# the maximum the geo service accepts
#
if [ -s "${map_lookup}" ]; then
"${ban_awkcmd}" -F '\t' -v file="${map_jsn}" -v size="100" \
'!seen[$1]++{no=int(cnt++/size)+1;printf "%s\"%s\"",(chunk[no]++?", ":""),$1 >(file ".req." no)}END{for(i=1;i<=no;i++)close(file ".req." i);printf "%s\n",no+0 >(file ".num")}' "${map_lookup}"
chunk_no="$("${ban_catcmd}" "${map_jsn}.num" 2>>"${ban_errorlog}")"
cnt="1"
while [ "${cnt}" -le "${chunk_no:-0}" ]; do
(
"${ban_fetchcmd}" ${ban_geoparm} "[ $("${ban_catcmd}" "${map_jsn}.req.${cnt}") ]" "${ban_geourl}" 2>>"${ban_errorlog}" |
"${ban_jsoncmd}" -qe '@[*&&@.status="success"]' |
"${ban_awkcmd}" -F '\t' 'NR==FNR{if(!($1 in feed))feed[$1]=$2;next}
match($0,/"query"[ \t]*:[ \t]*"[^"]+"/){query=substr($0,RSTART,RLENGTH);sub(/^"query"[ \t]*:[ \t]*"/,"",query);sub(/"$/,"",query);if(query in feed)printf ",{\"%s\": %s}\n",feed[query],$0}' \
"${map_lookup}" - >"${map_jsn}.rsp.${cnt}"
) &
[ "${cnt}" -gt "${ban_cores}" ] && wait -n
cnt="$((cnt + 1))"
done
wait
# assemble map data from the batch fragments
#
cnt="1"
while [ "${cnt}" -le "${chunk_no:-0}" ]; do
if [ -s "${map_jsn}.rsp.${cnt}" ]; then
[ -s "${map_jsn}" ] || printf '%s' ",[{}" >>"${map_jsn}"
"${ban_catcmd}" "${map_jsn}.rsp.${cnt}" >>"${map_jsn}"
fi
cnt="$((cnt + 1))"
done
[ -s "${map_jsn}" ] || f_log "info" "no geo data received, the rate limit of '${ban_geourl}' has probably been exceeded"
f_log "debug" "f_report ::: geo requests: ${chunk_no:-0}, map data: $([ -s "${map_jsn}" ] && printf '%s' "yes" || printf '%s' "no")"
fi
"${ban_rmcmd}" -f "${map_lookup}" "${map_jsn}".req.* "${map_jsn}".rsp.* "${map_jsn}.num"
fi
# text output preparation
@@ -2373,7 +2447,7 @@ f_report() {
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//_/.}"
json_select "${item}"
json_get_keys set_details
for detail in ${set_details}; do
@@ -2421,11 +2495,11 @@ f_report() {
[ -s "${report_txt}" ] && "${ban_catcmd}" "${report_txt}"
;;
"json")
if [ "${ban_nftcount}" = "1" ] && [ "${ban_map}" = "1" ]; then
jsn="$("${ban_catcmd}" ${report_jsn} ${map_jsn} 2>>"${ban_errorlog}")"
if [ "${ban_nftcount}" = "1" ] && [ "${ban_map}" = "1" ] && [ -s "${map_jsn}" ]; then
jsn="$("${ban_catcmd}" "${report_jsn}" "${map_jsn}" 2>>"${ban_errorlog}")"
[ -n "${jsn}" ] && printf '[%s]]\n' "${jsn}"
else
jsn="$("${ban_catcmd}" ${report_jsn} 2>>"${ban_errorlog}")"
jsn="$("${ban_catcmd}" "${report_jsn}" 2>>"${ban_errorlog}")"
[ -n "${jsn}" ] && printf '[%s]\n' "${jsn}"
fi
;;
@@ -2616,7 +2690,7 @@ 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 file cache_ts date_stamp time_now time_elapsed cache_interval rdap_interval rdap_tsfile rdap_lock rdap_jobs
local rdap_ts block_cache block_cache_limit block_cache_cnt
local rdap_ts block_cache block_cache_limit block_cache_cnt monitor_set
# intervals for periodic cache refresh and RDAP queries
#
@@ -2625,6 +2699,14 @@ f_monitor() {
rdap_tsfile="${ban_rundir}/banIP_rdap_ts"
printf '%s' "0" >"${rdap_tsfile}"
# determine the allowlist Set used by the monitor
#
if [ "${ban_allowlistonly}" = "1" ] && [ "${ban_monitorallowed}" = "1" ]; then
monitor_set="allowlist.local"
else
monitor_set="allowlist"
fi
# determine log reader type
#
if [ -f "${ban_logreadfile}" ] && [ -x "${ban_logreadcmd}" ] && [ "${ban_logreadcmd##*/}" = "tail" ]; then
@@ -2670,8 +2752,8 @@ f_monitor() {
# retrieve/cache current allowlist/blocklist content
#
allow_v4="$(nft_cache allowlist.v4)"
allow_v6="$(nft_cache allowlist.v6)"
allow_v4="$(nft_cache "${monitor_set}.v4")"
allow_v6="$(nft_cache "${monitor_set}.v6")"
block_v4="$(nft_cache blocklist.v4)"
block_v6="$(nft_cache blocklist.v6)"
@@ -2813,7 +2895,7 @@ 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
if "${ban_nftcmd}" get element inet banIP "${monitor_set}${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=""
@@ -2821,7 +2903,7 @@ f_monitor() {
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"
f_log "debug" "f_monitor ::: skip IP '${ip}', found via ${monitor_set}${proto} CIDR lookup"
continue
fi
+14 -22
View File
@@ -46,39 +46,31 @@ f_log "info" "start banIP download processes"
f_getfeed
[ "${ban_deduplicate}" = "1" ] && printf '\n' >"${ban_tmpfile}.deduplicate"
# handle allowlistonly mode
#
if [ "${ban_allowlistonly}" = "1" ] && [ "${ban_monitorallowed}" = "1" ]; then
ban_monitorfeed="allowlist.local"
fi
# handle downloads
#
cnt="1"
for feed in allowlist ${ban_feed} blocklist; do
for feed in allowlist ${ban_monitorfeed} ${ban_feed} blocklist; do
# local feeds (sequential processing)
#
if [ "${feed}" = "allowlist" ] || [ "${feed}" = "blocklist" ]; then
if [ "${feed%%.*}" = "allowlist" ] || [ "${feed}" = "blocklist" ]; then
for proto in 4MAC 6MAC 4 6; do
f_down "${feed}" "${proto}" "-" "-" "inout"
chain="inout"
if [ "${feed}" = "allowlist.local" ]; then
case "${proto}" in *MAC) continue ;; esac
chain="none"
fi
f_down "${feed}" "${proto}" "-" "-" "${chain}"
done
continue
fi
# skip external feeds in allowlistonly mode
#
if [ "${ban_allowlistonly}" = "1" ]; then
case " ${ban_feedin} " in
*" allowlist "*) ;;
*)
case " ${ban_feedout} " in
*" allowlist "*) ;;
*)
f_log "info" "skip feed '${feed}' in allowlistonly mode"
continue
;;
esac
;;
esac
fi
# external feeds (parallel processing on multicore hardware)
#
if ! json_select "${feed}" >/dev/null 2>&1; then