* output comprehensive runtime information via LuCI or via 'status' init command
* strong LuCI support
* optional: add new banIP sources on your own
+* optional: log banned inbound and/or outbound IP to syslog.
## Prerequisites
* [OpenWrt](https://openwrt.org), tested with the stable release series (19.07) and with the latest snapshot
## banIP config options
* usually the pre-configured banIP setup works quite well and no manual overrides are needed
* the following options apply to the 'global' config section:
- * ban\_enabled => main switch to enable/disable banIP service (bool/default: '0', disabled)
- * ban\_automatic => determine the L2/L3 WAN network device automatically (bool/default: '1', enabled)
- * ban\_iface => space separated list of WAN network interface(s)/device(s) used by banIP (default: not set, automatically detected)
- * ban\_realtime => a small log/banIP background monitor to block SSH/LuCI brute force attacks in realtime (bool/default: 'false', disabled)
+ * ban\_enabled => main switch to enable/disable banIP service (bool/default: '0', disabled)
+ * ban\_automatic => determine the L2/L3 WAN network device automatically (bool/default: '1', enabled)
+ * ban\_iface => space separated list of WAN network interface(s)/device(s) used by banIP (default: not set, automatically detected)
+ * ban\_realtime => a small log/banIP background monitor to block SSH/LuCI brute force attacks in realtime (bool/default: 'false', disabled)
+ * ban\_target\_src => action to perform when banning inbound IPv4 packets ('DROP'/'REJECT', default: 'DROP')
+ * ban\_target\_src\_6 => action to perform when banning inbound IPv6 packets ('DROP'/'REJECT', default: 'DROP')
+ * ban\_target\_dst => action to perform when banning outbound IPv4 packets ('DROP'/'REJECT', default: 'REJECT')
+ * ban\_target\_dst\_6 => action to perform when banning outbound IPv6 packets ('DROP'/'REJECT', default: 'REJECT')
+ * ban\_log\_src => switch to enable/disable logging of banned inbound IPv4 packets (bool/default: '0', disabled)
+ * ban\_log\_dst => switch to enable/disable logging of banned outbound IPv4 packets (bool/default: '0', disabled)
* the following options apply to the 'extra' config section:
- * ban\_debug => enable/disable banIP debug output (bool/default: '0', disabled)
- * ban\_nice => set the nice level of the banIP process and all sub-processes (int/default: '0', standard priority)
- * ban\_triggerdelay => additional trigger delay in seconds before banIP processing begins (int/default: '2')
- * ban\_backupdir => target directory for banIP backups (default: '/tmp')
- * ban\_sshdaemon => select the SSH daemon for logfile parsing, 'dropbear' or 'sshd' (default: 'dropbear')
- * ban\_starttype => select the used start type during boot, 'start', 'refresh' or 'reload' (default: 'start')
- * ban\_maxqueue => size of the download queue to handle downloads & IPSet processing in parallel (int/default: '4')
- * ban\_fetchutil => name of the used download utility: 'uclient-fetch', 'wget', 'curl', 'aria2c' (default: not set, automatically detected)
- * ban\_fetchparm => special config options for the download utility (default: not set)
- * ban\_autoblacklist => store auto-addons temporary in ipset and permanently in local blacklist as well (bool/default: '1', enabled)
- * ban\_autowhitelist => store auto-addons temporary in ipset and permanently in local whitelist as well (bool/default: '1', enabled)
+ * ban\_debug => enable/disable banIP debug output (bool/default: '0', disabled)
+ * ban\_nice => set the nice level of the banIP process and all sub-processes (int/default: '0', standard priority)
+ * ban\_triggerdelay => additional trigger delay in seconds before banIP processing begins (int/default: '2')
+ * ban\_backupdir => target directory for banIP backups (default: '/tmp')
+ * ban\_sshdaemon => select the SSH daemon for logfile parsing, 'dropbear' or 'sshd' (default: 'dropbear')
+ * ban\_starttype => select the used start type during boot, 'start', 'refresh' or 'reload' (default: 'start')
+ * ban\_maxqueue => size of the download queue to handle downloads & IPSet processing in parallel (int/default: '4')
+ * ban\_fetchutil => name of the used download utility: 'uclient-fetch', 'wget', 'curl', 'aria2c' (default: not set, automatically detected)
+ * ban\_fetchparm => special config options for the download utility (default: not set)
+ * ban\_autoblacklist => store auto-addons temporary in ipset and permanently in local blacklist as well (bool/default: '1', enabled)
+ * ban\_autowhitelist => store auto-addons temporary in ipset and permanently in local whitelist as well (bool/default: '1', enabled)
+
+## Logging of banned packets
+* by setting ban\_log\_src=1 / ban\_log\_dst=1 in the config options, banIP will log banned inbound / outbound packets to syslog.
+* example of a logged inbound (dst) and outbound (src) packet:
+<pre><code>
+Oct 2 12:49:14 gateway kernel: [434134.855130] REJECT(dst banIP) IN=br-lan OUT=br-wan MAC=xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx SRC=x.x.x.x DST=x.x.x.x LEN=100 TOS=0x00 PREC=0x00 TTL=63 ID=7938 PROTO=UDP SPT=16393 DPT=16393 LEN=80
+
+Oct 3 14:11:13 gateway kernel: [11290.429712] DROP(src banIP) IN=br-wan OUT= MAC=xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx SRC=x.x.x.x DST=x.x.x.x LEN=40 TOS=0x00 PREC=0x00 TTL=235 ID=63275 PROTO=TCP SPT=48246 DPT=37860 WINDOW=1024 RES=0x00 SYN URGP=0
+</code></pre>
+* to change the default logging behavior, the following options can be added to the 'global' config section:
+ * ban\_log\_src\_opts => IPv4 iptables LOG options for banned inbound packets (default: '-m limit --limit 10/sec')
+ * ban\_log\_src\_opts\_6 => IPv6 iptables LOG options for banned inbound packets (default: '-m limit --limit 10/sec')
+ * ban\_log\_src\_prefix (default: '<ban\_target\_src>(src banIP) ', typically 'DROP(src banIP) ')
+ * ban\_log\_src\_prefix\_6 (default: '<ban\_target\_src\_6>(src banIP) ', typically 'DROP('src banIP)' )
+ * ban\_log\_dst\_opts => IPv4 iptables LOG options for banned outbound packets (default: '-m limit --limit 10/sec')
+ * ban\_log\_dst\_opts\_6 => IPv6 iptables LOG options for banned outbound packets (default: '-m limit --limit 10/sec')
+ * ban\_log\_dst\_prefix (default: '<ban\_target\_dst>(dst banIP) ', typically 'REJECT(dst banIP) ')
+ * ban\_log\_dst\_prefix\_6 (default: '<ban\_target\_dst\_6>(dst banIP) ', typically 'REJECT('dst banIP)' )
## Examples
**receive banIP runtime information:**
-<pre><code>
-/etc/init.d/banip status
-::: banIP runtime information
- + status : enabled
- + version : 0.3.0
- + util_info : /usr/bin/aria2c, true
- + ipset_info : 10 IPSets with overall 106729 IPs/Prefixes
- + backup_dir : /tmp
- + last_run : 03.10.2019 19:15:25
- + system : UBNT-ERX, OpenWrt SNAPSHOT r11102-ced4c0e635
-</code></pre>
-
+ # /etc/init.d/banip status
+ ::: banIP runtime information
+ + status : enabled
+ + version : 0.3.0
+ + util_info : /usr/bin/aria2c, true
+ + ipset_info : 10 IPSets with overall 106729 IPs/Prefixes
+ + backup_dir : /tmp
+ + last_run : 03.10.2019 19:15:25
+ + system : UBNT-ERX, OpenWrt SNAPSHOT r11102-ced4c0e635
+
**cronjob for a regular IPSet blocklist update (/etc/crontabs/root):**
-<pre><code>
-0 06 * * * /etc/init.d/banip reload
-</code></pre>
-
+ # Every day at 06:00, update the IPSets of banIP
+ 00 06 * * * /etc/init.d/banip reload
## Support
Please join the banIP discussion in this [forum thread](https://forum.openwrt.org/t/banip-support-thread/16985) or contact me by mail <dev@brenken.org>
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# (s)hellcheck exceptions
-# shellcheck disable=1091 disable=2039 disable=2143 disable=2181 disable=2188
+# shellcheck disable=1091,2039,2086,2140,2143,2181,2188
# set initial defaults
#
LC_ALL=C
PATH="/usr/sbin:/usr/bin:/sbin:/bin"
-ban_ver="0.3.11"
+ban_ver="0.3.12"
ban_basever=""
ban_enabled=0
ban_automatic="1"
ban_sshdaemon=""
ban_setcnt=0
ban_cnt=0
+ban_log_src=0
+ban_log_dst=0
# load environment
#
config_load banip
config_foreach parse_config source
+ # setup logging
+ #
+ ban_log_chain_src="${ban_log_chain_src:-"${ban_chain}_log_src"}"
+ if [ "${ban_log_src}" -eq 1 ]
+ then
+ log_target_src="${ban_target_src:-"DROP"}"
+ ban_target_src="${ban_log_chain_src}"
+
+ log_target_src_6="${ban_target_src_6:-"DROP"}"
+ ban_target_src_6="${ban_log_chain_src}"
+ fi
+
+ ban_log_chain_dst="${ban_log_chain_dst:-"${ban_chain}_log_dst"}"
+ if [ "${ban_log_dst}" -eq 1 ]
+ then
+ log_target_dst="${ban_target_dst:-"REJECT"}"
+ ban_target_dst="${ban_log_chain_dst}"
+
+ log_target_dst_6="${ban_target_dst_6:-"REJECT"}"
+ ban_target_dst_6="${ban_log_chain_dst}"
+ fi
+
# log daemon check
#
if [ "$(/etc/init.d/log running; printf "%u" "${?}")" -eq 1 ]
fi
case "${util}" in
"aria2c")
- ban_fetchparm="${ban_fetchparm:-"--timeout=20 --allow-overwrite=true --auto-file-renaming=false --check-certificate=true --dir=" " -o"}"
+ ban_fetchparm="${ban_fetchparm:-"--timeout=20 --allow-overwrite=true --auto-file-renaming=false --check-certificate=true --dir=/ -o"}"
;;
"curl")
ban_fetchparm="${ban_fetchparm:-"--connect-timeout 20 -o"}"
then
if [ "${src_ruletype}" != "dst" ]
then
- if [ "${src_name##*_}" = "6" ]
+ f_iptrule "-I" "${wan_input} -j ${ban_chain}"
+ f_iptrule "-I" "${wan_forward} -j ${ban_chain}"
+ if [ "${src_name##*_}" != "6" ]
then
- # dummy, special IPv6 rules
- /bin/true
- else
- f_iptrule "-I" "${wan_input} -p udp --dport 67:68 --sport 67:68 -j RETURN"
+ # special IPv4 rules
+ f_iptrule "-A" "${ban_chain} -p udp --dport 67:68 --sport 67:68 -j RETURN"
fi
- f_iptrule "-A" "${wan_input} -j ${ban_chain}"
- f_iptrule "-A" "${wan_forward} -j ${ban_chain}"
for dev in ${ban_dev}
do
f_iptrule "${action:-"-A"}" "${ban_chain} -i ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j ${target_src}"
fi
if [ "${src_ruletype}" != "src" ]
then
- if [ "${src_name##*_}" = "6" ]
+ f_iptrule "-I" "${lan_input} -j ${ban_chain}"
+ f_iptrule "-I" "${lan_forward} -j ${ban_chain}"
+ if [ "${src_name##*_}" != "6" ]
then
- # dummy, special IPv6 rules
- /bin/true
- else
- f_iptrule "-I" "${lan_input} -p udp --dport 67:68 --sport 67:68 -j RETURN"
+ # special IPv4 rules
+ f_iptrule "-A" "${ban_chain} -p udp --dport 67:68 --sport 67:68 -j RETURN"
fi
- f_iptrule "-A" "${lan_input} -j ${ban_chain}"
- f_iptrule "-A" "${lan_forward} -j ${ban_chain}"
for dev in ${ban_dev}
do
f_iptrule "${action:-"-A"}" "${ban_chain} -o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j ${target_dst}"
#
f_ipset()
{
- local out_rc source action ruleset ruleset_6 rule cnt=0 cnt_ip=0 cnt_cidr=0 timeout="-w 5" mode="${1}" in_rc="${src_rc:-0}"
+ local out_rc source action ruleset rule cnt=0 cnt_ip=0 cnt_cidr=0 timeout="-w 5" mode="${1}" in_rc="${src_rc:-0}"
if [ "${src_name%_6*}" = "whitelist" ]
then
return "${out_rc}"
;;
"initial")
- if [ -x "${ban_ipt}" ] && [ -z "$("${ban_ipt}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
- then
- "${ban_ipt}" "${timeout}" -N "${ban_chain}" 2>/dev/null
- out_rc="${?}"
- elif [ -x "${ban_ipt}" ]
- then
- src_name="ruleset"
- ruleset="${ban_wan_input_chain:-"input_wan_rule"} ${ban_wan_forward_chain:-"forwarding_wan_rule"} ${ban_lan_input_chain:-"input_lan_rule"} ${ban_lan_forward_chain:-"forwarding_lan_rule"}"
- for rule in ${ruleset}
- do
- f_iptrule "-D" "${rule} -j ${ban_chain}"
- done
- fi
- if [ -x "${ban_ipt6}" ] && [ -z "$("${ban_ipt6}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
- then
- "${ban_ipt6}" "${timeout}" -N "${ban_chain}" 2>/dev/null
- out_rc="${?}"
- elif [ -x "${ban_ipt6}" ]
- then
- src_name="ruleset_6"
- ruleset_6="${ban_wan_input_chain_6:-"input_wan_rule"} ${ban_wan_forward_chain_6:-"forwarding_wan_rule"} ${ban_lan_input_chain_6:-"input_lan_rule"} ${ban_lan_forward_chain_6:-"forwarding_lan_rule"}"
- for rule in ${ruleset_6}
- do
- f_iptrule "-D" "${rule} -j ${ban_chain}"
- done
- fi
+ local ipt log_src_target log_src_opts log_src_prefix log_dst_target log_dst_opts log_dst_prefix
+ for src_name in "ruleset" "ruleset_6"
+ do
+ if [ "${src_name##*_}" = "6" ]
+ then
+ ipt="${ban_ipt6}"
+ ruleset="${ban_wan_input_chain_6:-"input_wan_rule"} ${ban_wan_forward_chain_6:-"forwarding_wan_rule"} ${ban_lan_input_chain_6:-"input_lan_rule"} ${ban_lan_forward_chain_6:-"forwarding_lan_rule"}"
+ log_src_target="${log_target_src_6}"
+ log_src_opts="${ban_log_src_opts_6:-"-m limit --limit 10/sec"}"
+ log_src_prefix="${ban_log_src_prefix_6:-"${log_target_src_6}(src banIP) "}"
+ log_dst_target="${log_target_dst_6}"
+ log_dst_opts="${ban_log_dst_opts_6:-"-m limit --limit 10/sec"}"
+ log_dst_prefix="${ban_log_dst_prefix_6:-"${log_target_dst_6}(dst banIP) "}"
+ else
+ ipt="${ban_ipt}"
+ ruleset="${ban_wan_input_chain:-"input_wan_rule"} ${ban_wan_forward_chain:-"forwarding_wan_rule"} ${ban_lan_input_chain:-"input_lan_rule"} ${ban_lan_forward_chain:-"forwarding_lan_rule"}"
+ log_src_target="${log_target_src}"
+ log_src_opts="${ban_log_src_opts:-"-m limit --limit 10/sec"}"
+ log_src_prefix="${ban_log_src_prefix:-"${log_target_src}(src banIP) "}"
+ log_dst_target="${log_target_dst}"
+ log_dst_opts="${ban_log_dst_opts:-"-m limit --limit 10/sec"}"
+ log_dst_prefix="${ban_log_dst_prefix:-"${log_target_dst}(dst banIP) "}"
+ fi
+
+ if [ -x "${ipt}" ]
+ then
+ if [ -z "$("${ipt}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
+ then
+ "${ipt}" "${timeout}" -N "${ban_chain}" 2>/dev/null
+ out_rc="${?}"
+ else
+ out_rc=0
+ for rule in ${ruleset}
+ do
+ f_iptrule "-D" "${rule} -j ${ban_chain}"
+ done
+ fi
+ f_log "debug" "f_ipset ::: name: -, mode: ${mode:-"-"}, chain: ${ban_chain:-"-"}, $src_name: ${ruleset:-"-"}, out_rc: ${out_rc}"
+
+ if [ "${ban_log_src}" -eq 1 ] && [ "${out_rc}" -eq 0 ]
+ then
+ if [ -z "$("${ipt}" "${timeout}" -nL "${ban_log_chain_src}" 2>/dev/null)" ]
+ then
+ "${ipt}" "${timeout}" -N "${ban_log_chain_src}" 2>/dev/null
+ out_rc="${?}"
+ if [ "${out_rc}" -eq 0 ]
+ then
+ "${ipt}" "${timeout}" -A "${ban_log_chain_src}" -j LOG ${log_src_opts} --log-prefix "${log_src_prefix}" && \
+ "${ipt}" "${timeout}" -A "${ban_log_chain_src}" -j "${log_src_target}"
+ out_rc="${?}"
+ fi
+ fi
+ f_log "debug" "f_ipset ::: name: -, mode: ${mode:-"-"}, chain: ${ban_log_chain_src:-"-"}, out_rc: ${out_rc}"
+ fi
+
+ if [ "${ban_log_dst}" -eq 1 ] && [ "${out_rc}" -eq 0 ]
+ then
+ if [ -z "$("${ipt}" "${timeout}" -nL "${ban_log_chain_dst}" 2>/dev/null)" ]
+ then
+ "${ipt}" "${timeout}" -N "${ban_log_chain_dst}" 2>/dev/null
+ out_rc="${?}"
+ if [ "${out_rc}" -eq 0 ]
+ then
+ "${ipt}" "${timeout}" -A "${ban_log_chain_dst}" -j LOG ${log_dst_opts} --log-prefix "${log_dst_prefix}" && \
+ "${ipt}" "${timeout}" -A "${ban_log_chain_dst}" -j "${log_dst_target}"
+ out_rc="${?}"
+ fi
+ fi
+ f_log "debug" "f_ipset ::: name: -, mode: ${mode:-"-"}, chain: ${ban_log_chain_dst:-"-"}, out_rc: ${out_rc}"
+ fi
+ fi
+ done
+
out_rc="${out_rc:-"${in_rc}"}"
- f_log "debug" "f_ipset ::: name: -, mode: ${mode:-"-"}, chain: ${ban_chain:-"-"}, ruleset: ${ruleset:-"-"}, ruleset_6: ${ruleset_6:-"-"}, out_rc: ${out_rc}"
+ f_log "debug" "f_ipset ::: name: -, mode: ${mode:-"-"}, out_rc: ${out_rc}"
return "${out_rc}"
;;
"create")
f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}"
;;
"destroy")
- if [ -x "${ban_ipt}" ] && [ -x "${ban_ipt_save}" ] && [ -x "${ban_ipt_restore}" ] && \
- [ -n "$("${ban_ipt}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
- then
- "${ban_ipt_save}" | grep -v -- "-j ${ban_chain}" | "${ban_ipt_restore}"
- "${ban_ipt}" "${timeout}" -F "${ban_chain}" 2>/dev/null
- "${ban_ipt}" "${timeout}" -X "${ban_chain}" 2>/dev/null
- fi
- if [ -x "${ban_ipt6}" ] && [ -x "${ban_ipt6_save}" ] && [ -x "${ban_ipt6_restore}" ] && \
- [ -n "$("${ban_ipt6}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
- then
- "${ban_ipt6_save}" | grep -v -- "-j ${ban_chain}" | "${ban_ipt6_restore}"
- "${ban_ipt6}" "${timeout}" -F "${ban_chain}" 2>/dev/null
- "${ban_ipt6}" "${timeout}" -X "${ban_chain}" 2>/dev/null
- fi
+ for chain in ${ban_log_chain_src} ${ban_log_chain_dst} ${ban_chain}
+ do
+ if [ -x "${ban_ipt}" ] && [ -x "${ban_ipt_save}" ] && [ -x "${ban_ipt_restore}" ] && \
+ [ -n "$("${ban_ipt}" "${timeout}" -nL "${chain}" 2>/dev/null)" ]
+ then
+ "${ban_ipt_save}" | grep -v -- "-j ${chain}" | "${ban_ipt_restore}"
+ "${ban_ipt}" "${timeout}" -F "${chain}" 2>/dev/null
+ "${ban_ipt}" "${timeout}" -X "${chain}" 2>/dev/null
+ fi
+ if [ -x "${ban_ipt6}" ] && [ -x "${ban_ipt6_save}" ] && [ -x "${ban_ipt6_restore}" ] && \
+ [ -n "$("${ban_ipt6}" "${timeout}" -nL "${chain}" 2>/dev/null)" ]
+ then
+ "${ban_ipt6_save}" | grep -v -- "-j ${chain}" | "${ban_ipt6_restore}"
+ "${ban_ipt6}" "${timeout}" -F "${chain}" 2>/dev/null
+ "${ban_ipt6}" "${timeout}" -X "${chain}" 2>/dev/null
+ fi
+ done
for source in ${ban_sources}
do
if [ -x "${ban_ipset}" ] && [ -n "$("${ban_ipset}" -q -n list "${source}")" ]
if [ -z "$(ls "${ban_tmpfile}".*.err 2>/dev/null)" ]
then
- for cnt in $(cat "${ban_tmpfile}".*.cnt 2>/dev/null)
- do
- ban_cnt="$((ban_cnt+cnt))"
- done
- if [ "${ban_cnt}" -gt 0 ]
- then
- ban_setcnt="$(ls "${ban_tmpfile}".*.cnt 2>/dev/null | wc -l)"
- fi
+ for cnt_file in "${ban_tmpfile}".*.cnt
+ do
+ if [ -f "$cnt_file" ]
+ then
+ read -r cnt < "$cnt_file"
+ ban_cnt="$((ban_cnt+cnt))"
+ ban_setcnt="$((ban_setcnt+1))"
+ fi
+ done
f_log "info" "${ban_setcnt} IPSets with overall ${ban_cnt} IPs/Prefixes loaded successfully (${ban_sysver})"
f_bgserv "start"
f_jsnup