From: Dirk Brenken Date: Tue, 8 Sep 2026 15:58:17 +0000 (+0200) Subject: banip: release 1.8.13 X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=aca7007595f4a5d468938cf8e1fea889ba7b5067;p=openwrt-packages.git banip: release 1.8.13 - f_getup() collects the wan state in one pass and diffs the uplink against the local allowlist - new f_refresh() patches only the changed allowlist Set elements in a single atomic nft transaction, without touching the running instance - the procd trigger calls start refresh, start_service() picks the path, a manual start is unaffected - wan6 in ban_trigger is supported now - updatted the README and moved to the package root - LuCI: reworked the feed editor, get rid of custom css Signed-off-by: Dirk Brenken dev@brenken.org Signed-off-by: Dirk Brenken --- diff --git a/net/banip/Makefile b/net/banip/Makefile index cb4a1f625..30ce292bc 100644 --- a/net/banip/Makefile +++ b/net/banip/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=banip -PKG_VERSION:=1.8.12 -PKG_RELEASE:=3 +PKG_VERSION:=1.8.13 +PKG_RELEASE:=1 PKG_LICENSE:=GPL-3.0-or-later PKG_MAINTAINER:=Dirk Brenken @@ -23,7 +23,7 @@ endef define Package/banip/description banIP blocks IPs via named nftables Sets. banIP supports many IP blocklist feeds and provides a log service to block suspicious IPs in realtime. -Please see https://github.com/openwrt/packages/blob/master/net/banip/files/README.md for further information. +Please see https://github.com/openwrt/packages/blob/master/net/banip/README.md for further information. endef diff --git a/net/banip/files/README.md b/net/banip/README.md similarity index 99% rename from net/banip/files/README.md rename to net/banip/README.md index b53078221..373033fab 100644 --- a/net/banip/files/README.md +++ b/net/banip/README.md @@ -25,7 +25,7 @@ IP address blocking is commonly used to protect against brute force attacks, pre ## Quick Start For a typical setup these few steps are enough to get banIP up and running — see the sections below for details: 1. Install the LuCI companion package: `apk update && apk add luci-app-banip` (this pulls in the `banip` backend as a dependency). -2. Open LuCI under `Services → banIP`, tick `Enabled` and (recommended) set a `Startup Trigger Interface` to your WAN interface (avoid IPv6/wan6). +2. Open LuCI under `Services → banIP`, tick `Enabled` and (recommended) set a `Startup Trigger Interface` to your WAN interface(s). 3. Activate a small, sensible feed selection to start with, e.g. `cinsscore`, `debl`, `turris` and `doh` in their default chains (≈20K IPs). 4. Start and verify the service: @@ -147,7 +147,7 @@ For a typical setup these few steps are enough to get banIP up and running — s * Install the LuCI companion package `luci-app-banip` which also installs the main banIP package as a dependency * Enable the banIP system service (System -> Startup) and enable banIP itself (banIP -> General Settings) * It's strongly recommended to use the LuCI frontend to easily configure all aspects of banIP, the application is located in LuCI under the `Services` menu -* It's also recommended to configure a `Startup Trigger Interface` to depend on your WAN ifup events during boot or restart of your router. Avoid IPv6 (wan6) interfaces here, as IPv6/netifd is chatty and would trigger frequent unnecessary banIP restarts +* It's also recommended to configure a `Startup Trigger Interface` to depend on your WAN interface events during boot or restart of your router. Listing IPv6 interfaces (wan6) is fine as well: an interface event that only changed the uplink addresses refreshes the auto-allowed uplink entries in place, without a full banIP restart. This keeps the allowlist in sync with a dynamic IPv6 prefix * To be able to use banIP in a meaningful way, you must activate the service and possibly also activate a few blocklist feeds * If you're using a complex network setup, e.g. special tunnel interfaces, then untick the `Auto Detection` option under the `General Settings` tab and set the required options manually * Start the service with `/etc/init.d/banip start` and check everything is working by running `/etc/init.d/banip status`, also check the `Processing Log` tab @@ -220,7 +220,7 @@ The `report` sub-command accepts an output mode: `text` (default, human-readable | ban_dev | list | - / autodetect | wan device(s), e.g. `eth2` | | ban_vlanallow | list | - | always allow certain VLAN forwards, e.g. br-lan.20 | | ban_vlanblock | list | - | always block certain VLAN forwards, e.g. br-lan.10 | -| ban_trigger | list | - | logical reload trigger interface(s), e.g. `wan` (avoid IPv6 interfaces) | +| ban_trigger | list | - | logical reload trigger interface(s), e.g. `wan` and `wan6` | | ban_triggerdelay | option | 20 | trigger timeout during interface reload and boot | | ban_deduplicate | option | 1 | deduplicate IP addresses across all active Sets (see optional feed flag `dup` below) | | ban_splitsize | option | 0 | split the processing/loading of Sets in chunks of n lines/members (saves RAM) | diff --git a/net/banip/files/banip-functions.sh b/net/banip/files/banip-functions.sh index 80d9a4e70..2565612ae 100644 --- a/net/banip/files/banip-functions.sh +++ b/net/banip/files/banip-functions.sh @@ -92,6 +92,9 @@ ban_dev="" ban_vlanallow="" ban_vlanblock="" ban_uplink="" +ban_uplink_add="" +ban_uplink_del="" +ban_devup="" ban_fetchcmd="" ban_fetchparm="" ban_fetchinsecure="" @@ -721,59 +724,170 @@ f_getdev() { # get local uplink # f_getup() { - local uplink iface timestamp ip + local uplink dev iface timestamp ip old + + ban_uplink="" + ban_uplink_add="" + ban_uplink_del="" + ban_devup="" + + # single pass over the wan interfaces, collects the current + # devices and uplink addresses + # + network_flush_cache + for iface in ${ban_ifv4} ${ban_ifv6}; do + network_get_device dev "${iface}" + if [ -n "${dev}" ]; then + case " ${ban_devup} " in + *" ${dev} "*) ;; + + *) + ban_devup="${ban_devup}${dev} " + ;; + esac + fi + [ "${ban_autoallowlist}" = "1" ] && [ "${ban_autoallowuplink}" != "disable" ] || continue + if [ "${ban_autoallowuplink}" = "subnet" ]; then + network_get_subnet uplink "${iface}" + elif [ "${ban_autoallowuplink}" = "ip" ]; then + network_get_ipaddr uplink "${iface}" + fi + if [ -n "${uplink}" ]; then + case " ${ban_uplink} " in + *" ${uplink} "*) ;; + + *) + ban_uplink="${ban_uplink}${uplink} " + ;; + esac + fi + if [ "${ban_autoallowuplink}" = "subnet" ]; then + network_get_subnet6 uplink "${iface}" + elif [ "${ban_autoallowuplink}" = "ip" ]; then + network_get_ipaddr6 uplink "${iface}" + fi + if [ -n "${uplink%fe80::*}" ]; then + case " ${ban_uplink} " in + *" ${uplink} "*) ;; + + *) + ban_uplink="${ban_uplink}${uplink} " + ;; + esac + fi + done + ban_uplink="$(f_trim "${ban_uplink}")" if [ "${ban_autoallowlist}" = "1" ] && [ "${ban_autoallowuplink}" != "disable" ]; then - for iface in ${ban_ifv4} ${ban_ifv6}; do - network_flush_cache - if [ "${ban_autoallowuplink}" = "subnet" ]; then - network_get_subnet uplink "${iface}" - elif [ "${ban_autoallowuplink}" = "ip" ]; then - network_get_ipaddr uplink "${iface}" - fi - if [ -n "${uplink}" ]; then + # compare the detected uplink with the local allowlist and + # track the differences for an in-place refresh (see f_refresh) + # + if [ -n "${ban_uplink}" ]; then + for ip in $("${ban_sedcmd}" -n "/# uplink added on /s/[[:space:]].*$//p" "${ban_allowlist}" 2>/dev/null); do + old="${old}${ip} " + done + for ip in ${old}; do case " ${ban_uplink} " in - *" ${uplink} "*) ;; + *" ${ip} "*) ;; *) - ban_uplink="${ban_uplink}${uplink} " + ban_uplink_del="${ban_uplink_del}${ip} " ;; esac - fi - if [ "${ban_autoallowuplink}" = "subnet" ]; then - network_get_subnet6 uplink "${iface}" - elif [ "${ban_autoallowuplink}" = "ip" ]; then - network_get_ipaddr6 uplink "${iface}" - fi - if [ -n "${uplink%fe80::*}" ]; then - case " ${ban_uplink} " in - *" ${uplink} "*) ;; + done + for ip in ${ban_uplink}; do + case " ${old} " in + *" ${ip} "*) ;; *) - ban_uplink="${ban_uplink}${uplink} " + ban_uplink_add="${ban_uplink_add}${ip} " ;; esac - fi - done - ban_uplink="$(f_trim "${ban_uplink}")" - for ip in ${ban_uplink}; do - if ! "${ban_grepcmd}" -q "${ip} " "${ban_allowlist}"; then + done + if [ -n "${ban_uplink_add}" ] || [ -n "${ban_uplink_del}" ]; then "${ban_sedcmd}" -i "/# uplink added on /d" "${ban_allowlist}" - break - fi - done - timestamp="$(date "+%Y-%m-%d %H:%M:%S")" - for ip in ${ban_uplink}; do - if ! "${ban_grepcmd}" -q "${ip} " "${ban_allowlist}"; then - printf '%-45s%s\n' "${ip}" "# uplink added on ${timestamp}" >>"${ban_allowlist}" - f_log "info" "add uplink '${ip}' to local allowlist" + timestamp="$(date "+%Y-%m-%d %H:%M:%S")" + for ip in ${ban_uplink}; do + printf '%-45s%s\n' "${ip}" "# uplink added on ${timestamp}" >>"${ban_allowlist}" + done + for ip in ${ban_uplink_add}; do + f_log "info" "add uplink '${ip}' to local allowlist" + done + for ip in ${ban_uplink_del}; do + f_log "info" "remove uplink '${ip}' from local allowlist" + done fi - done + fi elif [ "${ban_autoallowlist}" = "1" ] && [ "${ban_autoallowuplink}" = "disable" ]; then - "${ban_sedcmd}" -i "/# uplink added on /d" "${ban_allowlist}" + if "${ban_grepcmd}" -q "# uplink added on " "${ban_allowlist}"; then + "${ban_sedcmd}" -i "/# uplink added on /d" "${ban_allowlist}" + fi fi - f_log "debug" "f_getup ::: auto-allow/auto-uplink: ${ban_autoallowlist}/${ban_autoallowuplink}, uplink: ${ban_uplink:-"-"}" + f_log "debug" "f_getup ::: auto-allow/auto-uplink: ${ban_autoallowlist}/${ban_autoallowuplink}, devices: ${ban_devup:-"-"}, uplink: ${ban_uplink:-"-"}, add/remove: ${ban_uplink_add:-"-"}/${ban_uplink_del:-"-"}" +} + +# refresh the wan state in place, triggered by an interface event +# return 0 if handled, 1 to escalate to a full service run +# +f_refresh() { + local dev ip addv4 addv6 delv4 delv6 set_list set_name + + # require an initialized nft namespace + # + "${ban_nftcmd}" list chain inet banIP pre-routing >/dev/null 2>&1 || return 1 + + f_getup + + # escalate on new or renamed wan devices, the rulesets match on + # ban_dev - a device that is merely gone means the interface is + # currently down, that is handled by the uplink diff below + # + for dev in ${ban_devup}; do + case " ${ban_dev} " in + *" ${dev} "*) ;; + + *) + return 1 + ;; + esac + done + [ -z "${ban_uplink_add}" ] && [ -z "${ban_uplink_del}" ] && return 0 + + # update the allowlist Sets in a single atomic transaction, + # a rejected batch escalates to a full run + # + for ip in ${ban_uplink_del}; do + if [ "${ip##*:}" = "${ip}" ]; then + delv4="${delv4}${ip}, " + else + delv6="${delv6}${ip}, " + fi + done + for ip in ${ban_uplink_add}; do + if [ "${ip##*:}" = "${ip}" ]; then + addv4="${addv4}${ip}, " + else + addv6="${addv6}${ip}, " + fi + done + set_list="allowlist" + if [ "${ban_allowlistonly}" = "1" ] && [ "${ban_monitorallowed}" = "1" ]; then + set_list="${set_list} allowlist.local" + fi + if ! { + for set_name in ${set_list}; do + [ -n "${delv4}" ] && printf 'delete element inet banIP %s.v4 { %s }\n' "${set_name}" "${delv4%, }" + [ -n "${delv6}" ] && printf 'delete element inet banIP %s.v6 { %s }\n' "${set_name}" "${delv6%, }" + [ -n "${addv4}" ] && printf 'add element inet banIP %s.v4 { %s }\n' "${set_name}" "${addv4%, }" + [ -n "${addv6}" ] && printf 'add element inet banIP %s.v6 { %s }\n' "${set_name}" "${addv6%, }" + done + } | "${ban_nftcmd}" -f - >/dev/null 2>&1; then + return 1 + fi + + f_log "debug" "f_refresh ::: devices: ${ban_devup}, uplink: ${ban_uplink}" + return 0 } # get feed information diff --git a/net/banip/files/banip.init b/net/banip/files/banip.init index fd128e75f..3ae275a3f 100755 --- a/net/banip/files/banip.init +++ b/net/banip/files/banip.init @@ -58,9 +58,16 @@ boot() { start_service() { if "${ban_init}" enabled; then + if [ "${1}" = "refresh" ]; then + f_conf + if f_refresh; then + rm -rf "${ban_lock}" + return 0 + fi + fi f_rmpid procd_open_instance "banip-service" - procd_set_param command "${ban_service}" "${@:-"${action}"}" + procd_set_param command "${ban_service}" "${action}" 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")" @@ -122,6 +129,6 @@ service_triggers() { PROCD_RELOAD_DELAY="$((delay * 1000))" for iface in ${trigger}; do - procd_add_interface_trigger "interface.*.up" "${iface}" "${ban_init}" start + procd_add_interface_trigger "interface.*" "${iface}" "${ban_init}" start refresh done }