banip: new package to block incoming & outgoing ip addresses

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>
This commit is contained in:
Dirk Brenken 2018-11-10 11:01:45 +01:00
parent d785b15857
commit b17588a856
8 changed files with 1119 additions and 0 deletions

64
net/banip/Makefile Normal file
View File

@ -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))

75
net/banip/files/README.md Normal file
View File

@ -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

View File

223
net/banip/files/banip.conf Normal file
View File

@ -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'

View File

@ -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

74
net/banip/files/banip.init Executable file
View File

@ -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"
}

671
net/banip/files/banip.sh Executable file
View File

@ -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

View File