From 5af101564a9f889807e0e2762934e03cb0259eb1 Mon Sep 17 00:00:00 2001 From: Dirk Brenken Date: Thu, 28 Dec 2023 17:56:38 +0100 Subject: [PATCH] banip: update 0.9.3-2 * rework the device/interface auto-detection (only layer-3 network devices will be detetcted correctly), disable the auto-detection e.g. for special tunnel interfaces * supports now full gawk (preferred, if installed) and busybox awk * raise the default boot timeout to 20 seconds (if 'ban_triggerdelay' is not set) * various small fixes and improvements * readme update Signed-off-by: Dirk Brenken --- net/banip/Makefile | 2 +- net/banip/files/README.md | 3 +- net/banip/files/banip-functions.sh | 176 +++++++++++++++++------------ net/banip/files/banip-service.sh | 4 +- net/banip/files/banip.init | 15 +-- net/banip/files/banip.tpl | 16 ++- 6 files changed, 126 insertions(+), 90 deletions(-) diff --git a/net/banip/Makefile b/net/banip/Makefile index 00803da00..4a6458f00 100644 --- a/net/banip/Makefile +++ b/net/banip/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=banip PKG_VERSION:=0.9.3 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_LICENSE:=GPL-3.0-or-later PKG_MAINTAINER:=Dirk Brenken diff --git a/net/banip/files/README.md b/net/banip/files/README.md index 299a2cae8..c38f94b94 100644 --- a/net/banip/files/README.md +++ b/net/banip/files/README.md @@ -106,8 +106,9 @@ IP address blocking is commonly used to protect against brute force attacks, pre * Install banIP (_opkg install banip_) - the banIP service is disabled by default * Install the LuCI companion package 'luci-app-banip' (opkg install luci-app-banip) * 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 +* If you're using a complex network setup, e.g. special tunnel interfaces, than 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' and also check the 'Firewall Log' and 'Processing Log' tabs * If you're going to configure banIP via CLI, edit the config file '/etc/config/banip' and enable the service (set ban\_enabled to '1'), then add pre-configured feeds via 'ban\_feed' (see the feed list above) and add/change other options to your needs (see the options reference below) -* Start the service with '/etc/init.d/banip start' and check everything is working by running '/etc/init.d/banip status' ## banIP CLI interface * All important banIP functions are accessible via CLI. diff --git a/net/banip/files/banip-functions.sh b/net/banip/files/banip-functions.sh index f075eb6b1..cddb3ab5b 100644 --- a/net/banip/files/banip-functions.sh +++ b/net/banip/files/banip-functions.sh @@ -5,11 +5,13 @@ # (s)hellcheck exceptions # shellcheck disable=all -# set initial defaults +# environment # export LC_ALL=C export PATH="/usr/sbin:/usr/bin:/sbin:/bin" +# initial defaults +# ban_basedir="/tmp" ban_backupdir="/tmp/banIP-backup" ban_reportdir="/tmp/banIP-report" @@ -25,18 +27,6 @@ ban_rdapurl="https://rdap.db.ripe.net/ip/" ban_lock="/var/run/banip.lock" ban_logreadfile="/var/log/messages" ban_logreadcmd="" -ban_logcmd="$(command -v logger)" -ban_ubuscmd="$(command -v ubus)" -ban_nftcmd="$(command -v nft)" -ban_fw4cmd="$(command -v fw4)" -ban_awkcmd="$(command -v awk)" -ban_grepcmd="$(command -v grep)" -ban_sedcmd="$(command -v sed)" -ban_catcmd="$(command -v cat)" -ban_zcatcmd="$(command -v zcat)" -ban_lookupcmd="$(command -v nslookup)" -ban_jsoncmd="$(command -v jsonfilter)" -ban_mailcmd="$(command -v msmtp)" ban_mailsender="no-reply@banIP" ban_mailreceiver="" ban_mailtopic="banIP notification" @@ -103,7 +93,7 @@ f_system() { ban_debug="$(uci_get banip global ban_debug)" ban_cores="$(uci_get banip global ban_cores)" fi - ban_packages="$(${ban_ubuscmd} -S call rpc-sys packagelist '{ "all": true }' 2>/dev/null)" + ban_packages="$("${ban_ubuscmd}" -S call rpc-sys packagelist '{ "all": true }' 2>/dev/null)" ban_memory="$("${ban_awkcmd}" '/^MemAvailable/{printf "%s",int($2/1000)}' "/proc/meminfo" 2>/dev/null)" ban_ver="$(printf "%s" "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages.banip')" ban_sysver="$("${ban_ubuscmd}" -S call system board 2>/dev/null | "${ban_jsoncmd}" -ql1 -e '@.model' -e '@.release.description' | @@ -117,6 +107,23 @@ f_system() { fi } +# command selector +# +f_cmd() { + local cmd pri_cmd="${1}" sec_cmd="${2}" + + cmd="$(command -v "${pri_cmd}" 2>/dev/null)" + if [ ! -x "${cmd}" ]; then + if [ -n "${sec_cmd}" ]; then + [ "${sec_cmd}" = "true" ] && return + cmd="$(command -v "${sec_cmd}" 2>/dev/null)" + fi + [ -x "${cmd}" ] && printf "%s" "${cmd}" || f_log "emerg" "command '${pri_cmd:-"-"}'/'${sec_cmd:-"-"}' not found" + else + printf "%s" "${cmd}" + fi +} + # create directories # f_mkdir() { @@ -192,9 +199,9 @@ f_rmpid() { ppid="$("${ban_catcmd}" "${ban_pidfile}" 2>/dev/null)" if [ -n "${ppid}" ]; then - pids="$(pgrep -P "${ppid}" 2>/dev/null)" + pids="$("${ban_pgrepcmd}" -P "${ppid}" 2>/dev/null)" for pid in ${pids}; do - pids="${pids} $(pgrep -P "${pid}" 2>/dev/null)" + pids="${pids} $("${ban_pgrepcmd}" -P "${pid}" 2>/dev/null)" done for pid in ${pids}; do kill -INT "${pid}" >/dev/null 2>&1 @@ -216,13 +223,15 @@ f_log() { printf "%s %s %s\n" "${class}" "banIP-${ban_ver}[${$}]" "${log_msg}" fi fi - if [ "${class}" = "err" ]; then - "${ban_nftcmd}" delete table inet banIP >/dev/null 2>&1 - if [ "${ban_enabled}" = "1" ]; then - f_genstatus "error" - [ "${ban_mailnotification}" = "1" ] && [ -n "${ban_mailreceiver}" ] && [ -x "${ban_mailcmd}" ] && f_mail - else - f_genstatus "disabled" + if [ "${class}" = "err" ] || [ "${class}" = "emerg" ]; then + if [ "${class}" = "err" ]; then + "${ban_nftcmd}" delete table inet banIP >/dev/null 2>&1 + if [ "$(uci_get banip global ban_enabled)" = "1" ]; then + f_genstatus "error" + [ "${ban_mailnotification}" = "1" ] && [ -n "${ban_mailreceiver}" ] && [ -x "${ban_mailcmd}" ] && f_mail + else + f_genstatus "disabled" + fi fi f_rmdir "${ban_tmpdir}" f_rmpid @@ -297,7 +306,7 @@ f_conf() { # get nft/monitor actuals # f_actual() { - local nft monitor ppid pid + local nft monitor ppid pids pid if "${ban_nftcmd}" -t list set inet banIP allowlistv4MAC >/dev/null 2>&1; then nft="$(f_char "1")" @@ -307,10 +316,15 @@ f_actual() { ppid="$("${ban_catcmd}" "${ban_pidfile}" 2>/dev/null)" if [ -n "${ppid}" ]; then - pid="$(pgrep -oP "${ppid}" 2>/dev/null)" - fi - if pgrep -f "${ban_logreadcmd##*/}" -P "${pid}" >/dev/null 2>&1; then - monitor="$(f_char "1")" + pids="$("${ban_pgrepcmd}" -P "${ppid}" 2>/dev/null)" + for pid in ${pids}; do + if "${ban_pgrepcmd}" -f "${ban_logreadcmd##*/}" -P "${pid}" >/dev/null 2>&1; then + monitor="$(f_char "1")" + break + else + monitor="$(f_char "0")" + fi + done else monitor="$(f_char "0")" fi @@ -325,9 +339,7 @@ f_getfetch() { if { [ "${ban_fetchcmd}" = "uclient-fetch" ] && printf "%s" "${ban_packages}" | "${ban_grepcmd}" -q '"libustream-'; } || { [ "${ban_fetchcmd}" = "wget" ] && printf "%s" "${ban_packages}" | "${ban_grepcmd}" -q '"wget-ssl'; } || [ "${ban_fetchcmd}" = "curl" ] || [ "${ban_fetchcmd}" = "aria2c" ]; then - ban_fetchcmd="$(command -v "${ban_fetchcmd}")" - else - ban_fetchcmd="" + ban_fetchcmd="$(f_cmd "${ban_fetchcmd}" "true")" fi if [ "${ban_autodetect}" = "1" ] && [ ! -x "${ban_fetchcmd}" ]; then @@ -380,44 +392,47 @@ f_getfetch() { # get wan interfaces # f_getif() { - local iface update="0" + local iface iface_del update="0" if [ "${ban_autodetect}" = "1" ]; then - if [ -z "${ban_ifv4}" ]; then - network_flush_cache - network_find_wan iface - if [ -n "${iface}" ] && "${ban_ubuscmd}" -t 10 wait_for network.interface."${iface}" >/dev/null 2>&1; then - ban_protov4="1" - ban_ifv4="${iface}" - uci_set banip global ban_protov4 "1" - uci_add_list banip global ban_ifv4 "${iface}" - f_log "info" "add IPv4 interface '${iface}' to config" - fi + network_flush_cache + network_find_wan iface + if [ -n "${iface}" ] && [ "${iface}" != "$(f_trim "${ban_ifv4}")" ] && "${ban_ubuscmd}" -t 10 wait_for network.interface."${iface}" >/dev/null 2>&1; then + for iface_del in ${ban_ifv4}; do + uci_remove_list banip global ban_ifv4 "${iface_del}" + f_log "info" "remove IPv4 interface '${iface_del}' from config" + done + ban_protov4="1" + ban_ifv4="${iface}" + uci_set banip global ban_protov4 "1" + uci_add_list banip global ban_ifv4 "${iface}" + f_log "info" "add IPv4 interface '${iface}' to config" fi - if [ -z "${ban_ifv6}" ]; then - network_flush_cache - network_find_wan6 iface - if [ -n "${iface}" ] && "${ban_ubuscmd}" -t 10 wait_for network.interface."${iface}" >/dev/null 2>&1; then - ban_protov6="1" - ban_ifv6="${iface}" - uci_set banip global ban_protov6 "1" - uci_add_list banip global ban_ifv6 "${iface}" - f_log "info" "add IPv6 interface '${iface}' to config" - fi + network_find_wan6 iface + if [ -n "${iface}" ] && [ "${iface}" != "$(f_trim "${ban_ifv6}")" ] && "${ban_ubuscmd}" -t 10 wait_for network.interface."${iface}" >/dev/null 2>&1; then + for iface_del in ${ban_ifv6}; do + uci_remove_list banip global ban_ifv6 "${iface_del}" + f_log "info" "remove IPv6 interface '${iface_del}' from config" + done + ban_protov6="1" + ban_ifv6="${iface}" + uci_set banip global ban_protov6 "1" + uci_add_list banip global ban_ifv6 "${iface}" + f_log "info" "add IPv6 interface '${iface}' to config" fi fi if [ -n "$(uci -q changes "banip")" ]; then update="1" uci_commit "banip" else - ban_ifv4="${ban_ifv4%%?}" - ban_ifv6="${ban_ifv6%%?}" for iface in ${ban_ifv4} ${ban_ifv6}; do if ! "${ban_ubuscmd}" -t 10 wait_for network.interface."${iface}" >/dev/null 2>&1; then f_log "err" "no wan interface '${iface}'" fi done fi + ban_ifv4="$(f_trim "${ban_ifv4}")" + ban_ifv6="$(f_trim "${ban_ifv6}")" [ -z "${ban_ifv4}" ] && [ -z "${ban_ifv6}" ] && f_log "err" "no wan interfaces" f_log "debug" "f_getif ::: auto/update: ${ban_autodetect}/${update}, interfaces (4/6): ${ban_ifv4}/${ban_ifv6}, protocols (4/6): ${ban_protov4}/${ban_protov6}" @@ -426,31 +441,36 @@ f_getif() { # get wan devices # f_getdev() { - local dev iface update="0" cnt="0" cnt_max="30" + local dev dev_del iface update="0" if [ "${ban_autodetect}" = "1" ]; then - while [ "${cnt}" -lt "${cnt_max}" ] && [ -z "${ban_dev}" ]; do - network_flush_cache - for iface in ${ban_ifv4} ${ban_ifv6}; do - network_get_device dev "${iface}" - if [ -n "${dev}" ] && ! printf " %s " "${ban_dev}" | "${ban_grepcmd}" -q " ${dev} "; then + network_flush_cache + dev_del="${ban_dev}" + for iface in ${ban_ifv4} ${ban_ifv6}; do + network_get_device dev "${iface}" + if [ -n "${dev}" ]; then + dev_del="${dev_del/${dev} / }" + if ! printf " %s " "${ban_dev}" | "${ban_grepcmd}" -q " ${dev} "; then ban_dev="${ban_dev}${dev} " uci_add_list banip global ban_dev "${dev}" f_log "info" "add device '${dev}' to config" fi - done - cnt="$((cnt + 1))" - sleep 1 + fi + done + for dev in ${dev_del}; do + ban_dev="${ban_dev/${dev} / }" + uci_remove_list banip global ban_dev "${dev}" + f_log "info" "remove device '${dev}' from config" done fi if [ -n "$(uci -q changes "banip")" ]; then update="1" uci_commit "banip" fi - ban_dev="${ban_dev%%?}" + ban_dev="$(f_trim "${ban_dev}")" [ -z "${ban_dev}" ] && f_log "err" "no wan devices" - f_log "debug" "f_getdev ::: auto/update: ${ban_autodetect}/${update}, wan_devices: ${ban_dev}, cnt: ${cnt}" + f_log "debug" "f_getdev ::: auto/update: ${ban_autodetect}/${update}, wan_devices: ${ban_dev}" } # get local uplink @@ -488,7 +508,7 @@ f_getuplink() { update="1" fi done - ban_uplink="${ban_uplink%%?}" + ban_uplink="$(f_trim "${ban_uplink}")" elif [ "${ban_autoallowlist}" = "1" ] && [ "${ban_autoallowuplink}" = "disable" ]; then "${ban_sedcmd}" -i "/# uplink added on /d" "${ban_allowlist}" update="1" @@ -1090,7 +1110,7 @@ f_rmset() { } >"${tmp_del}" if [ -n "${del_set}" ]; then - del_set="${del_set%%??}" + del_set="$(f_trim "${del_set}")" feed_log="$("${ban_nftcmd}" -f "${tmp_del}" 2>&1)" feed_rc="${?}" fi @@ -1573,15 +1593,29 @@ if [ -r "/lib/functions.sh" ] && [ -r "/lib/functions/network.sh" ] && [ -r "/us . "/lib/functions/network.sh" . "/usr/share/libubox/jshn.sh" else - rm -rf "${ban_lock}" - exit 1 + f_log "emerg" "system libraries not found" fi -# check banIP availability +# initial system calls # -f_system +ban_awkcmd="$(f_cmd gawk awk)" +ban_catcmd="$(f_cmd cat)" +ban_fw4cmd="$(f_cmd fw4)" +ban_grepcmd="$(f_cmd grep)" +ban_jsoncmd="$(f_cmd jsonfilter)" +ban_logcmd="$(f_cmd logger)" +ban_lookupcmd="$(f_cmd nslookup)" +ban_mailcmd="$(f_cmd msmtp true)" +ban_nftcmd="$(f_cmd nft)" +ban_pgrepcmd="$(f_cmd pgrep)" +ban_sedcmd="$(f_cmd sed)" +ban_ubuscmd="$(f_cmd ubus)" +ban_zcatcmd="$(f_cmd zcat)" + if [ "${ban_action}" != "stop" ]; then [ ! -d "/etc/banip" ] && f_log "err" "no banIP config directory" [ ! -r "/etc/config/banip" ] && f_log "err" "no banIP config" [ "$(uci_get banip global ban_enabled)" = "0" ] && f_log "err" "banIP is disabled" fi + +f_system diff --git a/net/banip/files/banip-service.sh b/net/banip/files/banip-service.sh index 67b45bff5..3a40ab869 100755 --- a/net/banip/files/banip-service.sh +++ b/net/banip/files/banip-service.sh @@ -9,11 +9,11 @@ ban_action="${1}" ban_starttime="$(date "+%s")" ban_funlib="/usr/lib/banip-functions.sh" -[ -z "$(command -v "f_system")" ] && . "${ban_funlib}" +[ -z "${ban_ver}" ] && . "${ban_funlib}" # load config and set banIP environment # -[ "${ban_action}" = "boot" ] && sleep "$(uci_get banip global ban_triggerdelay "10")" +[ "${ban_action}" = "boot" ] && sleep "$(uci_get banip global ban_triggerdelay "20")" f_conf f_log "info" "start banIP processing (${ban_action})" f_log "debug" "f_system ::: system: ${ban_sysver:-"n/a"}, version: ${ban_ver:-"n/a"}, memory: ${ban_memory:-"0"}, cpu_cores: ${ban_cores}" diff --git a/net/banip/files/banip.init b/net/banip/files/banip.init index 4ef70e3d0..849bb894c 100755 --- a/net/banip/files/banip.init +++ b/net/banip/files/banip.init @@ -24,7 +24,8 @@ ban_lock="/var/run/banip.lock" { [ "${action}" = "stop" ] || [ "${action}" = "report" ] || [ "${action}" = "search" ] || [ "${action}" = "survey" ] || [ "${action}" = "lookup" ]; } && ! "${ban_init}" running && exit 0 [ ! -r "${ban_funlib}" ] && { [ "${action}" = "boot" ] || [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "stop" ] || [ "${action}" = "report" ] || [ "${action}" = "search" ] || [ "${action}" = "lookup" ] || [ "${action}" = "status" ]; } && exit 1 [ -d "${ban_lock}" ] && { [ "${action}" = "boot" ] || [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "lookup" ]; } && exit 1 -[ ! -d "${ban_lock}" ] && { [ "${action}" = "boot" ] || [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "lookup" ]; } && mkdir -p "${ban_lock}" +[ ! -d "${ban_lock}" ] && { [ "${action}" = "boot" ] || [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "lookup" ]; } && { mkdir -p "${ban_lock}"; . "${ban_funlib}"; } +[ ! -d "${ban_lock}" ] && { [ "${action}" = "boot" ] || [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "lookup" ]; } && exit 1 boot() { : >"${ban_pidfile}" @@ -32,7 +33,6 @@ boot() { } start_service() { - [ -z "$(command -v "f_system")" ] && . "${ban_funlib}" if "${ban_init}" enabled; then f_rmpid procd_open_instance "banip-service" @@ -50,13 +50,12 @@ start_service() { } reload_service() { - [ -z "$(command -v "f_system")" ] && . "${ban_funlib}" f_rmpid rc_procd start_service "reload" } stop_service() { - [ -z "$(command -v "f_system")" ] && . "${ban_funlib}" + [ -z "${ban_ver}" ] && . "${ban_funlib}" "${ban_nftcmd}" delete table inet banIP >/dev/null 2>&1 f_genstatus "stopped" f_rmpid @@ -73,29 +72,25 @@ status() { } status_service() { - [ -z "$(command -v "f_system")" ] && . "${ban_funlib}" + . "${ban_funlib}" f_getstatus } report() { - [ -z "$(command -v "f_system")" ] && . "${ban_funlib}" f_report "${1:-"text"}" } search() { - [ -z "$(command -v "f_system")" ] && . "${ban_funlib}" f_search "${1}" } survey() { - [ -z "$(command -v "f_system")" ] && . "${ban_funlib}" f_survey "${1}" } lookup() { local list hold cnt="1" - [ -z "$(command -v "f_system")" ] && . "${ban_funlib}" for list in allowlist blocklist; do (f_lookup "${list}") & hold="$((cnt % ban_cores))" @@ -109,7 +104,7 @@ lookup() { service_triggers() { local iface trigger delay - delay="$(uci_get banip global ban_triggerdelay "10")" + delay="$(uci_get banip global ban_triggerdelay "20")" trigger="$(uci_get banip global ban_trigger)" PROCD_RELOAD_DELAY="$((delay * 1000))" diff --git a/net/banip/files/banip.tpl b/net/banip/files/banip.tpl index 18b06faf8..2b3c20ff2 100644 --- a/net/banip/files/banip.tpl +++ b/net/banip/files/banip.tpl @@ -4,14 +4,20 @@ # info preparation # -local banip_info report_info log_info system_info mail_text +local banip_info report_info log_info system_info mail_text logread_cmd -banip_info="$(/etc/init.d/banip status 2>/dev/null | awk '{NR=1;max=160;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max)}else{print substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')" -report_info="$(cat ${ban_reportdir}/ban_report.txt 2>/dev/null)" -log_info="$("${ban_logreadcmd}" -l 100 -e "banIP/" 2>/dev/null | awk '{NR=1;max=160;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max)}else{print substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')" +if [ -f "${ban_logreadfile}" ]; then + logread_cmd="${ban_logreadcmd} -qn ${ban_loglimit} ${ban_logreadfile} 2>/dev/null | ${ban_grepcmd} -e \"banIP/\" 2>/dev/null" +elif printf "%s" "${ban_packages}" | "${ban_grepcmd}" -q '"logd'; then + logread_cmd="${ban_logreadcmd} -l ${ban_loglimit} -e "banIP/" 2>/dev/null" +fi + +banip_info="$(/etc/init.d/banip status 2>/dev/null | "${ban_awkcmd}" '{NR=1;max=160;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max)}else{print substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')" +report_info="$("${ban_catcmd}" "${ban_reportdir}/ban_report.txt" 2>/dev/null)" +log_info="$(${logread_cmd} | "${ban_awkcmd}" '{NR=1;max=160;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max)}else{print substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')" system_info="$( strings /etc/banner 2>/dev/null - ubus call system board | awk 'BEGIN{FS="[{}\"]"}{if($2=="kernel"||$2=="hostname"||$2=="system"||$2=="model"||$2=="description")printf " + %-12s: %s\n",$2,$4}' + "${ban_ubuscmd}" call system board | "${ban_awkcmd}" 'BEGIN{FS="[{}\"]"}{if($2=="kernel"||$2=="hostname"||$2=="system"||$2=="model"||$2=="description")printf " + %-12s: %s\n",$2,$4}' )" # content header