banip: new package to block incoming & outgoing ip addresses 7373/head
authorDirk Brenken <dev@brenken.org>
Sat, 10 Nov 2018 10:01:45 +0000 (11:01 +0100)
committerDirk Brenken <dev@brenken.org>
Sat, 10 Nov 2018 10:01:45 +0000 (11:01 +0100)
a new script based package called "banIP" to block
incoming & outgoing ip adresses/subnets via ipset.

Features:
* a shell script which uses ipset and iptables
  to ban a large number of IP addresses
  published in various IP blacklists (bogon, firehol etc.)
* support blocking by ASN numbers
* support blocking by iso country codes
* support local white & blacklist (IPv4, IPv6 & CIDR notation)
* auto-add unsuccessful ssh login attempts to local blacklist
* auto-add the uplink subnet to local whitelist
* per source configuration of SRC (incoming) and DST (outgoing)
* supports IPv4 & IPv6

Strong LuCI support:
* easy interface to track & change all aspects of your ipset
  configuration on the fly
* integrated IPSet-Lookup
* integrated RIPE-Lookup
* Log-Viewer & online configuration of white- & blacklist

LuCI-Screenshots will follow in the second post.
Forum discussion:
https://forum.openwrt.org/t/banip-new-project-needs-testers-feedback/16985

Signed-off-by: Dirk Brenken <dev@brenken.org>
net/banip/Makefile [new file with mode: 0644]
net/banip/files/README.md [new file with mode: 0644]
net/banip/files/banip.blacklist [new file with mode: 0644]
net/banip/files/banip.conf [new file with mode: 0644]
net/banip/files/banip.hotplug [new file with mode: 0644]
net/banip/files/banip.init [new file with mode: 0755]
net/banip/files/banip.sh [new file with mode: 0755]
net/banip/files/banip.whitelist [new file with mode: 0644]

diff --git a/net/banip/Makefile b/net/banip/Makefile
new file mode 100644 (file)
index 0000000..0b3a1c7
--- /dev/null
@@ -0,0 +1,64 @@
+#
+# Copyright (c) 2018 Dirk Brenken (dev@brenken.org)
+# This is free software, licensed under the GNU General Public License v3.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=banip
+PKG_VERSION:=0.0.5
+PKG_RELEASE:=1
+PKG_LICENSE:=GPL-3.0+
+PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/banip
+       SECTION:=net
+       CATEGORY:=Network
+       TITLE:=Ban incoming and/or outgoing ip adresses via ipsets
+       DEPENDS:=+jshn +jsonfilter +ipset +iptables
+       PKGARCH:=all
+endef
+
+define Package/banip/description
+Powerful banIP script to block ip addresses via ipsets.
+The script supports many ip blacklist sites plus manual black- and whitelist overrides.
+Please see https://github.com/openwrt/packages/blob/master/net/banip/files/README.md for further information.
+
+endef
+
+define Package/banip/conffiles
+/etc/config/banip
+/etc/banip/banip.whitelist
+/etc/banip/banip.blacklist
+endef
+
+define Build/Prepare
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/banip/install
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_BIN) ./files/banip.sh $(1)/usr/bin/
+
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) ./files/banip.init $(1)/etc/init.d/banip
+
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_CONF) ./files/banip.conf $(1)/etc/config/banip
+
+       $(INSTALL_DIR) $(1)/etc/banip
+       $(INSTALL_CONF) ./files/banip.blacklist $(1)/etc/banip/
+       $(INSTALL_CONF) ./files/banip.whitelist $(1)/etc/banip/
+       
+       $(INSTALL_DIR) $(1)/etc/hotplug.d/firewall
+       $(INSTALL_DATA) ./files/banip.hotplug $(1)/etc/hotplug.d/firewall/30-banip
+endef
+
+$(eval $(call BuildPackage,banip))
diff --git a/net/banip/files/README.md b/net/banip/files/README.md
new file mode 100644 (file)
index 0000000..982a713
--- /dev/null
@@ -0,0 +1,75 @@
+# banIP - ban incoming and/or outgoing ip adresses via ipsets
+
+## Description
+IP address blocking is commonly used to protect against brute force attacks, prevent disruptive or unautherized address(es) from access or it can be used to restrict access to or from a particular geographic area — for example.  
+
+## Main Features
+* support many IP blocklist sources (free for private usage, for commercial use please check their individual licenses):
+* zero-conf like automatic installation & setup, usually no manual changes needed
+* supports six different download utilities: uclient-fetch, wget, curl, aria2c, wget-nossl, busybox-wget
+* Really fast downloads & list processing as they are handled in parallel as background jobs in a configurable 'Download Queue'
+* provides 'http only' mode without installed ssl library for all non-SSL blocklist sources
+* full IPv4 and IPv6 support
+* ipsets (one per source) are used to ban a large number of IP addresses
+* supports blocking by ASN numbers
+* supports blocking by iso country codes
+* supports local white & blacklist (IPv4, IPv6 & CIDR notation), located by default in /etc/banip/banip.whitelist and /etc/banip/banip.blacklist
+* auto-add unsuccessful ssh login attempts to local blacklist
+* auto-add the uplink subnet to local whitelist
+* per source configuration of SRC (incoming) and DST (outgoing)
+* integrated IPSet-Lookup
+* integrated RIPE-Lookup
+* blocklist source parsing by fast & flexible regex rulesets
+* minimal status & error logging to syslog, enable debug logging to receive more output
+* procd based init system support (start/stop/restart/reload/status)
+* procd network interface trigger support
+* output comprehensive runtime information via LuCI or via 'status' init command
+* strong LuCI support
+* optional: add new banIP sources on your own
+
+## Prerequisites
+* [OpenWrt](https://openwrt.org), tested with the stable release series (18.06) and with the latest snapshot
+* a download utility:
+    * to support all blocklist sources a full version (with ssl support) of 'wget', 'uclient-fetch' with one of the 'libustream-*' ssl libraries, 'aria2c' or 'curl' is required
+    * for limited devices with real memory constraints, banIP provides also a 'http only' option and supports wget-nossl and uclient-fetch (without libustream-ssl) as well
+
+## Installation & Usage
+* install 'banip' (_opkg install banip_)
+* at minimum configure the needed IP blocklist sources, the download utility and enable the banIP service in _/etc/config/banip_
+* control the banip service manually with _/etc/init.d/banip_ start/stop/restart/reload/status or use the LuCI frontend
+
+## LuCI banIP companion package
+* it's recommended to use the provided LuCI frontend to control all aspects of banIP
+* install 'luci-app-banip' (_opkg install luci-app-banip_)
+* the application is located in LuCI under 'Services' menu
+
+## Examples
+**receive banIP runtime information:**
+
+<pre><code>
+/etc/init.d/banip status
+::: banIP runtime information
+  + status     : enabled
+  + version    : 0.0.5
+  + fetch_info : /bin/uclient-fetch (libustream-ssl)
+  + ipset_info : 3 IPSets with overall 29510 IPs/Prefixes
+  + last_run   : 08.11.2018 15:03:50
+  + system     : GL-AR750S, OpenWrt SNAPSHOT r8419-860de2e1aa
+</code></pre>
+  
+**cronjob for a regular block list update (/etc/crontabs/root):**
+
+<pre><code>
+0 06 * * *    /etc/init.d/banip reload
+</code></pre>
+  
+
+## Support
+Please join the banIP discussion in this [forum thread](https://forum.openwrt.org/t/banip-new-project-needs-testers-feedback/16985) or contact me by mail <dev@brenken.org>  
+
+## Removal
+* stop all banIP related services with _/etc/init.d/banip stop_
+* optional: remove the banip package (_opkg remove banip_)
+
+Have fun!  
+Dirk  
diff --git a/net/banip/files/banip.blacklist b/net/banip/files/banip.blacklist
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/net/banip/files/banip.conf b/net/banip/files/banip.conf
new file mode 100644 (file)
index 0000000..731b44a
--- /dev/null
@@ -0,0 +1,223 @@
+# banIP configuration, for further information
+# see 'https://github.com/openwrt/packages/blob/master/net/banip/files/README.md'
+
+config banip 'global'
+       option ban_enabled '0'
+       option ban_automatic '1'
+       option ban_fetchutil 'uclient-fetch'
+       option ban_iface 'wan'
+
+config banip 'extra'
+       option ban_debug '0'
+       option ban_maxqueue '8'
+
+config source 'whitelist'
+       option ban_src '/etc/banip/banip.whitelist'
+       option ban_src_6 '/etc/banip/banip.whitelist'
+       option ban_src_desc 'Always allow these IPs (IPv4/IPv6)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add whitelist \"\$1}'
+       option ban_src_rset_6 '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(:\/[0-9]{1,2})?([[:space:]]|$)/{print \"add whitelist_6 \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src+dst'
+       option ban_src_on '1'
+       option ban_src_on_6 '0'
+
+config source 'blacklist'
+       option ban_src '/etc/banip/banip.blacklist'
+       option ban_src_6 '/etc/banip/banip.blacklist'
+       option ban_src_desc 'Always deny these IPs (IPv4/IPv6)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add blacklist \"\$1}'
+       option ban_src_rset_6 '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(:\/[0-9]{1,2})?([[:space:]]|$)/{print \"add blacklist_6 \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src+dst'
+       option ban_src_on '0'
+       option ban_src_on_6 '0'
+
+config source 'bogon'
+       option ban_src 'https://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt'
+       option ban_src_6 'https://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt'
+       option ban_src_desc 'Bogon prefixes, plus prefixes that have been allocated to RIRs but not yet assigned to ISPs (IPv4/IPv6)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add bogon \"\$1}'
+       option ban_src_rset_6 '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(:\/[0-9]{1,2})?([[:space:]]|$)/{print \"add bogon_6 \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src+dst'
+       option ban_src_on '0'
+       option ban_src_on_6 '0'
+
+config source 'tor'
+       option ban_src 'https://check.torproject.org/exit-addresses'
+       option ban_src_desc 'List of Tor Exit Nodes (IPv4)'
+       option ban_src_rset '/^(ExitAddress ([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add tor \"\$2}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+       option ban_src_on_6 '0'
+
+config source 'threat'
+       option ban_src 'https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt'
+       option ban_src_desc 'Emerging Threats (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add threat \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'debl'
+       option ban_src 'https://www.blocklist.de/downloads/export-ips_all.txt'
+       option ban_src_6 'https://www.blocklist.de/downloads/export-ips_all.txt'
+       option ban_src_desc 'Fail2ban reporting service (IPv4/IPv6)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add debl \"\$1}'
+       option ban_src_rset_6 '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(:\/[0-9]{1,2})?([[:space:]]|$)/{print \"add debl_6 \"\$1}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+       option ban_src_on_6 '0'
+
+config source 'myip'
+       option ban_src 'https://www.myip.ms/files/blacklist/general/latest_blacklist.txt'
+       option ban_src_6 'https://www.myip.ms/files/blacklist/general/latest_blacklist.txt'
+       option ban_src_desc 'IP blacklist provided by myip.ms (IPv4/IPv6)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add myip \"\$1}'
+       option ban_src_rset_6 '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(:\/[0-9]{1,2})?([[:space:]]|$)/{print \"add myip_6 \"\$1}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+       option ban_src_on_6 '0'
+
+config source 'yoyo'
+       option ban_src 'http://pgl.yoyo.org/adservers/iplist.php?ipformat=plain&showintro=0&mimetype=plaintext'
+       option ban_src_desc 'IP blocklist provided by Peter Lowe (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add yoyo \"\$1}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'zeus'
+       option ban_src 'https://zeustracker.abuse.ch/blocklist.php?download=ipblocklist'
+       option ban_src_desc 'Zeus Tracker by abuse.ch (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add zeus \"\$1}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'sslbl'
+       option ban_src 'https://sslbl.abuse.ch/blacklist/sslipblacklist.csv'
+       option ban_src_desc 'SSL Blacklist by abuse.ch (IPv4)'
+       option ban_src_rset 'BEGIN{FS=\",\"}/^(([0-9]{1,3}\.){3}[0-9]{1,3},).*/{print \"add sslbl \"\$1}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'ransomware'
+       option ban_src 'https://ransomwaretracker.abuse.ch/downloads/RW_IPBL.txt'
+       option ban_src_desc 'Ransomware Tracker by abuse.ch (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add ransomware \"\$1}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'feodo'
+       option ban_src 'https://feodotracker.abuse.ch/blocklist/?download=ipblocklist'
+       option ban_src_desc 'Feodo Tracker by abuse.ch (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add feodo \"\$1}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'dshield'
+       option ban_src 'http://feeds.dshield.org/block.txt'
+       option ban_src_desc 'Dshield recommended IP blocklist. Contains top 20 attacking class C subnets (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add dshield \"\$1 \"/\"\$3}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'proxy'
+       option ban_src 'https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/proxylists.ipset'
+       option ban_src_desc 'List of Open Proxies (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3})([[:space:]]|$)/{print \"add proxy \"\$1}'
+       option ban_src_settype 'ip'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'iblocklist'
+       option ban_src 'http://list.iblocklist.com/?list=dgxtneitpuvgqqcpfulq&fileformat=cidr&archiveformat=gz'
+       option ban_src_desc 'Contains advertising trackers and a short list of bad/intrusive porn sites (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add iblocklist \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'drop'
+       option ban_src 'https://www.spamhaus.org/drop/drop.txt'
+       option ban_src_6 'https://www.spamhaus.org/drop/dropv6.txt'
+       option ban_src_desc 'Spamhaus drop compilation (IPv4/IPv6)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add drop \"\$1}'
+       option ban_src_rset_6 '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(:\/[0-9]{1,2})?([[:space:]]|$)/{print \"add drop_6 \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+       option ban_src_on_6 '0'
+
+config source 'edrop'
+       option ban_src 'https://www.spamhaus.org/drop/edrop.txt'
+       option ban_src_desc 'Spamhaus edrop compilation (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add edrop \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'firehol1'
+       option ban_src 'https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset'
+       option ban_src_desc 'Firehol Level 1 compilation. Contains bogons, spamhaus drop and edrop, dshield and malware lists (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add firehol1 \"\$1}'
+       option ban_src_settype 'net_inet'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'firehol2'
+       option ban_src 'https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level2.netset'
+       option ban_src_desc 'Firehol Level 2 compilation. Contains blocklists that track attacks, during the last 48 hours (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add firehol2 \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'firehol3'
+       option ban_src 'https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level3.netset'
+       option ban_src_desc 'Firehol Level 3 compilation. Contains blocklists that track attacks, spyware and viruses (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add firehol3 \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'firehol4'
+       option ban_src 'https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level4.netset'
+       option ban_src_desc 'Firehol Level 4 compilation. May include a large number of false positives (IPv4)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add firehol4 \"\$1}'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+
+config source 'country'
+       option ban_src 'https://stat.ripe.net/data/country-resource-list/data.json?resource='
+       option ban_src_6 'https://stat.ripe.net/data/country-resource-list/data.json?resource='
+       option ban_src_desc 'Build a dynamic IPSet by country iso codes based on RIPE data (IPv4/IPv6)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add country \"\$1}'
+       option ban_src_rset_6 '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(:\/[0-9]{1,2})?([[:space:]]|$)/{print \"add country_6 \"\$1}'
+       list ban_src_cat 'de'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+       option ban_src_on_6 '0'
+
+config source 'asn'
+       option ban_src 'https://stat.ripe.net/data/announced-prefixes/data.json?resource='
+       option ban_src_6 'https://stat.ripe.net/data/announced-prefixes/data.json?resource='
+       option ban_src_desc 'Build a dynamic IPSet by ASN numbers based on RIPE data (IPv4/IPv6)'
+       option ban_src_rset '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print \"add asn \"\$1}'
+       option ban_src_rset_6 '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}(:\/[0-9]{1,2})?([[:space:]]|$)/{print \"add asn_6 \"\$1}'
+       list ban_src_cat '32934'
+       option ban_src_settype 'net'
+       option ban_src_ruletype 'src'
+       option ban_src_on '0'
+       option ban_src_on_6 '0'
diff --git a/net/banip/files/banip.hotplug b/net/banip/files/banip.hotplug
new file mode 100644 (file)
index 0000000..9cb5f7d
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+
+ban_pidfile="/var/run/banip.pid"
+ban_enabled="$(/etc/init.d/banip enabled; printf "%u" ${?})"
+
+if [ "${ban_enabled}" = "1" ] || [ ! -f "${ban_pidfile}" ] || [ -s "${ban_pidfile}" ] || [ "${ACTION}" != "add" ]
+then
+       exit 0
+fi
+
+/etc/init.d/banip start
diff --git a/net/banip/files/banip.init b/net/banip/files/banip.init
new file mode 100755 (executable)
index 0000000..3d9accc
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/sh /etc/rc.common
+#
+
+START=30
+USE_PROCD=1
+
+EXTRA_COMMANDS="status"
+EXTRA_HELP="   status  Print runtime information"
+
+ban_init="/etc/init.d/banip"
+ban_script="/usr/bin/banip.sh"
+ban_pidfile="/var/run/banip.pid"
+
+boot()
+{
+       ban_boot="1"
+       rc_procd start_service
+}
+
+start_service()
+{
+       if [ $("${ban_init}" enabled; printf "%u" ${?}) -eq 0 ]
+       then
+               if [ "${ban_boot}" = "1" ]
+               then
+                       return 0
+               fi
+               local nice="$(uci_get banip extra ban_nice)"
+               procd_open_instance "banip"
+               procd_set_param command "${ban_script}" "${@}"
+               procd_set_param pidfile "${ban_pidfile}"
+               procd_set_param nice ${nice:-0}
+               procd_set_param stdout 1
+               procd_set_param stderr 1
+               procd_close_instance
+       fi
+}
+
+stop_service()
+{
+       rc_procd "${ban_script}" stop
+       rc_procd start_service
+}
+
+status()
+{
+       local key keylist value rtfile="$(uci_get banip global ban_rtfile)"
+
+       rtfile="${rtfile:-"/tmp/ban_runtime.json"}"
+       json_load_file "${rtfile}" >/dev/null 2>&1
+       json_select data >/dev/null 2>&1
+       if [ ${?} -eq 0 ]
+       then
+               printf "%s\n" "::: banIP runtime information"
+               json_get_keys keylist
+               for key in ${keylist}
+               do
+                       json_get_var value "${key}"
+                       printf "  + %-10s : %s\n" "${key}" "${value}"
+               done
+       else
+               printf "%s\n" "::: no banIP runtime information available"
+       fi
+}
+
+service_triggers()
+{
+       local iface="$(uci_get banip global ban_iface)"
+       local delay="$(uci_get banip extra ban_triggerdelay)"
+
+       PROCD_RELOAD_DELAY=$((${delay:-2} * 1000))
+       procd_add_interface_trigger "interface.*.up" "${iface:-"wan"}" "${ban_init}" start
+       procd_add_reload_trigger "banip" "firewall"
+}
diff --git a/net/banip/files/banip.sh b/net/banip/files/banip.sh
new file mode 100755 (executable)
index 0000000..212b706
--- /dev/null
@@ -0,0 +1,671 @@
+#!/bin/sh
+# banIP - ban incoming and outgoing ip adresses/subnets via ipset
+# written by Dirk Brenken (dev@brenken.org)
+
+# This is free software, licensed under the GNU General Public License v3.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# set initial defaults
+#
+LC_ALL=C
+PATH="/usr/sbin:/usr/bin:/sbin:/bin"
+ban_ver="0.0.5"
+ban_sysver="unknown"
+ban_enabled=0
+ban_automatic="1"
+ban_iface=""
+ban_debug=0
+ban_maxqueue=8
+ban_fetchutil="uclient-fetch"
+ban_ipt="$(command -v iptables)"
+ban_ipt_save="$(command -v iptables-save)"
+ban_ipt_restore="$(command -v iptables-restore)"
+ban_ipt6="$(command -v ip6tables)"
+ban_ipt6_save="$(command -v ip6tables-save)"
+ban_ipt6_restore="$(command -v ip6tables-restore)"
+ban_ipset="$(command -v ipset)"
+ban_chain="banIP"
+ban_action="${1:-"start"}"
+ban_pidfile="/var/run/banip.pid"
+ban_rtfile="/tmp/ban_runtime.json"
+ban_setcnt=0
+ban_cnt=0
+ban_rc=0
+
+# load environment
+#
+f_envload()
+{
+       local sys_call sys_desc sys_model
+
+       # get system information
+       #
+       sys_call="$(ubus -S call system board 2>/dev/null)"
+       if [ -n "${sys_call}" ]
+       then
+               sys_desc="$(printf '%s' "${sys_call}" | jsonfilter -e '@.release.description')"
+               sys_model="$(printf '%s' "${sys_call}" | jsonfilter -e '@.model')"
+               ban_sysver="${sys_model}, ${sys_desc}"
+       fi
+
+       # parse 'global' and 'extra' section by callback
+       #
+       config_cb()
+       {
+               local type="${1}"
+               if [ "${type}" = "banip" ]
+               then
+                       option_cb()
+                       {
+                               local option="${1}"
+                               local value="${2}"
+                               eval "${option}=\"${value}\""
+                       }
+               else
+                       reset_cb
+               fi
+       }
+
+       # parse 'source' typed sections
+       #
+       parse_config()
+       {
+               local value opt section="${1}" options="ban_src ban_src_6 ban_src_rset ban_src_rset_6 ban_src_settype ban_src_ruletype ban_src_on ban_src_on_6 ban_src_cat"
+               for opt in ${options}
+               do
+                       config_get value "${section}" "${opt}"
+                       if [ -n "${value}" ]
+                       then
+                               eval "${opt}_${section}=\"${value}\""
+                               if [ "${opt}" = "ban_src" ]
+                               then
+                                       eval "ban_sources=\"${ban_sources} ${section}\""
+                               elif [ "${opt}" = "ban_src_6" ]
+                               then
+                                       eval "ban_sources=\"${ban_sources} ${section}_6\""
+                               fi
+                       fi
+               done
+       }
+
+       # load config
+       #
+       config_load banip
+       config_foreach parse_config source
+
+       # create temp directory & files
+       #
+       f_temp
+
+       # check status
+       #
+       if [ ${ban_enabled} -eq 0 ]
+       then
+               f_jsnup disabled
+               f_ipset destroy
+               f_rmtemp
+               f_log "info" "banIP is currently disabled, please set ban_enabled to '1' to use this service"
+               exit 0
+       fi
+}
+
+# check environment
+#
+f_envcheck()
+{
+       local ssl_lib
+
+       # check fetch utility
+       #
+       case "${ban_fetchutil}" in
+               uclient-fetch)
+                       if [ -f "/lib/libustream-ssl.so" ]
+                       then
+                               ban_fetchparm="${ban_fetchparm:-"--timeout=20 --no-check-certificate -O"}"
+                               ssl_lib="libustream-ssl"
+                       else
+                               ban_fetchparm="${ban_fetchparm:-"--timeout=20 -O"}"
+                       fi
+               ;;
+               wget)
+                       ban_fetchparm="${ban_fetchparm:-"--no-cache --no-cookies --max-redirect=0 --timeout=20 --no-check-certificate -O"}"
+                       ssl_lib="built-in"
+               ;;
+               wget-nossl)
+                       ban_fetchparm="${ban_fetchparm:-"--no-cache --no-cookies --max-redirect=0 --timeout=20 -O"}"
+               ;;
+               busybox)
+                       ban_fetchparm="${ban_fetchparm:-"-O"}"
+               ;;
+               curl)
+                       ban_fetchparm="${ban_fetchparm:-"--connect-timeout 20 --insecure -o"}"
+                       ssl_lib="built-in"
+               ;;
+               aria2c)
+                       ban_fetchparm="${ban_fetchparm:-"--timeout=20 --allow-overwrite=true --auto-file-renaming=false --check-certificate=false -o"}"
+                       ssl_lib="built-in"
+               ;;
+       esac
+       ban_fetchutil="$(command -v "${ban_fetchutil}")"
+       ban_fetchinfo="${ban_fetchutil:-"-"} (${ssl_lib:-"-"})"
+
+       if [ ! -x "${ban_fetchutil}" ] || [ -z "${ban_fetchutil}" ] || [ -z "${ban_fetchparm}" ]
+       then
+               f_log "err" "download utility not found, please install 'uclient-fetch' with 'libustream-mbedtls' or the full 'wget' package"
+       fi
+
+       # get wan device and wan subnets
+       #
+       if [ "${ban_automatic}" = "1" ]
+       then
+               network_find_wan ban_iface
+               if [ -z "${ban_iface}" ]
+               then
+                       network_find_wan6 ban_iface
+               fi
+       fi
+       network_get_device ban_dev "${ban_iface}"
+       network_get_subnets ban_subnets "${ban_iface}"
+       network_get_subnets6 ban_subnets6 "${ban_iface}"
+
+       if [ -z "${ban_iface}" ] || [ -z "${ban_dev}" ]
+       then
+               f_log "err" "wan interface/device (${ban_iface:-"-"}/${ban_dev:-"-"}) not found, please please check your configuration"
+       fi
+       uci_set banip global ban_iface "${ban_iface}"
+       uci_commit banip
+
+       f_jsnup "running"
+       f_log "info" "start banIP processing (${ban_action})"
+}
+
+# create temporary files and directories
+#
+f_temp()
+{
+       if [ -z "${ban_tmpdir}" ]
+       then
+               ban_tmpdir="$(mktemp -p /tmp -d)"
+               ban_tmpload="$(mktemp -p ${ban_tmpdir} -tu)"
+               ban_tmpfile="$(mktemp -p ${ban_tmpdir} -tu)"
+       fi
+
+       if [ ! -s "${ban_pidfile}" ]
+       then
+               printf '%s' "${$}" > "${ban_pidfile}"
+       fi
+}
+
+# remove temporary files and directories
+#
+f_rmtemp()
+{
+       if [ -d "${ban_tmpdir}" ]
+       then
+               rm -rf "${ban_tmpdir}"
+       fi
+       > "${ban_pidfile}"
+}
+
+# iptables rules engine
+#
+f_iptrule()
+{
+       local rc timeout="-w 5" action="${1}" rule="${2}"
+
+       if [ "${src_name##*_}" = "6" ]
+       then
+               rc="$("${ban_ipt6}" "${timeout}" -C ${rule} 2>/dev/null; printf '%u' ${?})"
+
+               if ([ ${rc} -ne 0 ] && ([ "${action}" = "-A" ] || [ "${action}" = "-I" ])) \
+                  || ([ ${rc} -eq 0 ] && [ "${action}" = "-D" ])
+               then
+                       "${ban_ipt6}" "${timeout}" "${action}" ${rule}
+               fi
+       else
+               rc="$("${ban_ipt}" "${timeout}" -C ${rule} 2>/dev/null; printf '%u' ${?})"
+
+               if ([ ${rc} -ne 0 ] && ([ "${action}" = "-A" ] || [ "${action}" = "-I" ])) \
+                  || ([ ${rc} -eq 0 ] && [ "${action}" = "-D" ])
+               then
+                       "${ban_ipt}" "${timeout}" "${action}" ${rule}
+               fi
+       fi
+}
+
+# remove/add iptables rules
+#
+f_iptadd()
+{
+       local rm="${1}"
+
+       f_iptrule "-D" "${ban_chain} -i ${ban_dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j ${target_src}"
+       f_iptrule "-D" "${ban_chain} -o ${ban_dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j ${target_dst}"
+
+       if [ -z "${rm}" ] && [ ${cnt} -gt 0 ]
+       then
+               if [ "${src_ruletype}" != "dst" ]
+               then
+                       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"
+                       fi
+                       f_iptrule "-A" "${wan_input} -j ${ban_chain}"
+                       f_iptrule "-A" "${wan_forward} -j ${ban_chain}"
+                       f_iptrule "${action:-"-A"}" "${ban_chain} -i ${ban_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" ]
+                       then
+                               # dummy, special IPv6 rules
+                               /bin/true
+                       else
+                               f_iptrule "-I" "${lan_input} -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}"
+                       f_iptrule "${action:-"-A"}" "${ban_chain} -o ${ban_dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j ${target_dst}"
+               fi
+       else
+               if [ -n "$("${ban_ipset}" -n list "${src_name}" 2>/dev/null)" ]
+               then
+                       "${ban_ipset}" destroy "${src_name}"
+               fi
+       fi
+}
+
+# ipset/iptables actions
+#
+f_ipset()
+{
+       local rc cnt cnt_ip cnt_cidr size source action ruleset ruleset_6 rule timeout="-w 5" mode="${1}"
+
+       if [ "${src_name%_6*}" = "whitelist" ]
+       then
+               target_src="ACCEPT"
+               target_dst="ACCEPT"
+               action="-I"
+       fi
+
+       case "${mode}" in
+               initial)
+                       if [ -z "$("${ban_ipt}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
+                       then
+                               "${ban_ipt}" "${timeout}" -N "${ban_chain}"
+                       fi
+
+                       if [ -z "$("${ban_ipt6}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
+                       then
+                               "${ban_ipt6}" "${timeout}" -N "${ban_chain}"
+                       fi
+
+                       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
+
+                       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
+
+                       f_log "debug" "f_ipset ::: name: -, mode: ${mode:-"-"}, chain: ${ban_chain:-"-"}, ruleset: ${ruleset}, ruleset_6: ${ruleset_6}"
+               ;;
+               create)
+                       cnt="$(wc -l 2>/dev/null < "${tmp_file}")"
+                       cnt_cidr="$(grep -F "/" "${tmp_file}" | wc -l)"
+                       cnt_ip="$(( cnt - cnt_cidr ))"
+                       size="$(( cnt / 4 ))"
+
+                       if [ ${cnt} -gt 0 ]
+                       then
+                               if [ -z "$("${ban_ipset}" -n list "${src_name}" 2>/dev/null)" ]
+                               then
+                                       "${ban_ipset}" create "${src_name}" hash:"${src_settype}" hashsize "${size}" maxelem 262144 family "${src_setipv}" counters
+                               else
+                                       "${ban_ipset}" flush "${src_name}"
+                               fi
+
+                               "${ban_ipset}" -! restore < "${tmp_file}"
+                               printf "%s\n" "1" > "${tmp_set}"
+                               printf "%s\n" "${cnt}" > "${tmp_cnt}"
+                       fi
+                       f_iptadd
+
+                       end_ts="$(date +%s)"
+                       f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, settype: ${src_settype:-"-"}, setipv: "${src_setipv}", ruletype: ${src_ruletype:-"-"}, count(sum/ip/cidr): ${cnt:-0}/${cnt_ip:-0}/${cnt_cidr:-0}, time(s): $(( end_ts - start_ts ))"
+               ;;
+               refresh)
+                       if [ -n "$("${ban_ipset}" -n list "${src_name}" 2>/dev/null)" ]
+                       then
+                               "${ban_ipset}" save "${src_name}" > "${tmp_file}"
+                               if [ -s "${tmp_file}" ]
+                               then
+                                       cnt="$(( $(wc -l 2>/dev/null < "${tmp_file}") - 1 ))"
+                                       cnt_cidr="$(grep -F "/" "${tmp_file}" | wc -l)"
+                                       cnt_ip="$(( cnt - cnt_cidr ))"
+                                       printf "%s\n" "1" > "${tmp_set}"
+                                       printf "%s\n" "${cnt}" > "${tmp_cnt}"
+                               fi
+                               f_iptadd
+                       fi
+
+                       end_ts="$(date +%s)"
+                       f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, count: ${cnt:-0}/${cnt_ip:-0}/${cnt_cidr:-0}, time(s): $(( end_ts - start_ts ))"
+               ;;
+               flush)
+                       f_iptadd "remove"
+
+                       if [ -n "$("${ban_ipset}" -n list "${src_name}" 2>/dev/null)" ]
+                       then
+                               "${ban_ipset}" flush "${src_name}"
+                               "${ban_ipset}" destroy "${src_name}"
+                       fi
+
+                       f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}"
+               ;;
+               destroy)
+                       if [ -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}"
+                               "${ban_ipt}" "${timeout}" -X "${ban_chain}"
+                       fi
+
+                       if [ -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}"
+                               "${ban_ipt6}" "${timeout}" -X "${ban_chain}"
+                       fi
+
+                       for source in ${ban_sources}
+                       do
+                               if [ -n "$("${ban_ipset}" -n list "${source}" 2>/dev/null)" ]
+                               then
+                                       "${ban_ipset}" destroy "${source}"
+                               fi
+                       done
+
+                       f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}"
+               ;;
+       esac
+}
+
+# write to syslog
+#
+f_log()
+{
+       local class="${1}" log_msg="${2}"
+
+       if [ -n "${log_msg}" ] && ([ "${class}" != "debug" ] || [ ${ban_debug} -eq 1 ])
+       then
+               logger -p "${class}" -t "banIP-[${ban_ver}]" "${log_msg}"
+               if [ "${class}" = "err" ]
+               then
+                       f_jsnup error
+                       f_ipset destroy
+                       f_rmtemp
+                       logger -p "${class}" -t "banIP-[${ban_ver}]" "Please also check 'https://github.com/openwrt/packages/blob/master/net/banip/files/README.md'"
+                       exit 1
+               fi
+       fi
+}
+
+# main function for banIP processing
+#
+f_main()
+{
+       local start_ts end_ts ip tmp_raw tmp_cnt tmp_setcnt tmp_load tmp_file entry list suffix mem_total mem_free cnt=1
+       local src_name src_on src_url src_rset src_setipv src_settype src_ruletype src_cat src_log src_addon
+       local pid pid_list log_content="$(logread -e "dropbear")"
+       local wan_input wan_forward lan_input lan_forward target_src target_dst
+
+       mem_total="$(awk '/^MemTotal/ {print int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
+       mem_free="$(awk '/^MemFree/ {print int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
+       f_log "debug" "f_main  ::: fetch_util: ${ban_fetchinfo:-"-"}, fetch_parm: ${ban_fetchparm:-"-"}, iface: ${ban_iface:-"-"}, dev: ${ban_dev:-"-"}, mem_total: ${mem_total:-0}, mem_free: ${mem_free:-0}, max_queue: ${ban_maxqueue}"
+
+       f_ipset initial
+
+       # main loop
+       #
+       for src_name in ${ban_sources}
+       do
+               if [ "${src_name##*_}" = "6" ]
+               then
+                       src_on="$(eval printf '%s' \"\${ban_src_on_6_${src_name%_6*}\}\")"
+                       src_url="$(eval printf '%s' \"\${ban_src_6_${src_name%_6*}\}\")"
+                       src_rset="$(eval printf '%s' \"\${ban_src_rset_6_${src_name%_6*}\}\")"
+                       src_setipv="inet6"
+                       wan_input="${ban_wan_input_chain_6:-"input_wan_rule"}"
+                       wan_forward="${ban_wan_forward_chain_6:-"forwarding_wan_rule"}"
+                       lan_input="${ban_lan_input_chain_6:-"input_lan_rule"}"
+                       lan_forward="${ban_lan_forward_chain_6:-"forwarding_lan_rule"}"
+                       target_src="${ban_target_src_6:-"DROP"}"
+                       target_dst="${ban_target_dst_6:-"REJECT"}"
+               else
+                       src_on="$(eval printf '%s' \"\${ban_src_on_${src_name}\}\")"
+                       src_url="$(eval printf '%s' \"\${ban_src_${src_name}\}\")"
+                       src_rset="$(eval printf '%s' \"\${ban_src_rset_${src_name}\}\")"
+                       src_setipv="inet"
+                       wan_input="${ban_wan_input_chain:-"input_wan_rule"}"
+                       wan_forward="${ban_wan_forward_chain:-"forwarding_wan_rule"}"
+                       lan_input="${ban_lan_input_chain:-"input_lan_rule"}"
+                       lan_forward="${ban_lan_forward_chain:-"forwarding_lan_rule"}"
+                       target_src="${ban_target_src:-"DROP"}"
+                       target_dst="${ban_target_dst:-"REJECT"}"
+               fi
+               src_settype="$(eval printf '%s' \"\${ban_src_settype_${src_name%_6*}\}\")"
+               src_ruletype="$(eval printf '%s' \"\${ban_src_ruletype_${src_name%_6*}\}\")"
+               src_cat="$(eval printf '%s' \"\${ban_src_cat_${src_name%_6*}\}\")"
+               src_addon=""
+               tmp_load="${ban_tmpload}.${src_name}"
+               tmp_file="${ban_tmpfile}.${src_name}"
+               tmp_raw="${tmp_load}.raw"
+               tmp_cnt="${tmp_file}.cnt"
+               tmp_set="${tmp_file}.setcnt"
+
+               # basic pre-checks
+               #
+               f_log "debug" "f_main  ::: name: ${src_name}, src_on: ${src_on:-"-"}"
+
+               if [ "${src_on}" != "1" ] || [ -z "${src_url}" ] || [ -z "${src_rset}" ] ||\
+                       [ -z "${src_settype}" ] || [ -z "${src_ruletype}" ]
+               then
+                       f_ipset flush
+                       continue
+               fi
+
+               # download queue processing
+               #
+               (
+                       start_ts="$(date +%s)"
+                       if [ -f "${src_url}" ]
+                       then
+                               src_log="$(cat "${src_url}" 2>/dev/null > "${tmp_load}")"
+                               ban_rc=${?}
+
+                               case "${src_name}" in
+                                       whitelist)
+                                               src_addon="${ban_subnets}"
+                                       ;;
+                                       whitelist_6)
+                                               src_addon="${ban_subnets6}"
+                                       ;;
+                                       blacklist)
+                                               pid_list="$(printf "%s\n" "${log_content}" | grep -F "Exit before auth" | awk 'match($0,/(\[[0-9]+\])/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
+                                               for pid in ${pid_list}
+                                               do
+                                                       src_addon="${src_addon} $(printf "%s\n" "${log_content}" | grep -F "${pid}" | awk 'match($0,/([0-9]{1,3}\.){3}[0-9]{1,3}/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
+                                               done
+                                       ;;
+                                       blacklist_6)
+                                               pid_list="$(printf "%s\n" "${log_content}" | grep -F "Exit before auth" | awk 'match($0,/(\[[0-9]+\])/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
+                                               for pid in ${pid_list}
+                                               do
+                                                       src_addon="${src_addon} $(printf "%s\n" "${log_content}" | grep -F "${pid}" | awk 'match($0,/([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
+                                               done
+                                       ;;
+                               esac
+
+                               for ip in ${src_addon}
+                               do
+                                       if [ -z "$(grep -F "${ip}" "${src_url}")" ]
+                                       then
+                                               printf '\n%s\n' "${ip}" >> "${tmp_load}"
+                                               printf '\n%s\n' "${ip}" >> "${src_url}"
+                                       fi
+                               done
+                       elif [ -n "${src_cat}" ]
+                       then
+                               if [ "${src_cat//[0-9]/}" != "${src_cat}" ]
+                               then
+                                       for as in ${src_cat}
+                                       do
+                                               src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}AS${as}" 2>&1)"
+                                               ban_rc=${?}
+                                               if [ ${ban_rc} -eq 0 ]
+                                               then
+                                                       jsonfilter -i "${tmp_raw}" -e '@.data.prefixes.*.prefix' 2>/dev/null >> "${tmp_load}"
+                                               else
+                                                       break
+                                               fi
+                                       done
+                               else
+                                       for co in ${src_cat}
+                                       do
+                                               src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}${co}&v4_format=prefix" 2>&1)"
+                                               ban_rc=${?}
+                                               if [ ${ban_rc} -eq 0 ]
+                                               then
+                                                       if [ "${src_name##*_}" = "6" ]
+                                                       then
+                                                               jsonfilter -i "${tmp_raw}" -e '@.data.resources.ipv6.*' 2>/dev/null >> "${tmp_load}"
+                                                       else
+                                                               jsonfilter -i "${tmp_raw}" -e '@.data.resources.ipv4.*' 2>/dev/null >> "${tmp_load}"
+                                                       fi
+                                               else
+                                                       break
+                                               fi
+                                       done
+                               fi
+                       else
+                               src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}" 2>&1)"
+                               ban_rc=${?}
+                               if [ ${ban_rc} -eq 0 ]
+                               then
+                                       zcat "${tmp_raw}" 2>/dev/null > "${tmp_load}"
+                                       ban_rc=${?}
+                                       if [ ${ban_rc} -ne 0 ]
+                                       then
+                                               mv -f "${tmp_raw}" "${tmp_load}"
+                                               ban_rc=${?}
+                                       fi
+                               fi
+                       fi
+                       if [ ${ban_rc} -eq 0 ]
+                       then
+                               awk "${src_rset}" "${tmp_load}" 2>/dev/null | sort -u > "${tmp_file}"
+                               ban_rc=${?}
+                               if [ ${ban_rc} -eq 0 ]
+                               then
+                                       f_ipset create
+                               else
+                                       f_ipset refresh
+                               fi
+                       else
+                               src_log="$(printf '%s' "${src_log}" | awk '{ORS=" ";print $0}')"
+                               f_log "debug" "f_main  ::: name: ${src_name}, url: ${src_url}, rc: ${ban_rc}, log: ${src_log:-"-"}"
+                               f_ipset refresh
+                       fi
+               ) &
+               hold=$(( cnt % ban_maxqueue ))
+               if [ ${hold} -eq 0 ]
+               then
+                       wait
+               fi
+               cnt=$(( cnt + 1 ))
+       done
+
+       wait
+       if [ ${ban_rc} -eq 0 ]
+       then
+               for cnt in $(cat ${ban_tmpfile}.*.setcnt 2>/dev/null)
+               do
+                       ban_setcnt=$(( ban_setcnt + cnt ))
+               done
+               for cnt in $(cat ${ban_tmpfile}.*.cnt 2>/dev/null)
+               do
+                       ban_cnt=$(( ban_cnt + cnt ))
+               done
+               f_log "info" "${ban_setcnt} IPSets with overall ${ban_cnt} IPs/Prefixes loaded successfully (${ban_sysver})"
+       fi
+       f_jsnup
+       f_rmtemp
+       exit ${ban_rc}
+}
+
+# update runtime information
+#
+f_jsnup()
+{
+       local rundate="$(/bin/date "+%d.%m.%Y %H:%M:%S")" status="${1:-"enabled"}"
+
+       ban_cntinfo="${ban_setcnt} IPSets with overall ${ban_cnt} IPs/Prefixes"
+
+       json_add_string "status" "${status}"
+       json_add_string "version" "${ban_ver}"
+       json_add_string "fetch_info" "${ban_fetchinfo:-"-"}"
+       json_add_string "ipset_info" "${ban_cntinfo:-"-"}"
+       json_add_string "last_run" "${rundate:-"-"}"
+       json_add_string "system" "${ban_sysver}"
+       json_dump > "${ban_rtfile}"
+
+       f_log "debug" "f_jsnup ::: status: ${status}, setcnt: ${ban_setcnt}, cnt: ${ban_cnt}"
+}
+
+# source required system libraries
+#
+if [ -r "/lib/functions.sh" ] && [ -r "/lib/functions/network.sh" ] && [ -r "/usr/share/libubox/jshn.sh" ]
+then
+       . "/lib/functions.sh"
+       . "/lib/functions/network.sh"
+       . "/usr/share/libubox/jshn.sh"
+else
+       f_log "err" "system libraries not found"
+fi
+
+# initialize json runtime file
+#
+json_load_file "${ban_rtfile}" >/dev/null 2>&1
+json_select data >/dev/null 2>&1
+if [ ${?} -ne 0 ]
+then
+       > "${ban_rtfile}"
+       json_init
+       json_add_object "data"
+fi
+
+# handle different banIP actions
+#
+f_envload
+case "${ban_action}" in
+       stop)
+               f_jsnup stopped
+               f_ipset destroy
+               f_rmtemp
+       ;;
+       start|restart|reload)
+               f_envcheck
+               f_main
+       ;;
+esac
diff --git a/net/banip/files/banip.whitelist b/net/banip/files/banip.whitelist
new file mode 100644 (file)
index 0000000..e69de29