mirror of
https://github.com/openwrt/packages.git
synced 2026-10-13 03:37:43 +04:00
banip: update 1.9.0-2
* use RDAP startAddress/endAddress as a single interval element (one nft call per lookup)
* validate RDAP ranges, block nft command and log line injection
* always restart the procd instance (unique nonce via env)
* restart the log monitor if the log reader terminates (e.g. logd restart)
* f_rmpid clears the pidfile before killing child processes
* EXIT trap: route unexpected service exits through f_log "err"
* readme update
Signed-off-by: Dirk Brenken <dev@brenken.org>
(cherry picked from commit 4a69a0b767)
This commit is contained in:
5 files changed
+54
-30
No files matched your search
+1
-1
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=banip
|
||||
PKG_VERSION:=1.9.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
PKG_LICENSE:=GPL-3.0-or-later
|
||||
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
|
||||
|
||||
|
||||
@@ -453,6 +453,7 @@ You find the `Log Terms` option in LuCI under the `Log Settings` tab. Feel free
|
||||
**Allow-/Blocklist handling**
|
||||
banIP supports local allow- and block-lists, MAC/IPv4/IPv6 addresses (incl. ranges in CIDR notation) or domain names. These files are located in /etc/banip/banip.allowlist and /etc/banip/banip.blocklist.
|
||||
Unsuccessful login attempts or suspicious requests will be tracked and added to the local blocklist (see the `ban_autoblocklist` option). The blocklist behaviour can be further tweaked with the `ban_nftexpiry` option.
|
||||
Elements added by the log monitor, including the RDAP ranges of an offending address, expire after `ban_nftexpiry`, but every new hit within an existing range resets its timeout. As the Sets use `auto-merge`, overlapping or adjacent ranges are also combined into a single larger element. A network under continuous attack can therefore stay in the blocklist far beyond the configured expiry and grow over time - this is intended behaviour, not a stale entry.
|
||||
Depending on the options `ban_autoallowlist` and `ban_autoallowuplink` the uplink subnet or the uplink IP will be added automatically to local allowlist.
|
||||
Entries in CIDR notation always refer to the whole network - set host bits are masked by nftables, e.g. `192.168.1.5/24` ends up as `192.168.1.0/24` in the Set and `2001:db8::e65f:1:2:3/64` as `2001:db8::/64`. To allow or block a single host omit the prefix length or use /32 resp. /128.
|
||||
Furthermore, you can reference external Allowlist URLs with additional IPv4 and IPv6 feeds (see `ban_allowurl`).
|
||||
|
||||
@@ -261,9 +261,8 @@ f_trim() {
|
||||
f_rmpid() {
|
||||
local ppid pid pids_next pids_all childs newchilds
|
||||
|
||||
# kill all descendant processes of the pid in pidfile
|
||||
#
|
||||
ppid="$("${ban_catcmd}" "${ban_pidfile}" 2>>"${ban_errorlog}")"
|
||||
: >"${ban_pidfile}"
|
||||
if [ -n "${ppid}" ]; then
|
||||
pids_next="$("${ban_pgrepcmd}" -P "${ppid}" 2>>"${ban_errorlog}")"
|
||||
pids_all=""
|
||||
@@ -288,7 +287,6 @@ f_rmpid() {
|
||||
kill -INT "${pid}" >/dev/null 2>&1
|
||||
done
|
||||
fi
|
||||
: >"${ban_pidfile}"
|
||||
}
|
||||
|
||||
# write log messages
|
||||
@@ -2848,10 +2846,19 @@ f_mail() {
|
||||
f_log "debug" "f_mail ::: notification: ${ban_mailnotification}, template: ${ban_mailtemplate}, profile: ${ban_mailprofile}, receiver: ${ban_mailreceiver}, rc: ${?}"
|
||||
}
|
||||
|
||||
# handle unexpected service exits
|
||||
#
|
||||
f_exit() {
|
||||
trap - EXIT
|
||||
if [ "$("${ban_catcmd}" "${ban_pidfile}" 2>/dev/null)" = "${$}" ]; then
|
||||
f_log "err" "banIP service terminated unexpectedly"
|
||||
fi
|
||||
}
|
||||
|
||||
# log monitor
|
||||
#
|
||||
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 nft_expiry ip proto rdap_log rdap_rc rdap_start rdap_end rdap_range rdap_regex 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 monitor_set
|
||||
|
||||
@@ -3131,34 +3138,40 @@ f_monitor() {
|
||||
# process RDAP response if valid JSON with expected content, otherwise log error
|
||||
#
|
||||
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_start="$("${ban_jsoncmd}" -i "${ban_rdapfile}.${ip}" -qe '@.startAddress')"
|
||||
rdap_end="$("${ban_jsoncmd}" -i "${ban_rdapfile}.${ip}" -qe '@.endAddress')"
|
||||
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
|
||||
# if RDAP response contains a valid address range (RFC 9083 startAddress/endAddress),
|
||||
# add the entire range as a single interval element to blocklist set with same expiry as individual IP
|
||||
#
|
||||
base=""
|
||||
for idx in ${rdap_idx}; do
|
||||
if [ -z "${base}" ]; then
|
||||
base="${idx}"
|
||||
continue
|
||||
else
|
||||
case "${base}" in
|
||||
"" | "::"* | "127."* | "0."* | "fe80:"*)
|
||||
base=""
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
[ -z "${base}" ] && continue
|
||||
cidr="${base}/${idx}"
|
||||
if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" { ${cidr} ${nft_expiry} } >/dev/null 2>&1; then
|
||||
f_log "info" "add IP range '${cidr}' (source: ${rdap_info:-"n/a"} ::: expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set"
|
||||
fi
|
||||
base=""
|
||||
rdap_range=""
|
||||
rdap_regex=""
|
||||
case "${rdap_start}-${rdap_end}" in
|
||||
"-"* | "::"* | "127."* | "0."* | "fe80:"* | *[!0-9A-Fa-f.:-]*) ;;
|
||||
*)
|
||||
if [ "${proto}" = ".v4" ]; then
|
||||
rdap_regex='^[0-9]{1,3}(\.[0-9]{1,3}){3}-[0-9]{1,3}(\.[0-9]{1,3}){3}$'
|
||||
elif [ "${proto}" = ".v6" ]; then
|
||||
rdap_regex='^[0-9A-Fa-f:]*:[0-9A-Fa-f:]*-[0-9A-Fa-f:]*:[0-9A-Fa-f:]*$'
|
||||
fi
|
||||
done
|
||||
if [ -n "${rdap_regex}" ]; then
|
||||
printf '%s' "${rdap_start}-${rdap_end}" | "${ban_grepcmd}" -qE "${rdap_regex}" && rdap_range="${rdap_start}-${rdap_end}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if [ -n "${rdap_range}" ]; then
|
||||
if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" { ${rdap_range} ${nft_expiry} } >/dev/null 2>&1; then
|
||||
f_log "info" "add IP range '${rdap_range}' (source: ${rdap_info:-"n/a"} ::: expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set"
|
||||
else
|
||||
f_log "info" "failed to add IP range '${rdap_range}' to blocklist${proto} set with rc '${?}'"
|
||||
fi
|
||||
else
|
||||
rdap_start="${rdap_start%%[!0-9A-Fa-f.:]*}"
|
||||
rdap_end="${rdap_end%%[!0-9A-Fa-f.:]*}"
|
||||
f_log "info" "no valid rdap range (start: ${rdap_start:-"-"}/end: ${rdap_end:-"-"}) for IP '${ip}'"
|
||||
fi
|
||||
else
|
||||
f_log "info" "rdap request failed (rc: ${rdap_rc:-"-"}/log: ${rdap_log:-"-"}) for IP '${ip}'"
|
||||
fi
|
||||
|
||||
@@ -11,6 +11,7 @@ read -r ban_starttime _ <"/proc/uptime"
|
||||
ban_starttime="${ban_starttime%%.*}"
|
||||
ban_funlib="/usr/lib/banip-functions.sh"
|
||||
[ -z "${ban_bver}" ] && . "${ban_funlib}"
|
||||
trap 'f_exit' EXIT
|
||||
|
||||
# load config and set banIP environment
|
||||
#
|
||||
@@ -186,6 +187,13 @@ f_log "info" "finish banIP processing"
|
||||
rm -rf "${ban_lock}"
|
||||
) &
|
||||
|
||||
# start detached log service (infinite loop)
|
||||
# start detached log service (infinite loop),
|
||||
# restart the monitor if the log reader terminates (e.g. logd restart),
|
||||
# stop if the pidfile has been cleared by f_rmpid
|
||||
#
|
||||
f_monitor
|
||||
while :; do
|
||||
f_monitor
|
||||
sleep 5
|
||||
[ "$("${ban_catcmd}" "${ban_pidfile}" 2>/dev/null)" = "${$}" ] || break
|
||||
f_log "info" "log reader terminated, restart detached banIP log service"
|
||||
done
|
||||
@@ -66,8 +66,10 @@ start_service() {
|
||||
fi
|
||||
fi
|
||||
f_rmpid
|
||||
read -r ban_nonce _ <"/proc/uptime"
|
||||
procd_open_instance "banip-service"
|
||||
procd_set_param command "${ban_service}" "${action}"
|
||||
procd_set_param env ban_nonce="${ban_nonce}"
|
||||
procd_set_param pidfile "${ban_pidfile}"
|
||||
procd_set_param nice "$(uci_get banip global ban_nicelimit "0")"
|
||||
procd_set_param limits nofile="$(uci_get banip global ban_filelimit "1024")"
|
||||
|
||||
Reference in new issue
Block a user