#
-# Copyright (c) 2018-2021 Dirk Brenken (dev@brenken.org)
+# banIP - ban incoming and outgoing ip adresses/subnets via sets in nftables
+# Copyright (c) 2018-2023 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.7.10
-PKG_RELEASE:=6
+PKG_VERSION:=0.8.0
+PKG_RELEASE:=1
PKG_LICENSE:=GPL-3.0-or-later
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
define Package/banip
SECTION:=net
CATEGORY:=Network
- TITLE:=Ban incoming and outgoing ip adresses via ipsets
- DEPENDS:=+jshn +jsonfilter +ip +ipset +iptables +ca-bundle @BROKEN
+ TITLE:=banIP blocks IP addresses via named nftables sets
+ DEPENDS:=+jshn +jsonfilter +firewall4 +ca-bundle +logd +rpcd +rpcd-mod-rpcsys
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.
+banIP blocks IP addresses via named nftables sets.
+banIP supports many IP blocklist feeds and provides a log service to block suspicious IPs in realtime.
Please see https://github.com/openwrt/packages/blob/master/net/banip/files/README.md for further information.
endef
define Package/banip/conffiles
/etc/config/banip
-/etc/banip/banip.maclist
-/etc/banip/banip.blacklist
-/etc/banip/banip.whitelist
+/etc/banip/banip.allowlist
+/etc/banip/banip.blocklist
endef
define Build/Prepare
define Package/banip/install
$(INSTALL_DIR) $(1)/usr/bin
- $(INSTALL_BIN) ./files/banip.sh $(1)/usr/bin
+ $(INSTALL_BIN) ./files/banip-service.sh $(1)/usr/bin
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/banip.init $(1)/etc/init.d/banip
+ $(INSTALL_DIR) $(1)/usr/lib
+ $(INSTALL_CONF) ./files/banip-functions.sh $(1)/usr/lib
+
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/banip.conf $(1)/etc/config/banip
$(INSTALL_DIR) $(1)/etc/banip
- $(INSTALL_BIN) ./files/banip.dns $(1)/etc/banip
- $(INSTALL_BIN) ./files/banip.mail $(1)/etc/banip
- $(INSTALL_BIN) ./files/banip.service $(1)/etc/banip
- $(INSTALL_CONF) ./files/banip.maclist $(1)/etc/banip
- $(INSTALL_CONF) ./files/banip.blacklist $(1)/etc/banip
- $(INSTALL_CONF) ./files/banip.whitelist $(1)/etc/banip
- $(INSTALL_CONF) ./files/banip.countries $(1)/etc/banip
- $(INSTALL_CONF) ./files/banip.sources $(1)/etc/banip
- gzip -9n $(1)/etc/banip/banip.sources
-
- $(INSTALL_DIR) $(1)/etc/hotplug.d/firewall
- $(INSTALL_DATA) ./files/banip.hotplug $(1)/etc/hotplug.d/firewall/30-banip
+ $(INSTALL_CONF) ./files/banip.tpl $(1)/etc/banip
+ $(INSTALL_CONF) ./files/banip.allowlist $(1)/etc/banip
+ $(INSTALL_CONF) ./files/banip.blocklist $(1)/etc/banip
+ $(INSTALL_CONF) ./files/banip.feeds $(1)/etc/banip
+ gzip -9n $(1)/etc/banip/banip.feeds
endef
$(eval $(call BuildPackage,banip))
<!-- markdownlint-disable -->
-# banIP - ban incoming and/or outgoing ip adresses via ipsets
+# banIP - ban incoming and outgoing IP addresses/subnets via sets in nftables
## Description
-IP address blocking is commonly used to protect against brute force attacks, prevent disruptive or unauthorized address(es) from access or it can be used to restrict access to or from a particular geographic area — for example.
+IP address blocking is commonly used to protect against brute force attacks, prevent disruptive or unauthorized address(es) from access or it can be used to restrict access to or from a particular geographic area — for example. Further more banIP scans the log file via logread and bans IP addresses that make too many password failures, e.g. via ssh.
## Main Features
-* Support of the following fully pre-configured domain blocklist sources (free for private usage, for commercial use please check their individual licenses)
+* banIP supports the following fully pre-configured domain blocklist feeds (free for private usage, for commercial use please check their individual licenses).
+ **Please note:** the columns "INP" and "FWD" show for which chains the feeds are suitable in common scenarios, e.g. the first entry should be limited to forward chain - see the config options 'ban\_blockforward' and 'ban\_blockinput' below.
-| Source | Focus | Information |
-| :------------------ | :----------------------------: | :-------------------------------------------------------------------------------- |
-| asn | ASN block | [Link](https://asn.ipinfo.app) |
-| bogon | Bogon prefixes | [Link](https://team-cymru.com) |
-| country | Country blocks | [Link](https://www.ipdeny.com/ipblocks) |
-| darklist | blocks suspicious attacker IPs | [Link](https://darklist.de) |
-| debl | Fail2ban IP blacklist | [Link](https://www.blocklist.de) |
-| doh | Public DoH-Provider | [Link](https://github.com/dibdot/DoH-IP-blocklists) |
-| drop | Spamhaus drop compilation | [Link](https://www.spamhaus.org) |
-| dshield | Dshield IP blocklist | [Link](https://www.dshield.org) |
-| edrop | Spamhaus edrop compilation | [Link](https://www.spamhaus.org) |
-| feodo | Feodo Tracker | [Link](https://feodotracker.abuse.ch) |
-| firehol1 | Firehol Level 1 compilation | [Link](https://iplists.firehol.org/?ipset=firehol_level1) |
-| firehol2 | Firehol Level 2 compilation | [Link](https://iplists.firehol.org/?ipset=firehol_level2) |
-| firehol3 | Firehol Level 3 compilation | [Link](https://iplists.firehol.org/?ipset=firehol_level3) |
-| firehol4 | Firehol Level 4 compilation | [Link](https://iplists.firehol.org/?ipset=firehol_level4) |
-| greensnow | blocks suspicious server IPs | [Link](https://greensnow.co) |
-| iblockads | Advertising blocklist | [Link](https://www.iblocklist.com) |
-| iblockspy | Malicious spyware blocklist | [Link](https://www.iblocklist.com) |
-| myip | Myip Live IP blacklist | [Link](https://myip.ms) |
-| nixspam | iX spam protection | [Link](http://www.nixspam.org) |
-| proxy | Firehol list of open proxies | [Link](https://iplists.firehol.org/?ipset=proxylists) |
-| ssbl | SSL botnet IP blacklist | [Link](https://sslbl.abuse.ch) |
-| talos | Cisco Talos IP Blacklist | [Link](https://talosintelligence.com/reputation_center) |
-| threat | Emerging Threats | [Link](https://rules.emergingthreats.net) |
-| tor | Tor exit nodes | [Link](https://fissionrelays.net/lists) |
-| uceprotect1 | Spam protection level 1 | [Link](http://www.uceprotect.net/en/index.php) |
-| uceprotect2 | Spam protection level 2 | [Link](http://www.uceprotect.net/en/index.php) |
-| voip | VoIP fraud blocklist | [Link](http://www.voipbl.org) |
-| yoyo | Ad protection blacklist | [Link](https://pgl.yoyo.org/adservers/) |
+| Feed | Focus | INP | FWD | Information |
+| :------------------ | :----------------------------: | :-: | :-: | :-------------------------------------------------------------------- |
+| adaway | adaway IPs | | x | [Link](https://github.com/dibdot/banIP-IP-blocklists) |
+| adguard | adguard IPs | | x | [Link](https://github.com/dibdot/banIP-IP-blocklists) |
+| adguardtrackers | adguardtracker IPs | | x | [Link](https://github.com/dibdot/banIP-IP-blocklists) |
+| antipopads | antipopads IPs | | x | [Link](https://github.com/dibdot/banIP-IP-blocklists) |
+| asn | ASN IPs | | x | [Link](https://asn.ipinfo.app) |
+| backscatterer | backscatterer IPs | x | x | [Link](https://www.uceprotect.net/en/index.php) |
+| bogon | bogon prefixes | x | x | [Link](https://team-cymru.com) |
+| country | country blocks | x | | [Link](https://www.ipdeny.com/ipblocks) |
+| cinsscore | suspicious attacker IPs | x | x | [Link](https://cinsscore.com/#list) |
+| darklist | blocks suspicious attacker IPs | x | x | [Link](https://darklist.de) |
+| debl | fail2ban IP blacklist | x | x | [Link](https://www.blocklist.de) |
+| doh | public DoH-Provider | | x | [Link](https://github.com/dibdot/DoH-IP-blocklists) |
+| drop | spamhaus drop compilation | x | x | [Link](https://www.spamhaus.org) |
+| dshield | dshield IP blocklist | x | x | [Link](https://www.dshield.org) |
+| edrop | spamhaus edrop compilation | x | x | [Link](https://www.spamhaus.org) |
+| feodo | feodo tracker | x | x | [Link](https://feodotracker.abuse.ch) |
+| firehol1 | firehol level 1 compilation | x | x | [Link](https://iplists.firehol.org/?ipset=firehol_level1) |
+| firehol2 | firehol level 2 compilation | x | x | [Link](https://iplists.firehol.org/?ipset=firehol_level2) |
+| firehol3 | firehol level 3 compilation | x | x | [Link](https://iplists.firehol.org/?ipset=firehol_level3) |
+| firehol4 | firehol level 4 compilation | x | x | [Link](https://iplists.firehol.org/?ipset=firehol_level4) |
+| greensnow | suspicious server IPs | x | x | [Link](https://greensnow.co) |
+| iblockads | Advertising IPs | | x | [Link](https://www.iblocklist.com) |
+| iblockspy | Malicious spyware IPs | x | x | [Link](https://www.iblocklist.com) |
+| myip | real-time IP blocklist | x | x | [Link](https://myip.ms) |
+| nixspam | iX spam protection | x | x | [Link](http://www.nixspam.org) |
+| oisdnsfw | OISD-nsfw IPs | | x | [Link](https://github.com/dibdot/banIP-IP-blocklists) |
+| oisdsmall | OISD-small IPs | | x | [Link](https://github.com/dibdot/banIP-IP-blocklists) |
+| proxy | open proxies | x | | [Link](https://iplists.firehol.org/?ipset=proxylists) |
+| ssbl | SSL botnet IPs | x | x | [Link](https://sslbl.abuse.ch) |
+| stevenblack | stevenblack IPs | | x | [Link](https://github.com/dibdot/banIP-IP-blocklists) |
+| talos | talos IPs | x | x | [Link](https://talosintelligence.com/reputation_center) |
+| threat | emerging threats | x | x | [Link](https://rules.emergingthreats.net) |
+| threatview | malicious IPs | x | x | [Link](https://threatview.io) |
+| tor | tor exit nodes | x | | [Link](https://github.com/SecOps-Institute/Tor-IP-Addresses) |
+| uceprotect1 | spam protection level 1 | x | x | [Link](http://www.uceprotect.net/en/index.php) |
+| uceprotect2 | spam protection level 2 | x | x | [Link](http://www.uceprotect.net/en/index.php) |
+| uceprotect3 | spam protection level 3 | x | x | [Link](http://www.uceprotect.net/en/index.php) |
+| urlhaus | urlhaus IDS IPs | x | x | [Link](https://urlhaus.abuse.ch) |
+| urlvir | malware related IPs | x | x | [Link](https://iplists.firehol.org/?ipset=urlvir) |
+| webclient | malware related IPs | x | x | [Link](https://iplists.firehol.org/?ipset=firehol_webclient) |
+| voip | VoIP fraud blocklist | x | x | [Link](https://voipbl.org) |
+| yoyo | yoyo IPs | | x | [Link](https://github.com/dibdot/banIP-IP-blocklists) |
* zero-conf like automatic installation & setup, usually no manual changes needed
-* automatically selects one of the following supported download utilities: aria2c, curl, uclient-fetch, wget
-* fast downloads & list processing as they are handled in parallel as background jobs in a configurable 'Download Queue'
+* all sets are handled in a separate nft table/namespace 'banIP'
* 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 black- & whitelist (IPv4, IPv6, CIDR notation or domain names)
-* auto-add unsuccessful LuCI, nginx or ssh login attempts via 'dropbear'/'sshd' to local blacklist
-* auto-add the uplink subnet to local whitelist
-* black- and whitelist also accept domain names as input to allow IP filtering based on these names
-* supports a 'whitelist only' mode, this option allows to restrict Internet access from/to a small number of secure websites/IPs
+* supports nft atomic set loading
+* supports blocking by ASN numbers and by iso country codes
+* supports local allow- and blocklist (IPv4, IPv6, CIDR notation or domain names)
+* auto-add the uplink subnet to the local allowlist
* provides a small background log monitor to ban unsuccessful login attempts in real-time
-* per source configuration of SRC (incoming) and DST (outgoing)
-* integrated IPSet-Lookup
-* integrated bgpview-Lookup
-* blocklist source parsing by fast & flexible regex rulesets
+* auto-add unsuccessful LuCI, nginx, Asterisk or ssh login attempts to the local blocklist
+* fast feed processing as they are handled in parallel as background jobs
+* per feed it can be defined whether the input chain or the forward chain should be blocked (default: both chains)
+* automatic blocklist backup & restore, the backups will be used in case of download errors or during startup
+* automatically selects one of the following download utilities with ssl support: aria2c, curl, uclient-fetch or wget
+* supports a 'allowlist only' mode, this option restricts internet access from/to a small number of secure websites/IPs
+* provides comprehensive runtime information
+* provides a detailed set report
+* provides a set search engine for certain IPs
+* feed 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/refresh/status)
+* procd based init system support (start/stop/restart/reload/status/report/search)
* procd network interface trigger support
-* automatic blocklist backup & restore, they will be used in case of download errors or during startup
-* provides comprehensive runtime information
-* provides a detailed IPSet Report
-* provides a powerful query function to quickly find blocked IPs/CIDR in banIP related IPSets
-* provides an easily configurable blocklist update scheduler called 'Refresh Timer'
-* strong LuCI support
-* optional: add new banIP sources on your own
+* ability to add new banIP feeds on your own
## Prerequisites
-* [OpenWrt](https://openwrt.org), tested with the stable release series (21.02.x) and with the latest rolling snapshot releases. On turris devices it has been successfully tested with TurrisOS 5.2.x
- <b>Please note:</b> Ancient OpenWrt releases like 18.06.x or 17.01.x are _not_ supported!
- <b>Please note:</b> Devices with less than 128 MByte RAM are _not_ supported!
- <b>Please note:</b> If you're updating from former banIP 0.3x please manually remove your config (/etc/config/banip) before you start!
-* A download utility with SSL support: 'wget', 'uclient-fetch' with one of the 'libustream-*' ssl libraries, 'aria2c' or 'curl' is required
-* A certificate store like 'ca-bundle', as banIP checks the validity of the SSL certificates of all download sites by default
-* Optional E-Mail notification support: for E-Mail notifications you need to install and setup the additional 'msmtp' package
+* **[OpenWrt](https://openwrt.org)**, latest stable release or a snapshot with nft/firewall 4 support
+* a download utility with SSL support: 'wget', 'uclient-fetch' with one of the 'libustream-*' SSL libraries, 'aria2c' or 'curl' is required
+* a certificate store like 'ca-bundle', as banIP checks the validity of the SSL certificates of all download sites by default
+* for E-Mail notifications you need to install and setup the additional 'msmtp' package
+
+**Please note the following:**
+* Devices with less than 256Mb of RAM are **_not_** supported
+* Any previous installation of banIP must be uninstalled, and the /etc/banip folder and the /etc/config/banip configuration file must be deleted (they are recreated when this version is installed)
+* There is no LuCI frontend at this time
## Installation & Usage
-* Update your local opkg repository (_opkg update_)
-* Install 'banip' (_opkg install banip_). The banIP service is disabled by default
-* Install the LuCI companion package 'luci-app-banip' (_opkg install luci-app-banip_)
-* It's strongly recommended to use the LuCI frontend to easily configure all aspects of banIP, the application is located in LuCI under the 'Services' menu
+* update your local opkg repository (_opkg update_)
+* install banIP (_opkg install banip_) - the banIP service is disabled by default
+* edit the config file '/etc/config/banip' and enable the service (set ban\_enabled to '1'), then add pre-configured feeds via 'ban\_feed' (see the config options below)
+* start the service with '/etc/init.d/banip start' and check check everything is working by running '/etc/init.d/banip status'
-## banIP CLI
-* All important banIP functions are accessible via CLI as well.
-<pre><code>
-~# /etc/init.d/banip
+## banIP CLI interface
+* All important banIP functions are accessible via CLI. A LuCI frontend will be available in due course.
+```
+~# /etc/init.d/banip
Syntax: /etc/init.d/banip [command]
Available commands:
enable Enable service autostart
disable Disable service autostart
enabled Check if service is started on boot
- refresh Refresh ipsets without new list downloads
- suspend Suspend banIP processing
- resume Resume banIP processing
- query <IP> Query active banIP IPSets for a specific IP address
- report [<cli>|<mail>|<gen>|<json>] Print banIP related IPset statistics
- list [<add>|<add_asn>|<add_country>|<remove>|<remove_asn>|<remove_country>] <source(s)> List/Edit available sources
- timer [<add> <tasks> <hour> [<minute>] [<weekday>]]|[<remove> <line no.>] List/Edit cron update intervals
- version Print version information
+ report [text|json|mail] Print banIP related set statistics
+ search [<IPv4 address>|<IPv6 address>] Check if an element exists in the banIP sets
running Check if service is running
status Service status
trace Start with syscall trace
-</code></pre>
+ info Dump procd service info
+```
## banIP config options
-* Usually the auto pre-configured banIP setup works quite well and no manual overrides are needed
| Option | Type | Default | Description |
| :---------------------- | :----- | :---------------------------- | :------------------------------------------------------------------------------------ |
| ban_enabled | option | 0 | enable the banIP service |
+| ban_nicelimit | option | 0 | ulimit nice level of the banIP service (range 0-19) |
+| ban_filelimit | option | 1024 | ulimit max open/number of files (range 1024-4096) |
+| ban_loglimit | option | 100 | the logread monitor scans only the last n lines of the logfile |
+| ban_logcount | option | 1 | how many times the IP must appear in the log to be considered as suspicious |
+| ban_logterm | list | regex | various regex for logfile parsing (default: dropbear, sshd, luci, nginx, asterisk) |
| ban_autodetect | option | 1 | auto-detect wan interfaces, devices and subnets |
| ban_debug | option | 0 | enable banIP related debug logging |
-| ban_mail_enabled | option | 0 | enable the mail service |
-| ban_monitor_enabled | option | 0 | enable the log monitor, e.g. to catch failed ssh/luci logins |
-| ban_logsrc_enabled | option | 0 | enable the src-related logchain |
-| ban_logdst_enabled | option | 0 | enable the dst-related logchain |
-| ban_autoblacklist | option | 1 | add suspicious IPs automatically to the local blacklist |
-| ban_autowhitelist | option | 1 | add wan IPs/subnets automatically to the local whitelist |
-| ban_whitelistonly | option | 0 | allow to restrict Internet access from/to a small number of secure websites/IPs |
-| ban_maxqueue | option | 4 | size of the download queue to handle downloads and processing in parallel |
-| ban_reportdir | option | /tmp/banIP-Report | directory where banIP stores the report files |
-| ban_backupdir | option | /tmp/banIP-Backup | directory where banIP stores the compressed backup files |
-| ban_ifaces | list | - | list option to add logical wan interfaces manually |
-| ban_sources | list | - | list option to add banIP sources |
-| ban_countries | list | - | list option to add certain countries as an alpha-2 ISO code, e.g. 'de' for germany |
-| ban_asns | list | - | list option to add certain ASNs (autonomous system number), e.g. '32934' for facebook |
-| ban_chain | option | banIP | name of the root chain used by banIP |
-| ban_global_settype | option | src+dst | global settype as default for all sources |
-| ban_settype_src | list | - | special SRC settype for a certain sources |
-| ban_settype_dst | list | - | special DST settype for a certain sources |
-| ban_settype_all | list | - | special SRC+DST settype for a certain sources |
-| ban_target_src | option | DROP | default src action (used by log chains as well) |
-| ban_target_dst | option | REJECT | default dst action (used by log chains as well) |
-| ban_lan_inputchains_4 | list | input_lan_rule | list option to add IPv4 lan input chains |
-| ban_lan_inputchains_6 | list | input_lan_rule | list option to add IPv6 lan input chains |
-| ban_lan_forwardchains_4 | list | forwarding_lan_rule | list option to add IPv4 lan forward chains |
-| ban_lan_forwardchains_6 | list | forwarding_lan_rule | list option to add IPv6 lan forward chains |
-| ban_wan_inputchains_4 | list | input_wan_rule | list option to add IPv4 wan input chains |
-| ban_wan_inputchains_6 | list | input_wan_rule | list option to add IPv6 wan input chains |
-| ban_wan_forwardchains_4 | list | forwarding_wan_rule | list option to add IPv4 wan forward chains |
-| ban_wan_forwardchains_6 | list | forwarding_wan_rule | list option to add IPv6 wan forward chains |
-| ban_fetchutil | option | -, auto-detected | 'uclient-fetch', 'wget', 'curl' or 'aria2c' |
-| ban_fetchparm | option | -, auto-detected | manually override the config options for the selected download utility |
-| ban_fetchinsecure | option | 0, disabled | don't check SSL server certificates during download |
+| ban_loginput | option | 1 | log drops in the input chain |
+| ban_logforward | option | 0 | log rejects in the forward chain |
+| ban_autoallowlist | option | 1 | add wan IPs/subnets automatically to the local allowlist |
+| ban_autoblocklist | option | 1 | add suspicious attacker IPs automatically to the local blocklist |
+| ban_allowlistonly | option | 0 | restrict the internet access from/to a small number of secure websites/IPs |
+| ban_reportdir | option | /tmp/banIP-report | directory where banIP stores the report files |
+| ban_backupdir | option | /tmp/banIP-backup | directory where banIP stores the compressed backup files |
+| ban_protov4 | option | - / autodetect | enable IPv4 support |
+| ban_protov6 | option | - / autodetect | enable IPv4 support |
+| ban_ifv4 | list | - / autodetect | logical wan IPv4 interfaces, e.g. 'wan' |
+| ban_ifv6 | list | - / autodetect | logical wan IPv6 interfaces, e.g. 'wan6' |
+| ban_dev | list | - / autodetect | wan device(s), e.g. 'eth2' |
+| ban_trigger | list | - | logical startup trigger interface(s), e.g. 'wan' |
+| ban_triggerdelay | option | 10 | trigger timeout before banIP processing begins |
+| ban_deduplicate | option | 1 | deduplicate IP addresses across all active sets |
+| ban_splitsize | option | 0 | split ext. sets after every n lines/members (saves RAM) |
+| ban_cores | option | - / autodetect | limit the cpu cores used by banIP (saves RAM) |
+| ban_nftexpiry | option | - | expiry time for auto added blocklist members, e.g. '5m', '2h' or '1d' |
+| ban_nftpriority | option | -200 | nft banIP table priority (default is the prerouting table priority) |
+| ban_feed | list | - | external download feeds, e.g. 'yoyo', 'doh', 'country' or 'talos' (see feed table) |
+| ban_asn | list | - | ASNs for the 'asn' feed, e.g.'32934' |
+| ban_country | list | - | country iso codes for the 'country' feed, e.g. 'ru' |
+| ban_blockinput | list | - | limit a feed to the input chain, e.g. 'country' |
+| ban_blockforward | list | - | limit a feed to the forward chain, e.g. 'doh' |
+| ban_fetchcmd | option | - / autodetect | 'uclient-fetch', 'wget', 'curl' or 'aria2c' |
+| ban_fetchparm | option | - / autodetect | set the config options for the selected download utility |
+| ban_fetchinsecure | option | 0 | don't check SSL server certificates during download |
| ban_mailreceiver | option | - | receiver address for banIP related notification E-Mails |
| ban_mailsender | option | no-reply@banIP | sender address for banIP related notification E-Mails |
| ban_mailtopic | option | banIP notification | topic for banIP related notification E-Mails |
| ban_mailprofile | option | ban_notify | mail profile used in 'msmtp' for banIP related notification E-Mails |
-| ban_srcarc | option | /etc/banip/banip.sources.gz | full path to the compressed source archive file used by banIP |
-| ban_localsources | list | maclist, whitelist, blacklist | limit the selection to certain local sources |
-| ban_extrasources | list | - | add additional, non-banIP related IPSets e.g. for reporting or queries |
-| ban_maclist_timeout | option | - | individual maclist IPSet timeout |
-| ban_whitelist_timeout | option | - | individual whitelist IPSet timeout |
-| ban_blacklist_timeout | option | - | individual blacklist IPSet timeout |
-| ban_logterms | list | dropbear, sshd, luci, nginx | limit the log monitor to certain log terms |
-| ban_loglimit | option | 100 | parse only the last stated number of log entries for suspicious events |
-| ban_ssh_logcount | option | 3 | number of the failed ssh login repetitions of the same ip in the log before banning |
-| ban_luci_logcount | option | 3 | number of the failed luci login repetitions of the same ip in the log before banning |
-| ban_nginx_logcount | option | 5 | number of the failed nginx requests of the same ip in the log before banning |
-
-## Examples
-**list/edit banIP sources:**
-<pre><code>
-~# /etc/init.d/banip list
-::: Available banIP sources
-:::
- Name Enabled Focus Info URL
- ---------------------------------------------------------------------------
- + asn ASN blocks https://asn.ipinfo.app
- + bogon Bogon prefixes https://team-cymru.com
- + country x Country blocks https://www.ipdeny.com/ipblocks
- + darklist x Blocks suspicious attacker IPs https://darklist.de
- + debl x Fail2ban IP blacklist https://www.blocklist.de
- + doh x Public DoH-Provider https://github.com/dibdot/DoH-IP-blocklists
- + drop x Spamhaus drop compilation https://www.spamhaus.org
- + dshield x Dshield IP blocklist https://www.dshield.org
- + edrop Spamhaus edrop compilation https://www.spamhaus.org
- + feodo x Feodo Tracker https://feodotracker.abuse.ch
- + firehol1 x Firehol Level 1 compilation https://iplists.firehol.org/?ipset=firehol_level1
- + firehol2 Firehol Level 2 compilation https://iplists.firehol.org/?ipset=firehol_level2
- + firehol3 Firehol Level 3 compilation https://iplists.firehol.org/?ipset=firehol_level3
- + firehol4 Firehol Level 4 compilation https://iplists.firehol.org/?ipset=firehol_level4
- + greensnow x Blocks suspicious server IPs https://greensnow.co
- + iblockads Advertising blocklist https://www.iblocklist.com
- + iblockspy x Malicious spyware blocklist https://www.iblocklist.com
- + myip Myip Live IP blacklist https://myip.ms
- + nixspam x iX spam protection http://www.nixspam.org
- + proxy Firehol list of open proxies https://iplists.firehol.org/?ipset=proxylists
- + sslbl x SSL botnet IP blacklist https://sslbl.abuse.ch
- + talos x Cisco Talos IP Blacklist https://talosintelligence.com/reputation_center
- + threat x Emerging Threats https://rules.emergingthreats.net
- + tor x Tor exit nodes https://fissionrelays.net/lists
- + uceprotect1 x Spam protection level 1 http://www.uceprotect.net/en/index.php
- + uceprotect2 Spam protection level 2 http://www.uceprotect.net/en/index.php
- + voip x VoIP fraud blocklist http://www.voipbl.org
- + yoyo x Ad protection blacklist https://pgl.yoyo.org/adservers/
- ---------------------------------------------------------------------------
- * Configured ASNs: -
- * Configured Countries: af, bd, br, cn, hk, hu, id, il, in, iq, ir, kp, kr, no, pk, pl, ro, ru, sa, th, tr, ua, gb
-</code></pre>
-
-**receive banIP runtime information:**
-<pre><code>
-~# /etc/init.d/banip status
-::: banIP runtime information
- + status : enabled
- + version : 0.7.7
- + ipset_info : 2 IPSets with 30 IPs/Prefixes
- + active_sources : whitelist
- + active_devs : wlan0
- + active_ifaces : trm_wwan, trm_wwan6
- + active_logterms : dropbear, sshd, luci, nginx
- + active_subnets : xxx.xxx.xxx.xxx/24, xxxx:xxxx:xxxx:xx::xxx/128
- + run_infos : settype: src+dst, backup_dir: /tmp/banIP-Backup, report_dir: /tmp/banIP-Report
- + run_flags : protocols (4/6): ✔/✔, log (src/dst): ✔/✘, monitor: ✔, mail: ✘, whitelist only: ✔
- + last_run : restart, 0m 3s, 122/30/14, 21.04.2021 20:14:36
- + system : TP-Link RE650 v1, OpenWrt SNAPSHOT r16574-f7e00d81bc
-</code></pre>
-
-**black-/whitelist handling:**
-banIP supports a local black & whitelist (IPv4, IPv6, CIDR notation or domain names), located by default in /etc/banip/banip.whitelist and /etc/banip/banip.blacklist.
-Unsuccessful LuCI logins, suspicious nginx request or ssh login attempts via 'dropbear'/'sshd' could be tracked and automatically added to the local blacklist (see the 'ban_autoblacklist' option). Furthermore the uplink subnet could be automatically added to local whitelist (see 'ban_autowhitelist' option). The list behaviour could be further tweaked with different timeout and counter options (see the config options section above).
-Last but not least, both lists also accept domain names as input to allow IP filtering based on these names. The corresponding IPs (IPv4 & IPv6) will be resolved in a detached background process and added to the IPsets. The detached name lookup takes place only during 'restart' or 'reload' action, 'start' and 'refresh' actions are using an auto-generated backup instead.
-
-**whitelist-only mode:**
-banIP supports a "whitelist only" mode. This option allows to restrict the internet access from/to a small number of secure websites/IPs, and block access from/to the rest of the internet. All IPs and Domains which are _not_ listed in the whitelist are blocked. Please note: suspend/resume does not work in this mode.
-
-**Manually override the download options:**
-By default banIP uses the following pre-configured download options:
-* aria2c: <code>--timeout=20 --allow-overwrite=true --auto-file-renaming=false --log-level=warn --dir=/ -o</code>
-* curl: <code>--connect-timeout 20 --silent --show-error --location -o</code>
-* uclient-fetch: <code>--timeout=20 -O</code>
-* wget: <code>--no-cache --no-cookies --max-redirect=0 --timeout=20 -O</code>
+| ban_resolver | option | - | external resolver used for DNS lookups |
+| ban_feedarchive | option | /etc/banip/banip.feeds.gz | full path to the compressed feed archive file used by banIP |
-To override the default set 'ban_fetchparm' manually to your needs.
-
-**generate an IPSet report:**
-<pre><code>
+## Examples
+**banIP report information**
+```
~# /etc/init.d/banip report
:::
-::: report on all banIP related IPSets
+::: banIP Set Statistics
:::
- + Report timestamp ::: 04.02.2021 06:24:41
- + Number of all IPSets ::: 24
- + Number of all entries ::: 302448
- + Number of IP entries ::: 224748
- + Number of CIDR entries ::: 77700
- + Number of MAC entries ::: 0
- + Number of accessed entries ::: 36
+ Timestamp: 2023-02-08 22:12:40
+ ------------------------------
+ auto-added to allowlist: 1
+ auto-added to blocklist: 0
+
+ Set | Set Elements | Chain Input | Chain Forward | Input Packets | Forward Packets
+ ---------------------+---------------+---------------+---------------+---------------+----------------
+ allowlistvMAC | 0 | n/a | OK | n/a | 0
+ allowlistv4 | 1 | OK | OK | 0 | 0
+ allowlistv6 | 0 | OK | OK | 0 | 0
+ blocklistvMAC | 0 | n/a | OK | n/a | 0
+ blocklistv4 | 0 | OK | OK | 0 | 0
+ blocklistv6 | 0 | OK | OK | 0 | 0
+ dohv4 | 542 | n/a | OK | n/a | 22
+ adguardv4 | 23007 | n/a | OK | n/a | 18
+ yoyov4 | 1936 | n/a | OK | n/a | 1
+ oisdbasicv4 | 26000 | n/a | OK | n/a | 325
+ ---------------------+---------------+---------------+---------------+---------------+----------------
+ 10 | 51486 | 4 | 10 | 0 | 366
+```
+
+**banIP runtime information**
+```
+~# etc/init.d/banip status
+::: banIP runtime information
+ + status : active
+ + version : 0.8.0
+ + element_count : 51486
+ + active_feeds : allowlistvMAC, allowlistv4, allowlistv6, blocklistvMAC, blocklistv4, blocklistv6, dohv4, adguardv4
+ , yoyov4, oisdbasicv4
+ + active_devices : eth2
+ + active_interfaces : wan
+ + active_subnets : 192.168.98.107/24
+ + run_info : base_dir: /tmp, backup_dir: /tmp/banIP-backup, report_dir: /tmp/banIP-report, feed_archive: /etc/b
+ anip/banip.feeds.gz
+ + run_flags : protocol (4/6): ✔/✘, log (inp/fwd): ✔/✘, deduplicate: ✔, split: ✘, allowed only: ✘
+ + last_run : action: start, duration: 0m 15s, date: 2023-02-08 22:12:46
+ + system_info : cores: 2, memory: 3614, device: PC Engines apu1, OpenWrt SNAPSHOT r21997-b5193291bd
+```
+
+**banIP search information**
+```
+~# /etc/init.d/banip search 221.228.105.173
:::
-::: IPSet details
+::: banIP Search
:::
- Name Type Count Cnt_IP Cnt_CIDR Cnt_MAC Cnt_ACC Entry details (Entry/Count)
- --------------------------------------------------------------------------------------------------------------------
- whitelist_4 src+dst 1 0 1 0 1
- xxx.xxxx.xxx.xxxx/24 85
- --------------------------------------------------------------------------------------------------------------------
- whitelist_6 src+dst 2 0 2 0 1
- xxxx:xxxx:xxxx::/64 29
- --------------------------------------------------------------------------------------------------------------------
- blacklist_4 src+dst 513 513 0 0 2
- 192.35.168.16 3
- 80.82.65.74 1
- --------------------------------------------------------------------------------------------------------------------
- blacklist_6 src+dst 1 1 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- country_4 src 52150 0 52150 0 23
- 124.5.0.0/16 1
- 95.188.0.0/14 1
- 121.16.0.0/12 1
- 46.161.0.0/18 1
- 42.56.0.0/14 1
- 113.64.0.0/10 1
- 113.252.0.0/14 1
- 5.201.128.0/17 1
- 125.64.0.0/11 1
- 90.188.0.0/15 1
- 60.0.0.0/11 1
- 78.160.0.0/11 1
- 1.80.0.0/12 1
- 183.184.0.0/13 1
- 175.24.0.0/14 1
- 119.176.0.0/12 1
- 59.88.0.0/13 1
- 103.78.12.0/22 1
- 123.128.0.0/13 1
- 116.224.0.0/12 1
- 42.224.0.0/12 1
- 82.80.0.0/15 1
- 14.32.0.0/11 1
- --------------------------------------------------------------------------------------------------------------------
- country_6 src 20099 0 20099 0 0
- --------------------------------------------------------------------------------------------------------------------
- debl_4 src+dst 29389 29389 0 0 1
- 5.182.210.16 4
- --------------------------------------------------------------------------------------------------------------------
- debl_6 src+dst 64 64 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- doh_4 src+dst 168 168 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- doh_6 src+dst 122 122 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- drop_4 src+dst 965 0 965 0 0
- --------------------------------------------------------------------------------------------------------------------
- drop_6 src+dst 36 0 36 0 0
- --------------------------------------------------------------------------------------------------------------------
- dshield_4 src+dst 20 0 20 0 1
- 89.248.165.0/24 1
- --------------------------------------------------------------------------------------------------------------------
- feodo_4 src+dst 325 325 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- firehol1_4 src+dst 2763 403 2360 0 0
- --------------------------------------------------------------------------------------------------------------------
- iblockspy_4 src+dst 3650 2832 818 0 0
- --------------------------------------------------------------------------------------------------------------------
- nixspam_4 src+dst 9577 9577 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- sslbl_4 src+dst 104 104 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- threat_4 src+dst 1300 315 985 0 0
- --------------------------------------------------------------------------------------------------------------------
- tor_4 src+dst 1437 1437 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- tor_6 src+dst 478 478 0 0 0
- --------------------------------------------------------------------------------------------------------------------
- uceprotect1_4 src+dst 156249 156249 0 0 6
- 192.241.220.137 1
- 128.14.137.178 1
- 61.219.11.153 1
- 138.34.32.33 1
- 107.174.133.130 2
- 180.232.99.46 1
- --------------------------------------------------------------------------------------------------------------------
- voip_4 src+dst 12563 12299 264 0 0
- --------------------------------------------------------------------------------------------------------------------
- yoyo_4 src+dst 10472 10472 0 0 1
- 204.79.197.200 2
- --------------------------------------------------------------------------------------------------------------------
-</code></pre>
-
-**Enable E-Mail notification via 'msmtp':**
-To use the email notification you have to install & configure the package 'msmtp'.
+ Looking for IP 221.228.105.173 on 2023-02-08 22:12:48
+ ---
+ IP found in set oisdbasicv4
+```
+
+**allow-/blocklist handling**
+banIP supports local allow and block lists (IPv4, IPv6, CIDR notation or domain names), located in /etc/banip/banip.allowlist and /etc/banip/banip.blocklist.
+Unsuccessful login attempts or suspicious requests will be tracked and added to the local blocklist (see the 'ban\_autoblocklist' option). The blocklist behaviour can be further tweaked with the 'ban\_nftexpiry' option.
+Furthermore the uplink subnet will be added to local allowlist (see 'ban\_autowallowlist' option).
+Both lists also accept domain names as input to allow IP filtering based on these names. The corresponding IPs (IPv4 & IPv6) will be extracted in a detached background process and added to the sets.
+
+**allowlist-only mode**
+banIP supports an "allowlist only" mode. This option restricts the internet access from/to a small number of secure websites/IPs, and block access from/to the rest of the internet. All IPs and Domains which are _not_ listed in the allowlist are blocked.
+
+**redirect Asterisk security logs to lodg/logread**
+banIP only supports logfile scanning via logread, so to monitor attacks on Asterisk, its security log must be available via logread. To do this, edit '/etc/asterisk/logger.conf' and add the line 'syslog.local0 = security', then run 'asterisk -rx reload logger' to update the running Asterisk configuration.
+
+**tweaks for low memory systems**
+nftables supports the atomic loading of rules/sets/members, which is cool but unfortunately is also very memory intensive. To reduce the memory pressure on low memory systems (i.e. those with 256-512Mb RAM), you should optimize your configuration with the following options:
+
+ * point 'ban_reportdir' and 'ban_backupdir' to an external usb drive
+ * set 'ban_cores' to '1' (only useful on a multicore system) to force sequential feed processing
+ * set 'ban_splitsize' e.g. to '1000' to split the load of an external set after every 1000 lines/members
+
+**tweak the download options**
+By default banIP uses the following pre-configured download options:
+```
+ * aria2c: --timeout=20 --allow-overwrite=true --auto-file-renaming=false --log-level=warn --dir=/ -o
+ * curl: --connect-timeout 20 --silent --show-error --location -o
+ * uclient-fetch: --timeout=20 -O
+ * wget: --no-cache --no-cookies --max-redirect=0 --timeout=20 -O
+```
+To override the default set 'ban_fetchparm' manually to your needs.
+
+**send E-Mail notifications via 'msmtp'**
+To use the email notification you must install & configure the package 'msmtp'.
Modify the file '/etc/msmtprc', e.g.:
-<pre><code>
+```
[...]
defaults
auth on
account ban_notify
host smtp.gmail.com
port 587
-from <address>@gmail.com
-user <gmail-user>
-password <password>
-</code></pre>
-Finally enable E-Mail support and add a valid E-Mail receiver address in LuCI.
-
-**Edit, add new banIP sources:**
-The banIP blocklist sources are stored in an external, compressed JSON file '/etc/banip/banip.sources.gz'.
-This file is directly parsed in LuCI and accessible via CLI, just call _/etc/init.d/banip list_.
+from <address>@gmail.com
+user <gmail-user>
+password <password>
+```
+Finally add a valid E-Mail receiver address.
-To add new or edit existing sources extract the compressed JSON file _gunzip /etc/banip/banip.sources.gz_.
+**add new banIP feeds**
+The banIP blocklist feeds are stored in an external, compressed JSON file '/etc/banip/banip.feeds.gz'.
+To add a new or edit an existing feed extract the compressed JSON file _gunzip /etc/banip/banip.feeds.gz_.
A valid JSON source object contains the following required information, e.g.:
-<pre><code>
+```
[...]
"tor": {
- "url_4": "https://lists.fissionrelays.net/tor/exits-ipv4.txt",
- "url_6": "https://lists.fissionrelays.net/tor/exits-ipv6.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add tor_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add tor_6 \"$1}",
- "focus": "Tor exit nodes",
- "descurl": "https://fissionrelays.net/lists"
+ "url_4": "https://raw.githubusercontent.com/SecOps-Institute/Tor-IP-Addresses/master/tor-exit-nodes.lst",
+ "url_6": "https://raw.githubusercontent.com/SecOps-Institute/Tor-IP-Addresses/master/tor-exit-nodes.lst",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "tor exit nodes",
+ "descurl": "https://github.com/SecOps-Institute/Tor-IP-Addresses"
},
[...]
-</code></pre>
-Add an unique object name, make the required changes to 'url_4', 'rule_4' (and/or 'url_6', 'rule_6'), 'focus' and 'descurl' and finally compress the changed JSON file _gzip /etc/banip/banip.sources.gz_ to use the new source object in banIP.
-<b>Please note:</b> if you're going to add new sources on your own, please make a copy of the default file and work with that copy further on, cause the default will be overwritten with every banIP update. To reference your copy set the option 'ban\_srcarc' which points by default to '/etc/banip/banip.sources.gz'
-
+```
+Add an unique object name, make the required changes and compress the changed JSON file finally with _gzip /etc/banip/banip.feeds_ to use the new feed file in banIP.
+**Please note:** if you're going to add new feeds, **always** work with a copy of the default file; this file is always overwritten with every banIP update. To reference your own file set the option 'ban\_feedarchive' accordingly
+
## 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>
+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>
## Removal
* stop all banIP related services with _/etc/init.d/banip stop_
* optional: remove the banip package (_opkg remove banip_)
Have fun!
-Dirk
+Dirk
--- /dev/null
+# banIP shared function library/include
+# Copyright (c) 2018-2023 Dirk Brenken (dev@brenken.org)
+# This is free software, licensed under the GNU General Public License v3.
+
+# (s)hellcheck exceptions
+# shellcheck disable=all
+
+# set initial defaults
+#
+export LC_ALL=C
+export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
+
+ban_basedir="/tmp"
+ban_backupdir="${ban_basedir}/banIP-backup"
+ban_reportdir="${ban_basedir}/banIP-report"
+ban_feedarchive="/etc/banip/banip.feeds.gz"
+ban_pidfile="/var/run/banip.pid"
+ban_lock="/var/run/banip.lock"
+ban_blocklist="/etc/banip/banip.blocklist"
+ban_allowlist="/etc/banip/banip.allowlist"
+ban_fetchcmd=""
+ban_logreadcmd="$(command -v logread)"
+ban_logcmd="$(command -v logger)"
+ban_ubuscmd="$(command -v ubus)"
+ban_nftcmd="$(command -v nft)"
+ban_fw4cmd="$(command -v fw4)"
+ban_awkcmd="$(command -v awk)"
+ban_grepcmd="$(command -v grep)"
+ban_lookupcmd="$(command -v nslookup)"
+ban_mailcmd="$(command -v msmtp)"
+ban_mailsender="no-reply@banIP"
+ban_mailreceiver=""
+ban_mailtopic="banIP notification"
+ban_mailprofile="ban_notify"
+ban_mailtemplate="/etc/banip/banip.tpl"
+ban_nftpriority="-200"
+ban_nftexpiry=""
+ban_loglevel="warn"
+ban_loglimit="100"
+ban_logcount="1"
+ban_logterm=""
+ban_country=""
+ban_asn=""
+ban_loginput="0"
+ban_logforward="0"
+ban_allowlistonly="0"
+ban_autoallowlist="1"
+ban_autoblocklist="1"
+ban_deduplicate="1"
+ban_splitsize="0"
+ban_autodetect=""
+ban_feed=""
+ban_blockinput=""
+ban_blockforward=""
+ban_protov4="0"
+ban_protov6="0"
+ban_ifv4=""
+ban_ifv6=""
+ban_dev=""
+ban_sub=""
+ban_fetchinsecure=""
+ban_cores=""
+ban_memory=""
+ban_trigger=""
+ban_triggerdelay="10"
+ban_resolver=""
+ban_enabled="0"
+ban_debug="0"
+
+# gather system information
+#
+f_system() {
+ local cpu core
+
+ ban_memory="$("${ban_awkcmd}" '/^MemAvailable/{printf "%s",int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
+ ban_ver="$(${ban_ubuscmd} -S call rpc-sys packagelist 2>/dev/null | jsonfilter -ql1 -e '@.packages.banip')"
+ ban_sysver="$(${ban_ubuscmd} -S call system board 2>/dev/null | jsonfilter -ql1 -e '@.model' -e '@.release.description' |
+ "${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s",$1,$2}')"
+ if [ -z "${ban_cores}" ]; then
+ cpu="$("${ban_grepcmd}" -c '^processor' /proc/cpuinfo 2>/dev/null)"
+ core="$("${ban_grepcmd}" -cm1 '^core id' /proc/cpuinfo 2>/dev/null)"
+ [ "${cpu}" = "0" ] && cpu="1"
+ [ "${core}" = "0" ] && core="1"
+ ban_cores="$((cpu * core))"
+ fi
+
+ f_log "debug" "f_system ::: system: ${ban_sysver:-"n/a"}, version: ${ban_ver:-"n/a"}, memory: ${ban_memory:-"0"}, cpu_cores: ${ban_cores}"
+}
+
+# create directories
+#
+f_mkdir() {
+ local dir="${1}"
+
+ if [ ! -d "${dir}" ]; then
+ rm -f "${dir}"
+ mkdir -p "${dir}"
+ f_log "debug" "f_mkdir ::: created directory: ${dir}"
+ fi
+}
+
+# create files
+#
+f_mkfile() {
+ local file="${1}"
+
+ if [ ! -f "${file}" ]; then
+ : >"${file}"
+ f_log "debug" "f_mkfile ::: created file: ${file}"
+ fi
+}
+
+# create temporary files and directories
+#
+f_tmp() {
+ f_mkdir "${ban_basedir}"
+ ban_tmpdir="$(mktemp -p "${ban_basedir}" -d)"
+ ban_tmpfile="$(mktemp -p "${ban_tmpdir}" -tu)"
+
+ f_log "debug" "f_tmp ::: base_dir: ${ban_basedir:-"-"}, tmp_dir: ${ban_tmpdir:-"-"}"
+}
+
+# remove directories
+#
+f_rmdir() {
+ local dir="${1}"
+
+ if [ -d "${dir}" ]; then
+ rm -rf "${dir}"
+ f_log "debug" "f_rmdir ::: deleted directory: ${dir}"
+ fi
+}
+
+# convert chars
+#
+f_char() {
+ local char="${1}"
+
+ [ "${char}" = "1" ] && printf "%s" "✔" || printf "%s" "✘"
+}
+
+# trim strings
+#
+f_trim() {
+ local string="${1}"
+
+ string="${string#"${string%%[![:space:]]*}"}"
+ string="${string%"${string##*[![:space:]]}"}"
+ printf "%s" "${string}"
+}
+
+# write log messages
+#
+f_log() {
+ local class="${1}" log_msg="${2}"
+
+ if [ -n "${log_msg}" ] && { [ "${class}" != "debug" ] || [ "${ban_debug}" = "1" ]; }; then
+ if [ -x "${ban_logcmd}" ]; then
+ "${ban_logcmd}" -p "${class}" -t "banIP-${ban_ver}[${$}]" "${log_msg}"
+ else
+ printf "%s %s %s\n" "${class}" "banIP-${ban_ver}[${$}]" "${log_msg}"
+ fi
+ fi
+ if [ "${class}" = "err" ]; then
+ f_genstatus "error"
+ f_rmdir "${ban_tmpdir}"
+ rm -rf "${ban_lock}"
+ exit 1
+ fi
+}
+
+# load config
+#
+f_conf() {
+ unset ban_dev ban_ifv4 ban_ifv6 ban_feed ban_blockinput ban_blockforward ban_logterm ban_country ban_asn
+ config_cb() {
+ option_cb() {
+ local option="${1}"
+ local value="${2}"
+ eval "${option}=\"${value}\""
+ }
+ list_cb() {
+ local option="${1}"
+ local value="${2}"
+ case "${option}" in
+ "ban_dev")
+ eval "${option}=\"$(printf "%s" "${ban_dev}")${value} \""
+ ;;
+ "ban_ifv4")
+ eval "${option}=\"$(printf "%s" "${ban_ifv4}")${value} \""
+ ;;
+ "ban_ifv6")
+ eval "${option}=\"$(printf "%s" "${ban_ifv6}")${value} \""
+ ;;
+ "ban_feed")
+ eval "${option}=\"$(printf "%s" "${ban_feed}")${value} \""
+ ;;
+ "ban_blockinput")
+ eval "${option}=\"$(printf "%s" "${ban_blockinput}")${value} \""
+ ;;
+ "ban_blockforward")
+ eval "${option}=\"$(printf "%s" "${ban_blockforward}")${value} \""
+ ;;
+ "ban_logterm")
+ eval "${option}=\"$(printf "%s" "${ban_logterm}")${value}\\|\""
+ ;;
+ "ban_country")
+ eval "${option}=\"$(printf "%s" "${ban_country}")${value} \""
+ ;;
+ "ban_asn")
+ eval "${option}=\"$(printf "%s" "${ban_asn}")${value} \""
+ ;;
+ esac
+ }
+ }
+ config_load banip
+
+ [ "${ban_action}" = "boot" ] && [ -z "${ban_trigger}" ] && sleep ${ban_triggerdelay}
+}
+
+# prepare fetch utility
+#
+f_fetch() {
+ local ut utils packages insecure
+
+ if [ -z "${ban_fetchcmd}" ] || [ ! -x "${ban_fetchcmd}" ]; then
+ packages="$(${ban_ubuscmd} -S call rpc-sys packagelist 2>/dev/null)"
+ [ -z "${packages}" ] && f_log "err" "local opkg package repository is not available, please set the download utility 'ban_fetchcmd' manually"
+ utils="aria2c curl wget uclient-fetch"
+ for ut in ${utils}; do
+ if { [ "${ut}" = "uclient-fetch" ] && printf "%s" "${packages}" | "${ban_grepcmd}" -q '"libustream-'; } ||
+ { [ "${ut}" = "wget" ] && printf "%s" "${packages}" | "${ban_grepcmd}" -q '"wget-ssl'; } ||
+ [ "${ut}" = "curl" ] || [ "${ut}" = "aria2c" ]; then
+ ban_fetchcmd="$(command -v "${ut}")"
+ if [ -x "${ban_fetchcmd}" ]; then
+ uci_set banip global ban_fetchcmd "${ban_fetchcmd##*/}"
+ uci_commit "banip"
+ break
+ fi
+ fi
+ done
+ fi
+ [ ! -x "${ban_fetchcmd}" ] && f_log "err" "download utility with SSL support not found"
+ case "${ban_fetchcmd##*/}" in
+ "aria2c")
+ [ "${ban_fetchinsecure}" = "1" ] && insecure="--check-certificate=false"
+ ban_fetchparm="${ban_fetchparm:-"${insecure} --timeout=20 --allow-overwrite=true --auto-file-renaming=false --log-level=warn --dir=/ -o"}"
+ ;;
+ "curl")
+ [ "${ban_fetchinsecure}" = "1" ] && insecure="--insecure"
+ ban_fetchparm="${ban_fetchparm:-"${insecure} --connect-timeout 20 --fail --silent --show-error --location -o"}"
+ ;;
+ "uclient-fetch")
+ [ "${ban_fetchinsecure}" = "1" ] && insecure="--no-check-certificate"
+ ban_fetchparm="${ban_fetchparm:-"${insecure} --timeout=20 -O"}"
+ ;;
+ "wget")
+ [ "${ban_fetchinsecure}" = "1" ] && insecure="--no-check-certificate"
+ ban_fetchparm="${ban_fetchparm:-"${insecure} --no-cache --no-cookies --max-redirect=0 --timeout=20 -O"}"
+ ;;
+ esac
+
+ f_log "debug" "f_fetch ::: fetch_cmd: ${ban_fetchcmd:-"-"}, fetch_parm: ${ban_fetchparm:-"-"}"
+}
+
+# remove logservice
+#
+f_rmpid() {
+ local ppid pid pids
+
+ ppid="$(cat "${ban_pidfile}" 2>/dev/null)"
+ [ -n "${ppid}" ] && pids="$(pgrep -P "${ppid}" 2>/dev/null)" || return 0
+ for pid in ${pids}; do
+ kill -INT "${pid}" >/dev/null 2>&1
+ done
+ : >"${ban_pidfile}"
+}
+
+# get wan interfaces
+#
+f_getif() {
+ local iface
+
+ "${ban_ubuscmd}" -t 5 wait_for network.device network.interface 2>/dev/null
+ if [ "${ban_autodetect}" = "1" ]; then
+ if [ -z "${ban_ifv4}" ]; then
+ network_find_wan iface
+ if [ -n "${iface}" ] && ! printf "%s" "${ban_ifv4}" | "${ban_grepcmd}" -q "${iface}"; then
+ ban_protov4="1"
+ ban_ifv4="${ban_ifv4}${iface} "
+ uci_set banip global ban_protov4 "1"
+ uci_add_list banip global ban_ifv4 "${iface}"
+ fi
+ fi
+ if [ -z "${ban_ifv6}" ]; then
+ network_find_wan6 iface
+ if [ -n "${iface}" ] && ! printf "%s" "${ban_ifv6}" | "${ban_grepcmd}" -q "${iface}"; then
+ ban_protov6="1"
+ ban_ifv6="${ban_ifv6}${iface} "
+ uci_set banip global ban_protov6 "1"
+ uci_add_list banip global ban_ifv6 "${iface}"
+ fi
+ fi
+ ban_ifv4="${ban_ifv4%%?}"
+ ban_ifv6="${ban_ifv6%%?}"
+ [ -n "$(uci -q changes "banip")" ] && uci_commit "banip"
+ fi
+ [ -z "${ban_ifv4}" ] && [ -z "${ban_ifv6}" ] && f_log "err" "wan interfaces not found, please check your configuration"
+
+ f_log "debug" "f_getif ::: auto_detect: ${ban_autodetect}, interfaces (4/6): ${ban_ifv4}/${ban_ifv6}, protocols (4/6): ${ban_protov4}/${ban_protov6}"
+}
+
+# get wan devices
+#
+f_getdev() {
+ local dev iface
+
+ if [ "${ban_autodetect}" = "1" ] && [ -z "${ban_dev}" ]; then
+ for iface in ${ban_ifv4} ${ban_ifv6}; do
+ network_get_device dev "${iface}"
+ if [ -n "${dev}" ] && ! printf "%s" "${ban_dev}" | "${ban_grepcmd}" -q "${dev}"; then
+ ban_dev="${ban_dev}${dev} "
+ uci_add_list banip global ban_dev "${dev}"
+ else
+ network_get_physdev dev "${iface}"
+ if [ -n "${dev}" ] && ! printf "%s" "${ban_dev}" | "${ban_grepcmd}" -q "${dev}"; then
+ ban_dev="${ban_dev}${dev} "
+ uci_add_list banip global ban_dev "${dev}"
+ fi
+ fi
+ done
+ ban_dev="${ban_dev%%?}"
+ [ -n "$(uci -q changes "banip")" ] && uci_commit "banip"
+ fi
+ [ -z "${ban_dev}" ] && f_log "err" "wan devices not found, please check your configuration"
+
+ f_log "debug" "f_getdev ::: auto_detect: ${ban_autodetect}, devices: ${ban_dev}"
+}
+
+# get local subnets
+#
+f_getsub() {
+ local sub iface ip
+
+ for iface in ${ban_ifv4} ${ban_ifv6}; do
+ network_get_subnet sub "${iface}"
+ if [ -n "${sub}" ] && ! printf "%s" "${ban_sub}" | "${ban_grepcmd}" -q "${sub}"; then
+ ban_sub="${ban_sub} ${sub}"
+ fi
+ network_get_subnet6 sub "${iface}"
+ if [ -n "${sub}" ] && ! printf "%s" "${ban_sub}" | "${ban_grepcmd}" -q "${sub}"; then
+ ban_sub="${ban_sub} ${sub}"
+ fi
+ done
+ if [ "${ban_autoallowlist}" = "1" ]; then
+ for ip in ${ban_sub}; do
+ if ! "${ban_grepcmd}" -q "${ip}" "${ban_allowlist}"; then
+ printf "%-42s%s\n" "${ip}" "added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_allowlist}"
+ f_log "info" "add subnet '${ip}' to local allowlist"
+ fi
+ done
+ fi
+ [ -z "${ban_sub}" ] && f_log "err" "wan subnet(s) not found, please check your configuration"
+
+ f_log "debug" "f_getsub ::: auto_allowlist: ${ban_autoallowlist}, subnet(s): ${ban_sub:-"-"}"
+}
+
+# get set elements
+#
+f_getelements() {
+ local file="${1}"
+
+ [ -s "${file}" ] && printf "%s" "elements={ $(cat "${file}") };"
+}
+
+# build initial nft file with base table, chains and rules
+#
+f_nftinit() {
+ local feed_log feed_rc file="${1}"
+
+ {
+ # nft header (tables and chains)
+ #
+ printf "%s\n\n" "#!/usr/sbin/nft -f"
+ if "${ban_nftcmd}" -t list table inet banIP >/dev/null 2>&1; then
+ printf "%s\n" "delete table inet banIP"
+ fi
+ printf "%s\n" "add table inet banIP"
+ printf "%s\n" "add chain inet banIP wan-input { type filter hook input priority ${ban_nftpriority}; policy accept; }"
+ printf "%s\n" "add chain inet banIP lan-forward { type filter hook forward priority ${ban_nftpriority}; policy accept; }"
+
+ # default input rules
+ #
+ printf "%s\n" "add rule inet banIP wan-input ct state established,related counter accept"
+ printf "%s\n" "add rule inet banIP wan-input iifname != { ${ban_dev// /, } } counter accept"
+ printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv4 icmp type { echo-request } limit rate 1000/second counter accept"
+ printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { echo-request } limit rate 1000/second counter accept"
+ printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert} limit rate 1000/second ip6 hoplimit 1 counter accept"
+ printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert} limit rate 1000/second ip6 hoplimit 255 counter accept"
+
+ # default forward rules
+ #
+ printf "%s\n" "add rule inet banIP lan-forward ct state established,related counter accept"
+ printf "%s\n" "add rule inet banIP lan-forward oifname != { ${ban_dev// /, } } counter accept"
+ } >"${file}"
+
+ # load initial banIP table within nft (atomic load)
+ #
+ feed_log="$("${ban_nftcmd}" -f "${file}" 2>&1)"
+ feed_rc="${?}"
+
+ f_log "debug" "f_nftinit ::: devices: ${ban_dev}, priority: ${ban_nftpriority}, rc: ${feed_rc:-"-"}, log: ${feed_log:-"-"}"
+ return ${feed_rc}
+}
+
+f_down() {
+ local nft_loginput nft_logforward start_ts end_ts tmp_raw tmp_load tmp_file split_file input_handles forward_handles handle
+ local cnt_set cnt_dl restore_rc feed_direction feed_rc feed_log feed="${1}" proto="${2}" feed_url="${3}" feed_rule="${4}" feed_flag="${5}"
+
+ start_ts="$(date +%s)"
+ feed="${feed}v${proto}"
+ tmp_load="${ban_tmpfile}.${feed}.load"
+ tmp_raw="${ban_tmpfile}.${feed}.raw"
+ tmp_split="${ban_tmpfile}.${feed}.split"
+ tmp_file="${ban_tmpfile}.${feed}.file"
+ tmp_flush="${ban_tmpfile}.${feed}.flush"
+ tmp_nft="${ban_tmpfile}.${feed}.nft"
+
+ [ "${ban_loginput}" = "1" ] && nft_loginput="limit rate 2/second log level ${ban_loglevel} prefix \"banIP_drp/${feed}: \""
+ [ "${ban_logforward}" = "1" ] && nft_logforward="limit rate 2/second log level ${ban_loglevel} prefix \"banIP_rej/${feed}: \""
+
+ # set source block direction
+ #
+ if printf "%s" "${ban_blockinput}" | "${ban_grepcmd}" -q "${feed%v*}"; then
+ feed_direction="input"
+ elif printf "%s" "${ban_blockforward}" | "${ban_grepcmd}" -q "${feed%v*}"; then
+ feed_direction="forward"
+ fi
+
+ # chain/rule maintenance
+ #
+ if [ "${ban_action}" = "reload" ] && "${ban_nftcmd}" -t list set inet banIP "${feed}" >/dev/null 2>&1; then
+ input_handles="$("${ban_nftcmd}" -t --handle --numeric list chain inet banIP wan-input 2>/dev/null)"
+ forward_handles="$("${ban_nftcmd}" -t --handle --numeric list chain inet banIP lan-forward 2>/dev/null)"
+ {
+ printf "%s\n" "flush set inet banIP ${feed}"
+ handle="$(printf "%s\n" "${input_handles}" | "${ban_awkcmd}" "/@${feed} /{print \$NF}")"
+ [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP wan-input handle ${handle}"
+ handle="$(printf "%s\n" "${forward_handles}" | "${ban_awkcmd}" "/@${feed} /{print \$NF}")"
+ [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP lan-forward handle ${handle}"
+ } >"${tmp_flush}"
+ fi
+
+ # restore local backups during init
+ #
+ if { [ "${ban_action}" != "reload" ] || [ "${feed_url}" = "local" ]; } && [ "${feed%v*}" != "allowlist" ] && [ "${feed%v*}" != "blocklist" ]; then
+ f_restore "${feed}" "${feed_url}" "${tmp_load}"
+ restore_rc="${?}"
+ feed_rc="${restore_rc}"
+ fi
+
+ # handle local lists
+ #
+ if [ "${feed%v*}" = "allowlist" ]; then
+ {
+ printf "%s\n\n" "#!/usr/sbin/nft -f"
+ [ -s "${tmp_flush}" ] && cat "${tmp_flush}"
+ if [ "${proto}" = "MAC" ]; then
+ "${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}([[:space:]]|$)/{printf "%s, ",tolower($1)}' "${ban_allowlist}" >"${tmp_file}"
+ printf "%s\n" "add set inet banIP ${feed} { type ether_addr; policy memory; $(f_getelements "${tmp_file}") }"
+ if [ "${feed_direction}" != "input" ]; then
+ printf "%s\n" "add rule inet banIP lan-forward ether saddr @${feed} counter accept"
+ fi
+ elif [ "${proto}" = "4" ]; then
+ "${ban_awkcmd}" '/^(([0-9]{1,3}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{printf "%s, ",$1}' "${ban_allowlist}" >"${tmp_file}"
+ printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy memory; $(f_getelements "${tmp_file}") }"
+ if [ "${feed_direction}" != "forward" ]; then
+ if [ "${ban_allowlistonly}" = "1" ]; then
+ printf "%s\n" "add rule inet banIP wan-input ip saddr != @${feed} ${nft_loginput} counter drop"
+ else
+ printf "%s\n" "add rule inet banIP wan-input ip saddr @${feed} counter accept"
+ fi
+ fi
+ if [ "${feed_direction}" != "input" ]; then
+ if [ "${ban_allowlistonly}" = "1" ]; then
+ printf "%s\n" "add rule inet banIP lan-forward ip daddr != @${feed} ${nft_logforward} counter reject with icmp type admin-prohibited"
+ else
+ printf "%s\n" "add rule inet banIP lan-forward ip daddr @${feed} counter accept"
+ fi
+ fi
+ elif [ "${proto}" = "6" ]; then
+ "${ban_awkcmd}" '!/^([0-9A-f]{2}:){5}[0-9A-f]{2}([[:space:]]|$)/{printf "%s\n",$1}' "${ban_allowlist}" |
+ "${ban_awkcmd}" '/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{printf "%s, ",tolower($1)}' >"${tmp_file}"
+ printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy memory; $(f_getelements "${tmp_file}") }"
+ if [ "${feed_direction}" != "forward" ]; then
+ if [ "${ban_allowlistonly}" = "1" ]; then
+ printf "%s\n" "add rule inet banIP wan-input ip6 saddr != @${feed} ${nft_loginput} counter drop"
+ else
+ printf "%s\n" "add rule inet banIP wan-input ip6 saddr @${feed} counter accept"
+ fi
+ fi
+ if [ "${feed_direction}" != "input" ]; then
+ if [ "${ban_allowlistonly}" = "1" ]; then
+ printf "%s\n" "add rule inet banIP lan-forward ip6 daddr != @${feed} ${nft_logforward} counter reject with icmpv6 type admin-prohibited"
+ else
+ printf "%s\n" "add rule inet banIP lan-forward ip6 daddr @${feed} counter accept"
+ fi
+ fi
+ fi
+ } >"${tmp_nft}"
+ feed_rc="${?}"
+ elif [ "${feed%v*}" = "blocklist" ]; then
+ {
+ printf "%s\n\n" "#!/usr/sbin/nft -f"
+ [ -s "${tmp_flush}" ] && cat "${tmp_flush}"
+ if [ "${proto}" = "MAC" ]; then
+ "${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}([[:space:]]|$)/{printf "%s, ",tolower($1)}' "${ban_blocklist}" >"${tmp_file}"
+ printf "%s\n" "add set inet banIP ${feed} { type ether_addr; policy memory; $(f_getelements "${tmp_file}") }"
+ if [ "${feed_direction}" != "input" ]; then
+ printf "%s\n" "add rule inet banIP lan-forward ether saddr @${feed} ${nft_logforward} counter reject"
+ fi
+ elif [ "${proto}" = "4" ]; then
+ if [ "${ban_deduplicate}" = "1" ]; then
+ "${ban_awkcmd}" '/^(([0-9]{1,3}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{printf "%s,\n",$1}' "${ban_blocklist}" >"${tmp_raw}"
+ "${ban_awkcmd}" 'NR==FNR{member[$0];next}!($0 in member)' "${ban_tmpfile}.deduplicate" "${tmp_raw}" 2>/dev/null >"${tmp_split}"
+ "${ban_awkcmd}" 'BEGIN{FS="[ ,]"}NR==FNR{member[$1];next}!($1 in member)' "${ban_tmpfile}.deduplicate" "${ban_blocklist}" 2>/dev/null >"${tmp_raw}"
+ cat "${tmp_raw}" 2>/dev/null >"${ban_blocklist}"
+ else
+ "${ban_awkcmd}" '/^(([0-9]{1,3}\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{printf "%s,\n",$1}' "${ban_blocklist}" >"${tmp_split}"
+ fi
+ "${ban_awkcmd}" '{ORS=" ";print}' "${tmp_split}" 2>/dev/null >"${tmp_file}"
+ printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval, timeout; auto-merge; policy memory; $(f_getelements "${tmp_file}") }"
+ if [ "${feed_direction}" != "forward" ]; then
+ printf "%s\n" "add rule inet banIP wan-input ip saddr @${feed} ${nft_loginput} counter drop"
+ fi
+ if [ "${feed_direction}" != "input" ]; then
+ printf "%s\n" "add rule inet banIP lan-forward ip daddr @${feed} ${nft_logforward} counter reject with icmp type admin-prohibited"
+ fi
+ elif [ "${proto}" = "6" ]; then
+ if [ "${ban_deduplicate}" = "1" ]; then
+ "${ban_awkcmd}" '!/^([0-9A-f]{2}:){5}[0-9A-f]{2}([[:space:]]|$)/{printf "%s\n",$1}' "${ban_blocklist}" |
+ "${ban_awkcmd}" '/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{printf "%s,\n",tolower($1)}' >"${tmp_raw}"
+ "${ban_awkcmd}" 'NR==FNR{member[$0];next}!($0 in member)' "${ban_tmpfile}.deduplicate" "${tmp_raw}" 2>/dev/null >"${tmp_split}"
+ "${ban_awkcmd}" 'BEGIN{FS="[ ,]"}NR==FNR{member[$1];next}!($1 in member)' "${ban_tmpfile}.deduplicate" "${ban_blocklist}" 2>/dev/null >"${tmp_raw}"
+ cat "${tmp_raw}" 2>/dev/null >"${ban_blocklist}"
+ else
+ "${ban_awkcmd}" '!/^([0-9A-f]{2}:){5}[0-9A-f]{2}([[:space:]]|$)/{printf "%s\n",$1}' "${ban_blocklist}" |
+ "${ban_awkcmd}" '/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{printf "%s,\n",tolower($1)}' >"${tmp_split}"
+ fi
+ "${ban_awkcmd}" '{ORS=" ";print}' "${tmp_split}" 2>/dev/null >"${tmp_file}"
+ printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval, timeout; auto-merge; policy memory; $(f_getelements "${tmp_file}") }"
+ if [ "${feed_direction}" != "forward" ]; then
+ printf "%s\n" "add rule inet banIP wan-input ip6 saddr @${feed} ${nft_loginput} counter drop"
+ fi
+ if [ "${feed_direction}" != "input" ]; then
+ printf "%s\n" "add rule inet banIP lan-forward ip6 daddr @${feed} ${nft_logforward} counter reject with icmpv6 type admin-prohibited"
+ fi
+ fi
+ } >"${tmp_nft}"
+ feed_rc="${?}"
+ # handle external downloads
+ #
+ elif [ "${restore_rc}" != "0" ] && [ "${feed_url}" != "local" ]; then
+ # handle country downloads
+ #
+ if [ "${feed%v*}" = "country" ]; then
+ for country in ${ban_country}; do
+ feed_log="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_raw}" "${feed_url}${country}-aggregated.zone" 2>&1)"
+ feed_rc="${?}"
+ [ "${feed_rc}" = "0" ] && cat "${tmp_raw}" 2>/dev/null >>"${tmp_load}"
+ done
+ rm -f "${tmp_raw}"
+
+ # handle asn downloads
+ #
+ elif [ "${feed%v*}" = "asn" ]; then
+ for asn in ${ban_asn}; do
+ feed_log="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_raw}" "${feed_url}AS${asn}" 2>&1)"
+ feed_rc="${?}"
+ [ "${feed_rc}" = "0" ] && cat "${tmp_raw}" 2>/dev/null >>"${tmp_load}"
+ done
+ rm -f "${tmp_raw}"
+
+ # handle compressed downloads
+ #
+ elif [ -n "${feed_flag}" ]; then
+ case "${feed_flag}" in
+ "gz")
+ feed_log="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_raw}" "${feed_url}" 2>&1)"
+ feed_rc="${?}"
+ if [ "${feed_rc}" = "0" ]; then
+ zcat "${tmp_raw}" 2>/dev/null >"${tmp_load}"
+ feed_rc="${?}"
+ fi
+ rm -f "${tmp_raw}"
+ ;;
+ esac
+
+ # handle normal downloads
+ #
+ else
+ feed_log="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_load}" "${feed_url}" 2>&1)"
+ feed_rc="${?}"
+ fi
+ fi
+
+ # backup/restore
+ #
+ if [ "${restore_rc}" != "0" ] && [ "${feed_rc}" = "0" ] && [ "${feed_url}" != "local" ] && [ ! -s "${tmp_nft}" ]; then
+ f_backup "${feed}" "${tmp_load}"
+ feed_rc="${?}"
+ elif [ -z "${restore_rc}" ] && [ "${feed_rc}" != "0" ] && [ "${feed_url}" != "local" ] && [ ! -s "${tmp_nft}" ]; then
+ f_restore "${feed}" "${feed_url}" "${tmp_load}" "${feed_rc}"
+ feed_rc="${?}"
+ fi
+
+ # build nft file with set and rules for regular downloads
+ #
+ if [ "${feed_rc}" = "0" ] && [ ! -s "${tmp_nft}" ]; then
+ # deduplicate sets
+ #
+ if [ "${ban_deduplicate}" = "1" ] && [ "${feed_url}" != "local" ]; then
+ "${ban_awkcmd}" "${feed_rule}" "${tmp_load}" 2>/dev/null >"${tmp_raw}"
+ "${ban_awkcmd}" 'NR==FNR{member[$0];next}!($0 in member)' "${ban_tmpfile}.deduplicate" "${tmp_raw}" 2>/dev/null | tee -a "${ban_tmpfile}.deduplicate" >"${tmp_split}"
+ else
+ "${ban_awkcmd}" "${feed_rule}" "${tmp_load}" 2>/dev/null >"${tmp_split}"
+ fi
+ feed_rc="${?}"
+ # split sets
+ #
+ if [ "${feed_rc}" = "0" ]; then
+ if [ -n "${ban_splitsize//[![:digit]]/}" ] && [ "${ban_splitsize//[![:digit]]/}" -gt "0" ]; then
+ if ! "${ban_awkcmd}" "NR%${ban_splitsize//[![:digit]]/}==1{file=\"${tmp_file}.\"++i;}{ORS=\" \";print > file}" "${tmp_split}" 2>/dev/null; then
+ rm -f "${tmp_file}".*
+ f_log "info" "failed to split ${feed} set to size '${ban_splitsize//[![:digit]]/}'"
+ fi
+ else
+ "${ban_awkcmd}" '{ORS=" ";print}' "${tmp_split}" 2>/dev/null >"${tmp_file}.1"
+ fi
+ feed_rc="${?}"
+ fi
+ rm -f "${tmp_raw}" "${tmp_load}"
+ if [ "${feed_rc}" = "0" ] && [ "${proto}" = "4" ]; then
+ {
+ # nft header (IPv4 set)
+ #
+ printf "%s\n\n" "#!/usr/sbin/nft -f"
+ [ -s "${tmp_flush}" ] && cat "${tmp_flush}"
+ printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy memory; $(f_getelements "${tmp_file}.1") }"
+
+ # input and forward rules
+ #
+ if [ "${feed_direction}" != "forward" ]; then
+ printf "%s\n" "add rule inet banIP wan-input ip saddr @${feed} ${nft_loginput} counter drop"
+ fi
+ if [ "${feed_direction}" != "input" ]; then
+ printf "%s\n" "add rule inet banIP lan-forward ip daddr @${feed} ${nft_logforward} counter reject with icmp type admin-prohibited"
+ fi
+ } >"${tmp_nft}"
+ elif [ "${feed_rc}" = "0" ] && [ "${proto}" = "6" ]; then
+ {
+ # nft header (IPv6 set)
+ #
+ printf "%s\n\n" "#!/usr/sbin/nft -f"
+ [ -s "${tmp_flush}" ] && cat "${tmp_flush}"
+ printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy memory; $(f_getelements "${tmp_file}.1") }"
+
+ # input and forward rules
+ #
+ if [ "${feed_direction}" != "forward" ]; then
+ printf "%s\n" "add rule inet banIP wan-input ip6 saddr @${feed} ${nft_loginput} counter drop"
+ fi
+ if [ "${feed_direction}" != "input" ]; then
+ printf "%s\n" "add rule inet banIP lan-forward ip6 daddr @${feed} ${nft_logforward} counter reject with icmpv6 type admin-prohibited"
+ fi
+ } >"${tmp_nft}"
+ fi
+ fi
+
+ # load generated nft file in banIP table
+ #
+ if [ "${feed_rc}" = "0" ]; then
+ cnt_dl="$("${ban_awkcmd}" 'END{printf "%d",NR}' "${tmp_split}" 2>/dev/null)"
+ if [ "${cnt_dl:-"0"}" -gt "0" ] || [ "${feed_url}" = "local" ] || [ "${feed%v*}" = "allowlist" ] || [ "${feed%v*}" = "blocklist" ]; then
+ feed_log="$("${ban_nftcmd}" -f "${tmp_nft}" 2>&1)"
+ feed_rc="${?}"
+ # load additional split files
+ #
+ if [ "${feed_rc}" = "0" ]; then
+ for split_file in "${tmp_file}".*; do
+ [ ! -f "${split_file}" ] && break
+ if [ "${split_file##*.}" = "1" ]; then
+ rm -f "${split_file}"
+ continue
+ fi
+ if ! "${ban_nftcmd}" add element inet banIP "${feed}" "{ $(cat "${split_file}") }" >/dev/null 2>&1; then
+ f_log "info" "failed to add split file '${split_file##*.}' to ${feed} set"
+ fi
+ rm -f "${split_file}"
+ done
+ cnt_set="$("${ban_nftcmd}" -j list set inet banIP "${feed}" 2>/dev/null | jsonfilter -qe '@.nftables[*].set.elem[*]' | wc -l 2>/dev/null)"
+ fi
+ else
+ f_log "info" "empty feed ${feed} will be skipped"
+ fi
+ fi
+ rm -f "${tmp_split}" "${tmp_nft}"
+ end_ts="$(date +%s)"
+
+ f_log "debug" "f_down ::: name: ${feed}, cnt_dl: ${cnt_dl:-"-"}, cnt_set: ${cnt_set:-"-"}, split_size: ${ban_splitsize:-"-"}, time: $((end_ts - start_ts)), rc: ${feed_rc:-"-"}, log: ${feed_log:-"-"}"
+}
+
+# backup feeds
+#
+f_backup() {
+ local backup_rc feed="${1}" feed_file="${2}"
+
+ gzip -cf "${feed_file}" >"${ban_backupdir}/banIP.${feed}.gz"
+ backup_rc="${?}"
+
+ f_log "debug" "f_backup ::: name: ${feed}, source: ${feed_file##*/}, target: banIP.${feed}.gz, rc: ${backup_rc}"
+ return ${backup_rc}
+}
+
+# restore feeds
+#
+f_restore() {
+ local tmp_feed restore_rc="1" feed="${1}" feed_url="${2}" feed_file="${3}" feed_rc="${4:-"0"}"
+
+ [ "${feed_rc}" != "0" ] && restore_rc="${feed_rc}"
+ [ "${feed_url}" = "local" ] && tmp_feed="${feed%v*}v4" || tmp_feed="${feed}"
+ if [ -f "${ban_backupdir}/banIP.${tmp_feed}.gz" ]; then
+ zcat "${ban_backupdir}/banIP.${tmp_feed}.gz" 2>/dev/null >"${feed_file}"
+ restore_rc="${?}"
+ fi
+
+ f_log "debug" "f_restore ::: name: ${feed}, source: banIP.${tmp_feed}.gz, target: ${feed_file##*/}, in_rc: ${feed_rc}, rc: ${restore_rc}"
+ return ${restore_rc}
+}
+
+# remove disabled feeds
+#
+f_rmset() {
+ local tmp_del table_sets input_handles forward_handles handle sets feed feed_log feed_rc
+
+ tmp_del="${ban_tmpfile}.final.delete"
+ table_sets="$("${ban_nftcmd}" -t list table inet banIP 2>/dev/null | "${ban_awkcmd}" '/^[[:space:]]+set [[:alnum:]]+ /{printf "%s ",$2}' 2>/dev/null)"
+ input_handles="$("${ban_nftcmd}" -t --handle --numeric list chain inet banIP wan-input 2>/dev/null)"
+ forward_handles="$("${ban_nftcmd}" -t --handle --numeric list chain inet banIP lan-forward 2>/dev/null)"
+ {
+ printf "%s\n\n" "#!/usr/sbin/nft -f"
+ for feed in ${table_sets}; do
+ if ! printf "%s" "allowlist blocklist ${ban_feed}" | "${ban_grepcmd}" -q "${feed%v*}"; then
+ sets="${sets}${feed}/"
+ rm -f "${ban_backupdir}/banIP.${feed}.gz"
+ printf "%s\n" "flush set inet banIP ${feed}"
+ handle="$(printf "%s\n" "${input_handles}" | "${ban_awkcmd}" "/@${feed} /{print \$NF}" 2>/dev/null)"
+ [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP wan-input handle ${handle}"
+ handle="$(printf "%s\n" "${forward_handles}" | "${ban_awkcmd}" "/@${feed} /{print \$NF}" 2>/dev/null)"
+ [ -n "${handle}" ] && printf "%s\n" "delete rule inet banIP lan-forward handle ${handle}"
+ printf "%s\n\n" "delete set inet banIP ${feed}"
+ fi
+ done
+ } >"${tmp_del}"
+
+ if [ -n "${sets}" ]; then
+ feed_log="$("${ban_nftcmd}" -f "${tmp_del}" 2>&1)"
+ feed_rc="${?}"
+ fi
+ rm -f "${tmp_del}"
+
+ f_log "debug" "f_rmset ::: sets: ${sets:-"-"}, tmp: ${tmp_del}, rc: ${feed_rc:-"-"}, log: ${feed_log:-"-"}"
+}
+
+# generate status information
+#
+f_genstatus() {
+ local object duration nft_table nft_feeds cnt_elements="0" split="0" status="${1}"
+
+ [ -z "${ban_dev}" ] && f_conf
+ if [ "${status}" = "active" ]; then
+ if [ -n "${ban_starttime}" ]; then
+ ban_endtime="$(date "+%s")"
+ duration="$(((ban_endtime - ban_starttime) / 60))m $(((ban_endtime - ban_starttime) % 60))s"
+ fi
+ nft_table="$("${ban_nftcmd}" -t list table inet banIP 2>/dev/null)"
+ nft_feeds="$(f_trim "$(printf "%s\n" "${nft_table}" | "${ban_awkcmd}" '/^[[:space:]]+set [[:alnum:]]+ /{printf "%s ",$2}')")"
+ for object in ${nft_feeds}; do
+ cnt_elements="$((cnt_elements + $("${ban_nftcmd}" -j list set inet banIP "${object}" 2>/dev/null | jsonfilter -qe '@.nftables[*].set.elem[*]' | wc -l 2>/dev/null)))"
+ done
+ runtime="action: ${ban_action:-"-"}, duration: ${duration:-"-"}, date: $(date "+%Y-%m-%d %H:%M:%S")"
+ fi
+ f_system
+ [ ${ban_splitsize:-"0"} -gt "0" ] && split="1"
+
+ : >"${ban_basedir}/ban_runtime.json"
+ json_init
+ json_load_file "${ban_basedir}/ban_runtime.json" >/dev/null 2>&1
+ json_add_string "status" "${status}"
+ json_add_string "version" "${ban_ver}"
+ json_add_string "element_count" "${cnt_elements}"
+ json_add_array "active_feeds"
+ if [ "${status}" != "active" ]; then
+ json_add_object
+ json_add_string "feed" "-"
+ json_close_object
+ else
+ for object in ${nft_feeds}; do
+ json_add_object
+ json_add_string "feed" "${object}"
+ json_close_object
+ done
+ fi
+ json_close_array
+ json_add_array "active_devices"
+ if [ "${status}" != "active" ]; then
+ json_add_object
+ json_add_string "device" "-"
+ json_close_object
+ else
+ for object in ${ban_dev}; do
+ json_add_object
+ json_add_string "device" "${object}"
+ json_close_object
+ done
+ fi
+ json_close_array
+ json_add_array "active_interfaces"
+ if [ "${status}" != "active" ]; then
+ json_add_object
+ json_add_string "interface" "-"
+ json_close_object
+ else
+ for object in ${ban_ifv4} ${ban_ifv6}; do
+ json_add_object
+ json_add_string "interface" "${object}"
+ json_close_object
+ done
+ fi
+ json_close_array
+ json_add_array "active_subnets"
+ if [ "${status}" != "active" ]; then
+ json_add_object
+ json_add_string "subnet" "-"
+ json_close_object
+ else
+ for object in ${ban_sub}; do
+ json_add_object
+ json_add_string "subnet" "${object}"
+ json_close_object
+ done
+ fi
+ json_close_array
+ json_add_string "run_info" "base_dir: ${ban_basedir}, backup_dir: ${ban_backupdir}, report_dir: ${ban_reportdir}, feed_archive: ${ban_feedarchive}"
+ json_add_string "run_flags" "protocol (4/6): $(f_char ${ban_protov4})/$(f_char ${ban_protov6}), log (inp/fwd): $(f_char ${ban_loginput})/$(f_char ${ban_logforward}), deduplicate: $(f_char ${ban_deduplicate}), split: $(f_char ${split}), allowed only: $(f_char ${ban_allowlistonly})"
+ json_add_string "last_run" "${runtime:-"-"}"
+ json_add_string "system_info" "cores: ${ban_cores}, memory: ${ban_memory}, device: ${ban_sysver}"
+ json_dump >"${ban_basedir}/ban_runtime.json"
+}
+
+# get status information
+#
+f_getstatus() {
+ local key keylist type value index_value
+
+ [ -z "${ban_dev}" ] && f_conf
+ json_load_file "${ban_basedir}/ban_runtime.json" >/dev/null 2>&1
+ if json_get_keys keylist; then
+ printf "%s\n" "::: banIP runtime information"
+ for key in ${keylist}; do
+ json_get_var value "${key}" >/dev/null 2>&1
+ if [ "${key%_*}" = "active" ]; then
+ json_select "${key}" >/dev/null 2>&1
+ index=1
+ while json_get_type type "${index}" && [ "${type}" = "object" ]; do
+ json_get_values index_value "${index}" >/dev/null 2>&1
+ if [ "${index}" = "1" ]; then
+ value="${index_value}"
+ else
+ value="${value}, ${index_value}"
+ fi
+ index=$((index + 1))
+ done
+ json_select ".."
+ fi
+ value="$(
+ printf "%s" "${value}" |
+ awk '{NR=1;max=98;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max)}else{printf"%-24s%s\n","",substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}'
+ )"
+ printf " + %-17s : %s\n" "${key}" "${value:-"-"}"
+ done
+ else
+ printf "%s\n" "::: no banIP runtime information available"
+ fi
+}
+
+# domain lookup
+#
+f_lookup() {
+ local cnt list domain lookup ip start_time end_time duration cnt_domain="0" cnt_ip="0" feed="${1}"
+
+ start_time="$(date "+%s")"
+ if [ "${feed}" = "allowlist" ]; then
+ list="$("${ban_awkcmd}" '/^([[:alnum:]_-]{1,63}\.)+[[:alpha:]]+([[:space:]]|$)/{printf "%s ",tolower($1)}' "${ban_allowlist}" 2>/dev/null)"
+ elif [ "${feed}" = "blocklist" ]; then
+ list="$("${ban_awkcmd}" '/^([[:alnum:]_-]{1,63}\.)+[[:alpha:]]+([[:space:]]|$)/{printf "%s ",tolower($1)}' "${ban_blocklist}" 2>/dev/null)"
+ fi
+
+ for domain in ${list}; do
+ lookup="$("${ban_lookupcmd}" "${domain}" ${ban_resolver} 2>/dev/null | "${ban_awkcmd}" '/^Address[ 0-9]*: /{if(!seen[$NF]++)printf "%s ",$NF}' 2>/dev/null)"
+ for ip in ${lookup}; do
+ if [ "${ip%%.*}" = "0" ] || [ -z "${ip%%::*}" ]; then
+ continue
+ else
+ if { [ "${feed}" = "allowlist" ] && ! "${ban_grepcmd}" -q "^${ip}" "${ban_allowlist}"; } ||
+ { [ "${feed}" = "blocklist" ] && ! "${ban_grepcmd}" -q "^${ip}" "${ban_blocklist}"; }; then
+ cnt_ip="$((cnt_ip + 1))"
+ if [ "${ip##*:}" = "${ip}" ]; then
+ if ! "${ban_nftcmd}" add element inet banIP "${feed}v4" "{ ${ip} }" >/dev/null 2>&1; then
+ f_log "info" "failed to add IP '${ip}' (${domain}) to ${feed}v4 set"
+ continue
+ fi
+ else
+ if ! "${ban_nftcmd}" add element inet banIP "${feed}v6" "{ ${ip} }" >/dev/null 2>&1; then
+ f_log "info" "failed to add IP '${ip}' (${domain}) to ${feed}v6 set"
+ continue
+ fi
+ fi
+ if [ "${feed}" = "allowlist" ] && [ "${ban_autoallowlist}" = "1" ]; then
+ printf "%-42s%s\n" "${ip}" "# ip of '${domain}' added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_allowlist}"
+ elif [ "${feed}" = "blocklist" ] && [ "${ban_autoblocklist}" = "1" ]; then
+ printf "%-42s%s\n" "${ip}" "# ip of '${domain}' added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_blocklist}"
+ fi
+ fi
+ fi
+ done
+ cnt_domain="$((cnt_domain + 1))"
+ done
+ end_time="$(date "+%s")"
+ duration="$(((end_time - start_time) / 60))m $(((end_time - start_time) % 60))s"
+
+ f_log "debug" "f_lookup ::: name: ${feed}, cnt_domain: ${cnt_domain}, cnt_ip: ${cnt_ip}, duration: ${duration}"
+}
+
+# banIP table statistics
+#
+f_report() {
+ local report_jsn report_txt set nft_raw nft_sets set_cnt set_input set_forward set_cntinput set_cntforward output="${1}"
+ local detail set_details jsnval timestamp autoadd_allow autoadd_block sum_sets sum_setinput sum_setforward sum_setelements sum_cntinput sum_cntforward
+
+ [ -z "${ban_dev}" ] && f_conf
+ f_mkdir "${ban_reportdir}"
+ report_jsn="${ban_reportdir}/ban_report.jsn"
+ report_txt="${ban_reportdir}/ban_report.txt"
+
+ # json output preparation
+ #
+ nft_raw="$("${ban_nftcmd}" -tj list table inet banIP 2>/dev/null)"
+ nft_sets="$(printf "%s" "${nft_raw}" | jsonfilter -qe '@.nftables[*].set.name')"
+ sum_sets="0"
+ sum_setinput="0"
+ sum_setforward="0"
+ sum_setelements="0"
+ sum_cntinput="0"
+ sum_cntforward="0"
+ timestamp="$(date "+%Y-%m-%d %H:%M:%S")"
+ : >"${report_jsn}"
+ {
+ printf "%s\n" "{"
+ printf "\t%s\n" '"sets": {'
+ for set in ${nft_sets}; do
+ set_cnt="$("${ban_nftcmd}" -j list set inet banIP "${set}" 2>/dev/null | jsonfilter -qe '@.nftables[*].set.elem[*]' | wc -l 2>/dev/null)"
+ sum_setelements="$((sum_setelements + set_cnt))"
+ set_cntinput="$(printf "%s" "${nft_raw}" | jsonfilter -qe "@.nftables[@.rule.chain=\"wan-input\"][@.expr[*].match.right=\"@${set}\"].expr[*].counter.packets")"
+ set_cntforward="$(printf "%s" "${nft_raw}" | jsonfilter -qe "@.nftables[@.rule.chain=\"lan-forward\"][@.expr[*].match.right=\"@${set}\"].expr[*].counter.packets")"
+ if [ -n "${set_cntinput}" ]; then
+ set_input="OK"
+ sum_setinput="$((sum_setinput + 1))"
+ sum_cntinput="$((sum_cntinput + set_cntinput))"
+ else
+ set_input="n/a"
+ set_cntinput="n/a"
+ fi
+ if [ -n "${set_cntforward}" ]; then
+ set_forward="OK"
+ sum_setforward="$((sum_setforward + 1))"
+ sum_cntforward="$((sum_cntforward + set_cntforward))"
+ else
+ set_forward="n/a"
+ set_cntforward="n/a"
+ fi
+ [ "${sum_sets}" -gt "0" ] && printf "%s\n" ","
+ printf "\t\t%s\n" "\"${set}\": {"
+ printf "\t\t\t%s\n" "\"cnt_elements\": \"${set_cnt}\","
+ printf "\t\t\t%s\n" "\"input\": \"${set_input}\","
+ printf "\t\t\t%s\n" "\"forward\": \"${set_forward}\","
+ printf "\t\t\t%s\n" "\"cnt_input\": \"${set_cntinput}\","
+ printf "\t\t\t%s\n" "\"cnt_forward\": \"${set_cntforward}\""
+ printf "\t\t%s" "}"
+ sum_sets="$((sum_sets + 1))"
+ done
+ printf "\n\t%s\n" "},"
+ printf "\t%s\n" "\"timestamp\": \"${timestamp}\","
+ printf "\t%s\n" "\"autoadd_allow\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_allowlist}")\","
+ printf "\t%s\n" "\"autoadd_block\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_blocklist}")\","
+ printf "\t%s\n" "\"sum_sets\": \"${sum_sets}\","
+ printf "\t%s\n" "\"sum_setinput\": \"${sum_setinput}\","
+ printf "\t%s\n" "\"sum_setforward\": \"${sum_setforward}\","
+ printf "\t%s\n" "\"sum_setelements\": \"${sum_setelements}\","
+ printf "\t%s\n" "\"sum_cntinput\": \"${sum_cntinput}\","
+ printf "\t%s\n" "\"sum_cntforward\": \"${sum_cntforward}\""
+ printf "%s\n" "}"
+ } >>"${report_jsn}"
+
+ # text output preparation
+ #
+ if [ "${output}" != "json" ] && [ -s "${report_jsn}" ]; then
+ : >"${report_txt}"
+ json_init
+ if json_load_file "${report_jsn}" >/dev/null 2>&1; then
+ json_get_var timestamp "timestamp" >/dev/null 2>&1
+ json_get_var autoadd_allow "autoadd_allow" >/dev/null 2>&1
+ json_get_var autoadd_block "autoadd_block" >/dev/null 2>&1
+ json_get_var sum_sets "sum_sets" >/dev/null 2>&1
+ json_get_var sum_setinput "sum_setinput" >/dev/null 2>&1
+ json_get_var sum_setforward "sum_setforward" >/dev/null 2>&1
+ json_get_var sum_setelements "sum_setelements" >/dev/null 2>&1
+ json_get_var sum_cntinput "sum_cntinput" >/dev/null 2>&1
+ json_get_var sum_cntforward "sum_cntforward" >/dev/null 2>&1
+ {
+ printf "%s\n%s\n%s\n" ":::" "::: banIP Set Statistics" ":::"
+ printf "%s\n" " Timestamp: ${timestamp}"
+ printf "%s\n" " ------------------------------"
+ printf "%s\n" " auto-added to allowlist: ${autoadd_allow}"
+ printf "%s\n\n" " auto-added to blocklist: ${autoadd_block}"
+ json_select "sets" >/dev/null 2>&1
+ json_get_keys nft_sets >/dev/null 2>&1
+ if [ -n "${nft_sets}" ]; then
+ printf "%-25s%-16s%-16s%-16s%-16s%s\n" " Set" "| Set Elements" "| Chain Input" "| Chain Forward" "| Input Packets" "| Forward Packets"
+ printf "%s\n" " ---------------------+---------------+---------------+---------------+---------------+----------------"
+ for set in ${nft_sets}; do
+ printf " %-21s" "${set}"
+ json_select "${set}"
+ json_get_keys set_details
+ for detail in ${set_details}; do
+ json_get_var jsnval "${detail}" >/dev/null 2>&1
+ printf "%-16s" "| ${jsnval}"
+ done
+ printf "\n"
+ json_select ".."
+ done
+ printf "%s\n" " ---------------------+---------------+---------------+---------------+---------------+----------------"
+ printf "%-25s%-16s%-16s%-16s%-16s%s\n" " ${sum_sets}" "| ${sum_setelements}" "| ${sum_setinput}" "| ${sum_setforward}" "| ${sum_cntinput}" "| ${sum_cntforward}"
+ fi
+ } >>"${report_txt}"
+ fi
+ fi
+
+ # output channel (text|json|mail)
+ #
+ case "${output}" in
+ "text")
+ [ -s "${report_txt}" ] && cat "${report_txt}"
+ ;;
+ "json")
+ [ -s "${report_jsn}" ] && cat "${report_jsn}"
+ ;;
+ "mail")
+ [ -x "${ban_mailcmd}" ] && f_mail
+ ;;
+ esac
+}
+
+# banIP set search
+#
+f_search() {
+ local nft_sets ip proto run_search search="${1}"
+
+ f_system
+ run_search="/var/run/banIP.search"
+
+ if [ -n "${search}" ]; then
+ ip="$(printf "%s" "${search}" | "${ban_awkcmd}" 'BEGIN{RS="(([0-9]{1,3}\\.){3}[0-9]{1,3})+"}{printf "%s",RT}')"
+ [ -n "${ip}" ] && proto="v4"
+ if [ -z "${proto}" ]; then
+ ip="$(printf "%s" "${search}" | "${ban_awkcmd}" 'BEGIN{RS="([A-Fa-f0-9]{1,4}::?){3,7}[A-Fa-f0-9]{1,4}"}{printf "%s",RT}')"
+ [ -n "${ip}" ] && proto="v6"
+ fi
+ if [ -n "${proto}" ]; then
+ nft_sets="$("${ban_nftcmd}" -tj list table inet banIP 2>/dev/null | jsonfilter -qe "@.nftables[@.set.type=\"ip${proto}_addr\"].set.name")"
+ else
+ printf "%s\n%s\n%s\n" ":::" "::: no valid search input (single IPv4/IPv6 address)" ":::"
+ return
+ fi
+ else
+ printf "%s\n%s\n%s\n" ":::" "::: no valid search input (single IPv4/IPv6 address)" ":::"
+ return
+ fi
+ printf "%s\n%s\n%s\n" ":::" "::: banIP Search" ":::"
+ printf "%s\n" " Looking for IP ${ip} on $(date "+%Y-%m-%d %H:%M:%S")"
+ printf "%s\n" " ---"
+ cnt=1
+ for set in ${nft_sets}; do
+ (
+ if "${ban_nftcmd}" get element inet banIP "${set}" "{ ${ip} }" >/dev/null 2>&1; then
+ printf "%s\n" " IP found in set ${set}"
+ : >"${run_search}"
+ fi
+ ) &
+ hold="$((cnt % ban_cores))"
+ [ "${hold}" = "0" ] && wait
+ cnt="$((cnt + 1))"
+ done
+ wait
+ [ ! -f "${run_search}" ] && printf "%s\n" " IP not found"
+ rm -f "${run_search}"
+}
+
+# send status mails
+#
+f_mail() {
+ local msmtp_debug
+
+ # load mail template
+ #
+ [ ! -r "${ban_mailtemplate}" ] && f_log "err" "the mail template is missing"
+ . "${ban_mailtemplate}"
+
+ [ -z "${ban_mailreceiver}" ] && f_log "err" "the option 'ban_mailreceiver' is missing"
+ [ -z "${mail_text}" ] && f_log "err" "the 'mail_text' is empty"
+ [ "${ban_debug}" = "1" ] && msmtp_debug="--debug"
+
+ # send mail
+ #
+ ban_mailhead="From: ${ban_mailsender}\nTo: ${ban_mailreceiver}\nSubject: ${ban_mailtopic}\nReply-to: ${ban_mailsender}\nMime-Version: 1.0\nContent-Type: text/html;charset=utf-8\nContent-Disposition: inline\n\n"
+ if printf "%b" "${ban_mailhead}${mail_text}" | "${ban_mailcmd}" --timeout=10 ${msmtp_debug} -a "${ban_mailprofile}" "${ban_mailreceiver}" >/dev/null 2>&1; then
+ f_log "info" "status mail was sent successfully"
+ else
+ f_log "info" "failed to send status mail (${?})"
+ fi
+
+ f_log "debug" "f_mail ::: template: ${ban_mailtemplate}, profile: ${ban_mailprofile}, receiver: ${ban_mailreceiver}, rc: ${?}"
+}
+
+# check banIP availability and initial sourcing
+#
+if [ "${ban_action}" != "stop" ]; then
+ 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
+ [ ! -d "/etc/banip" ] && f_log "err" "banIP config directory not found, please re-install the package"
+ [ ! -r "/etc/config/banip" ] && f_log "err" "banIP config not found, please re-install the package"
+ [ ! -r "/etc/banip/banip.feeds.gz" ] || ! zcat "$(uci_get banip global ban_feedarchive "/etc/banip/banip.feeds.gz")" >"$(uci_get banip global ban_basedir "/tmp")/ban_feeds.json" && f_log "err" "banIP feed archive not found, please re-install the package"
+ [ "$(uci_get banip global ban_enabled)" = "0" ] && f_log "err" "banIP is currently disabled, please set the config option 'ban_enabled' to '1' to use this service"
+fi
--- /dev/null
+#!/bin/sh
+# banIP main service script - ban incoming and outgoing ip adresses/subnets via sets in nftables
+# Copyright (c) 2018-2023 Dirk Brenken (dev@brenken.org)
+# This is free software, licensed under the GNU General Public License v3.
+
+# (s)hellcheck exceptions
+# shellcheck disable=all
+
+ban_action="${1}"
+ban_starttime="$(date "+%s")"
+ban_funlib="/usr/lib/banip-functions.sh"
+[ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
+
+# load config and set banIP environment
+#
+f_conf
+f_log "info" "start banIP processing (${ban_action})"
+f_genstatus "processing"
+f_tmp
+f_fetch
+f_getif
+f_getdev
+f_getsub
+f_mkdir "${ban_backupdir}"
+f_mkfile "${ban_blocklist}"
+f_mkfile "${ban_allowlist}"
+
+# firewall check
+#
+if [ "${ban_action}" != "reload" ]; then
+ if [ -x "${ban_fw4cmd}" ]; then
+ cnt=0
+ while [ "${cnt}" -lt "10" ] && ! /etc/init.d/firewall status | grep -q "^active"; do
+ cnt="$((cnt + 1))"
+ sleep 1
+ done
+ if ! /etc/init.d/firewall status | grep -q "^active"; then
+ f_log "err" "nft based firewall/fw4 not functional"
+ fi
+ else
+ f_log "err" "nft based firewall/fw4 not found"
+ fi
+fi
+
+# init nft namespace
+#
+if [ "${ban_action}" != "reload" ] || ! "${ban_nftcmd}" -t list table inet banIP >/dev/null 2>&1; then
+ if f_nftinit "${ban_tmpfile}".init.nft; then
+ f_log "info" "nft namespace initialized"
+ else
+ f_log "err" "nft namespace can't be initialized"
+ fi
+fi
+
+# handle downloads
+#
+f_log "info" "start banIP download processes"
+if [ "${ban_allowlistonly}" = "1" ]; then
+ ban_feed=""
+else
+ json_init
+ if ! json_load_file "${ban_basedir}/ban_feeds.json" >/dev/null 2>&1; then
+ f_log "err" "banIP feed file can't be loaded"
+ fi
+ [ "${ban_deduplicate}" = "1" ] && printf "\n" >"${ban_tmpfile}.deduplicate"
+fi
+
+cnt="1"
+for feed in allowlist ${ban_feed} blocklist; do
+ # local feeds
+ #
+ if [ "${feed}" = "allowlist" ] || [ "${feed}" = "blocklist" ]; then
+ for proto in MAC 4 6; do
+ [ "${feed}" = "blocklist" ] && wait
+ (f_down "${feed}" "${proto}") &
+ [ "${feed}" = "blocklist" ] || { [ "${feed}" = "allowlist" ] && [ "${proto}" = "MAC" ]; } && wait
+ hold="$((cnt % ban_cores))"
+ [ "${hold}" = "0" ] && wait
+ cnt="$((cnt + 1))"
+ done
+ wait
+ continue
+ fi
+
+ # read external feed information
+ #
+ if ! json_select "${feed}" >/dev/null 2>&1; then
+ continue
+ fi
+ json_objects="url_4 rule_4 url_6 rule_6 flag"
+ for object in ${json_objects}; do
+ eval json_get_var feed_"${object}" '${object}' >/dev/null 2>&1
+ done
+ json_select ..
+ # handle IPv4/IPv6 feeds with the same/single download URL
+ #
+ if [ "${feed_url_4}" = "${feed_url_6}" ]; then
+ if [ "${ban_protov4}" = "1" ] && [ -n "${feed_url_4}" ] && [ -n "${feed_rule_4}" ]; then
+ (f_down "${feed}" "4" "${feed_url_4}" "${feed_rule_4}" "${feed_flag}") &
+ feed_url_6="local"
+ wait
+ fi
+ if [ "${ban_protov6}" = "1" ] && [ -n "${feed_url_6}" ] && [ -n "${feed_rule_6}" ]; then
+ (f_down "${feed}" "6" "${feed_url_6}" "${feed_rule_6}" "${feed_flag}") &
+ hold="$((cnt % ban_cores))"
+ [ "${hold}" = "0" ] && wait
+ cnt="$((cnt + 1))"
+ fi
+ continue
+ fi
+ # handle IPv4/IPv6 feeds with separated download URLs
+ #
+ if [ "${ban_protov4}" = "1" ] && [ -n "${feed_url_4}" ] && [ -n "${feed_rule_4}" ]; then
+ (f_down "${feed}" "4" "${feed_url_4}" "${feed_rule_4}" "${feed_flag}") &
+ hold="$((cnt % ban_cores))"
+ [ "${hold}" = "0" ] && wait
+ cnt="$((cnt + 1))"
+ fi
+ if [ "${ban_protov6}" = "1" ] && [ -n "${feed_url_6}" ] && [ -n "${feed_rule_6}" ]; then
+ (f_down "${feed}" "6" "${feed_url_6}" "${feed_rule_6}" "${feed_flag}") &
+ hold="$((cnt % ban_cores))"
+ [ "${hold}" = "0" ] && wait
+ cnt="$((cnt + 1))"
+ fi
+done
+wait
+
+# start domain lookup
+#
+f_log "info" "start detached banIP domain lookup"
+(f_lookup "allowlist") &
+hold="$((cnt % ban_cores))"
+[ "${hold}" = "0" ] && wait
+(f_lookup "blocklist") &
+
+# tidy up
+#
+f_rmset
+f_rmdir "${ban_tmpdir}"
+f_genstatus "active"
+f_log "info" "finished banIP download processes"
+rm -rf "${ban_lock}"
+
+# start log service
+#
+if [ -x "${ban_logreadcmd}" ] && [ -n "${ban_logterm%%??}" ]; then
+ f_log "info" "start detached banIP log service"
+
+ nft_expiry="$(printf "%s" "${ban_nftexpiry}" | grep -oE "([0-9]+[h|m|s]$)")"
+ [ -n "${nft_expiry}" ] && nft_expiry="timeout ${nft_expiry}"
+
+ # read log continuously with given logterms
+ #
+ "${ban_logreadcmd}" -fe "${ban_logterm%%??}" 2>/dev/null |
+ while read -r line; do
+ # IPv4 log parsing
+ #
+ ip="$(printf "%s" "${line}" | "${ban_awkcmd}" 'BEGIN{RS="(([0-9]{1,3}\\.){3}[0-9]{1,3})+"}{if(!seen[RT]++)printf "%s ",RT}')"
+ ip="$(f_trim "${ip}")"
+ ip="${ip##* }"
+ [ -n "${ip}" ] && proto="v4"
+ if [ -z "${proto}" ]; then
+ # IPv6 log parsing
+ #
+ ip="$(printf "%s" "${line}" | "${ban_awkcmd}" 'BEGIN{RS="([A-Fa-f0-9]{1,4}::?){3,7}[A-Fa-f0-9]{1,4}"}{if(!seen[RT]++)printf "%s ",RT}')"
+ ip="$(f_trim "${ip}")"
+ ip="${ip##* }"
+ [ -n "${ip}" ] && proto="v6"
+ fi
+ if [ -n "${proto}" ] && ! "${ban_nftcmd}" get element inet banIP blocklist"${proto}" "{ ${ip} }" >/dev/null 2>&1; then
+ f_log "info" "suspicious IP found '${ip}'"
+ log_raw="$("${ban_logreadcmd}" -l "${ban_loglimit}" 2>/dev/null)"
+ log_count="$(printf "%s\n" "${log_raw}" | grep -c "found '${ip}'")"
+ if [ "${log_count}" -ge "${ban_logcount}" ]; then
+ if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" "{ ${ip} ${nft_expiry} }" >/dev/null 2>&1; then
+ f_log "info" "added IP '${ip}' (${nft_expiry:-"-"}) to blocklist${proto} set"
+ if [ "${ban_autoblocklist}" = "1" ] && ! grep -q "^${ip}" "${ban_blocklist}"; then
+ printf "%-42s%s\n" "${ip}" "# added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_blocklist}"
+ f_log "info" "added IP '${ip}' to local blocklist"
+ fi
+ fi
+ fi
+ fi
+ done
+
+# start no-op service loop
+#
+else
+ f_log "info" "start detached no-op banIP service (logterms are missing)"
+ while :; do
+ sleep 1
+ done
+fi
config banip 'global'
option ban_enabled '0'
option ban_debug '0'
- option ban_mail_enabled '0'
- option ban_monitor_enabled '0'
- option ban_logsrc_enabled '0'
- option ban_logdst_enabled '0'
option ban_autodetect '1'
- option ban_autoblacklist '1'
- option ban_autowhitelist '1'
- option ban_nice '0'
- option ban_maxqueue '4'
- option ban_global_settype 'src+dst'
- option ban_target_src 'DROP'
- option ban_target_dst 'REJECT'
- option ban_loglimit '100'
+ list ban_logterm 'Exit before auth from'
+ list ban_logterm 'luci: failed login'
+ list ban_logterm 'error: maximum authentication attempts exceeded'
+ list ban_logterm 'sshd.*Connection closed by.*\[preauth\]'
+ list ban_logterm 'SecurityEvent=\"ChallengeResponseFailed\".*RemoteAddress='
+++ /dev/null
-#!/bin/sh
-# helper script to resolve domains for adding to banIP-related IPSets
-# Copyright (c) 2020-2021 Dirk Brenken (dev@brenken.org)
-# This is free software, licensed under the GNU General Public License v3.
-
-# (s)hellcheck exceptions
-# shellcheck disable=1091,3040
-
-export LC_ALL=C
-export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
-set -o pipefail
-
-. "/lib/functions.sh"
-
-ban_src_name="${1}"
-ban_src_file="${2}"
-ban_tmpbase="$(uci_get banip global ban_tmpbase "/tmp")"
-ban_backupdir="$(uci_get banip global ban_backupdir "${ban_tmpbase}/banIP-Backup")"
-ban_proto4_enabled="$(uci_get banip global ban_proto4_enabled "0")"
-ban_proto6_enabled="$(uci_get banip global ban_proto6_enabled "0")"
-ban_ipset_cmd="$(command -v ipset)"
-ban_lookup_cmd="$(command -v nslookup)"
-ban_logger_cmd="$(command -v logger)"
-ban_cnt_err="0"
-ban_message=""
-
-rm -f "${ban_backupdir}/banIP.${ban_src_name}_addon_4" "${ban_backupdir}/banIP.${ban_src_name}_addon_6"
-while read -r domain; do
- result="$(
- "${ban_lookup_cmd}" "${domain}" 2>/dev/null
- printf "%s" "${?}"
- )"
- if [ "$(printf "%s" "${result}" | tail -1)" = "0" ]; then
- ips="$(printf "%s" "${result}" | awk '/^Address[ 0-9]*: /{ORS=" ";print $NF}')"
- for ip in ${ips}; do
- for proto in "4" "6"; do
- if { [ "${proto}" = "4" ] && [ "${ban_proto4_enabled}" = "1" ] && [ -n "$("${ban_ipset_cmd}" -q -n list "${ban_src_name}_${proto}")" ] &&
- [ -n "$(printf "%s" "${ip}" | awk '/^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)([[:space:]]|$)/{print $1}')" ]; } ||
- { [ "${proto}" = "6" ] && [ "${ban_proto6_enabled}" = "1" ] && [ -n "$("${ban_ipset_cmd}" -q -n list "${ban_src_name}_${proto}")" ] &&
- [ -n "$(printf "%s" "${ip}" | awk '/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print $1}')" ]; }; then
- printf "%s\n" "add ${ban_src_name}_${proto} ${ip}" >>"${ban_backupdir}/banIP.${ban_src_name}_addon_${proto}"
- fi
- done
- done
- [ -n "${ips}" ] && "${ban_logger_cmd}" -p "debug" -t "banIP-resolve [${$}]" "added IPs of '${domain}' to ${ban_src_name} (${ips})" 2>/dev/null
- else
- ban_cnt_err=$((ban_cnt_err + 1))
- fi
-done <"${ban_src_file}"
-
-for proto in "4" "6"; do
- if { { [ "${proto}" = "4" ] && [ "${ban_proto4_enabled}" = "1" ]; } || { [ "${proto}" = "6" ] && [ "${ban_proto6_enabled}" = "1" ]; }; } &&
- [ ! -s "${ban_backupdir}/banIP.${ban_src_name}_addon_${proto}" ] && [ -s "${ban_backupdir}/banIP.${ban_src_name}_addon_${proto}.gz" ]; then
- gzip -df "${ban_backupdir}/banIP.${ban_src_name}_addon_${proto}.gz" 2>/dev/null
- "${ban_ipset_cmd}" -q -! restore <"${ban_backupdir}/banIP.${ban_src_name}_addon_${proto}"
- ban_message="backup used"
- elif [ -n "$("${ban_ipset_cmd}" -q -n list "${ban_src_name}_${proto}")" ] && [ -s "${ban_backupdir}/banIP.${ban_src_name}_addon_${proto}" ]; then
- "${ban_ipset_cmd}" -q -! restore <"${ban_backupdir}/banIP.${ban_src_name}_addon_${proto}"
- ban_message="${ban_cnt_err} lookup errors"
- fi
- gzip -f "${ban_backupdir}/banIP.${ban_src_name}_addon_${proto}" 2>/dev/null
-done
-"${ban_logger_cmd}" -p "info" -t "banIP-resolve [${$}]" "${ban_src_name} domain import has been finished (${ban_message:-"-"})" 2>/dev/null
-rm -f "${ban_src_file}"
--- /dev/null
+{
+ "adaway": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/adaway-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/adaway-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "adaway IPs",
+ "descurl": "https://github.com/dibdot/banIP-IP-blocklists"
+ },
+ "adguard": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/adguard-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/adguard-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "adguard IPs",
+ "descurl": "https://github.com/dibdot/banIP-IP-blocklists"
+ },
+ "adguardtrackers": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/adguardtrackers-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/adguardtrackers-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "adguardtracker IPs",
+ "descurl": "https://github.com/dibdot/banIP-IP-blocklists"
+ },
+ "antipopads": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/antipopads-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/antipopads-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "antipopads IPs",
+ "descurl": "https://github.com/dibdot/banIP-IP-blocklists"
+ },
+ "asn": {
+ "url_4": "https://asn.ipinfo.app/api/text/list/",
+ "url_6": "https://asn.ipinfo.app/api/text/list/",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "ASN IPs",
+ "descurl": "https://asn.ipinfo.app"
+ },
+ "backscatterer": {
+ "url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/ips.backscatterer.org.gz",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "backscatterer IPs",
+ "descurl": "https://www.uceprotect.net/en/index.php",
+ "flag": "gz"
+ },
+ "bogon": {
+ "url_4": "https://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt",
+ "url_6": "https://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "bogon prefixes",
+ "descurl": "https://team-cymru.com"
+ },
+ "cinsscore": {
+ "url_4": "https://cinsscore.com/list/ci-badguys.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "suspicious attacker IPs",
+ "descurl": "https://cinsscore.com/#list"
+ },
+ "country": {
+ "url_4": "https://www.ipdeny.com/ipblocks/data/aggregated/",
+ "url_6": "https://www.ipdeny.com/ipv6/ipaddresses/aggregated/",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "country blocks",
+ "descurl": "http://www.ipdeny.com/ipblocks"
+ },
+ "darklist": {
+ "url_4": "https://darklist.de/raw.php",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "suspicious attacker IPs",
+ "descurl": "https://darklist.de"
+ },
+ "debl": {
+ "url_4": "https://www.blocklist.de/downloads/export-ips_all.txt",
+ "url_6": "https://www.blocklist.de/downloads/export-ips_all.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "fail2ban IP blacklist",
+ "descurl": "https://www.blocklist.de"
+ },
+ "doh": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/DoH-IP-blocklists/master/doh-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/DoH-IP-blocklists/master/doh-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "public DoH-Provider",
+ "descurl": "https://github.com/dibdot/DoH-IP-blocklists"
+ },
+ "drop": {
+ "url_4": "https://www.spamhaus.org/drop/drop.txt",
+ "url_6": "https://www.spamhaus.org/drop/dropv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "spamhaus drop compilation",
+ "descurl": "https://www.spamhaus.org"
+ },
+ "dshield": {
+ "url_4": "https://feeds.dshield.org/block.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s/%s,\\n\",$1,$3}",
+ "focus": "dshield IP blocklist",
+ "descurl": "https://www.dshield.org"
+ },
+ "edrop": {
+ "url_4": "https://www.spamhaus.org/drop/edrop.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "spamhaus edrop compilation",
+ "descurl": "https://www.spamhaus.org"
+ },
+ "feodo": {
+ "url_4": "https://feodotracker.abuse.ch/downloads/ipblocklist.txt",
+ "rule_4": "BEGIN{RS=\"\\r\\n\"}/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "feodo tracker",
+ "descurl": "https://feodotracker.abuse.ch"
+ },
+ "firehol1": {
+ "url_4": "https://iplists.firehol.org/files/firehol_level1.netset",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "firehol level 1 compilation",
+ "descurl": "https://iplists.firehol.org/?ipset=firehol_level1"
+ },
+ "firehol2": {
+ "url_4": "https://iplists.firehol.org/files/firehol_level2.netset",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "firehol level 2 compilation",
+ "descurl": "https://iplists.firehol.org/?ipset=firehol_level2"
+ },
+ "firehol3": {
+ "url_4": "https://iplists.firehol.org/files/firehol_level3.netset",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "firehol level 3 compilation",
+ "descurl": "https://iplists.firehol.org/?ipset=firehol_level3"
+ },
+ "firehol4": {
+ "url_4": "https://iplists.firehol.org/files/firehol_level4.netset",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{if(!seen[$1]++)printf \"%s,\\n\",$1}",
+ "focus": "firehol level 4 compilation",
+ "descurl": "https://iplists.firehol.org/?ipset=firehol_level4"
+ },
+ "greensnow": {
+ "url_4": "https://blocklist.greensnow.co/greensnow.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "suspicious server IPs",
+ "descurl": "https://greensnow.co"
+ },
+ "iblockads": {
+ "url_4": "https://list.iblocklist.com/?list=dgxtneitpuvgqqcpfulq&fileformat=cidr&archiveformat=gz",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "advertising IPs",
+ "descurl": "https://www.iblocklist.com",
+ "flag": "gz",
+ "login": true
+ },
+ "iblockspy": {
+ "url_4": "https://list.iblocklist.com/?list=llvtlsjyoyiczbkjsxpf&fileformat=cidr&archiveformat=gz",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "malicious spyware IPs",
+ "descurl": "https://www.iblocklist.com",
+ "flag": "gz",
+ "login": true
+ },
+ "myip": {
+ "url_4": "https://myip.ms/files/blacklist/general/latest_blacklist.txt",
+ "url_6": "https://myip.ms/files/blacklist/general/latest_blacklist.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "real-time IP blocklist",
+ "descurl": "https://myip.ms"
+ },
+ "nixspam": {
+ "url_4": "https://www.nixspam.net/download/nixspam-ip.dump.gz",
+ "rule_4": "/(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$2}",
+ "focus": "iX spam protection",
+ "descurl": "https://www.nixspam.net",
+ "flag": "gz"
+ },
+ "oisdnsfw": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/oisdnsfw-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/oisdnsfw-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "OISD-nsfw IPs",
+ "descurl": "https://github.com/dibdot/banIP-IP-blocklists"
+ },
+ "oisdsmall": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/oisdsmall-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/oisdsmall-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "OISD-small IPs",
+ "descurl": "https://github.com/dibdot/banIP-IP-blocklists"
+ },
+ "proxy": {
+ "url_4": "https://iplists.firehol.org/files/proxylists.ipset",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "open proxies",
+ "descurl": "https://iplists.firehol.org/?ipset=proxylists"
+ },
+ "sslbl": {
+ "url_4": "https://sslbl.abuse.ch/blacklist/sslipblacklist.csv",
+ "rule_4": "BEGIN{FS=\",\"}/(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)/{printf \"%s,\\n\",$2}",
+ "focus": "SSL botnet IPs",
+ "descurl": "https://sslbl.abuse.ch"
+ },
+ "stevenblack": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/stevenblack-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/stevenblack-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "stevenblack IPs",
+ "descurl": "https://github.com/dibdot/banIP-IP-blocklists"
+ },
+ "talos": {
+ "url_4": "https://www.talosintelligence.com/documents/ip-blacklist",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "talos IPs",
+ "descurl": "https://talosintelligence.com/reputation_center"
+ },
+ "threat": {
+ "url_4": "https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "emerging threats",
+ "descurl": "https://rules.emergingthreats.net"
+ },
+ "threatview": {
+ "url_4": "https://threatview.io/Downloads/IP-High-Confidence-Feed.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "malicious IPs",
+ "descurl": "https://threatview.io"
+ },
+ "tor": {
+ "url_4": "https://raw.githubusercontent.com/SecOps-Institute/Tor-IP-Addresses/master/tor-exit-nodes.lst",
+ "url_6": "https://raw.githubusercontent.com/SecOps-Institute/Tor-IP-Addresses/master/tor-exit-nodes.lst",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "tor exit nodes",
+ "descurl": "https://github.com/SecOps-Institute/Tor-IP-Addresses"
+ },
+ "uceprotect1": {
+ "url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/dnsbl-1.uceprotect.net.gz",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "spam protection level 1",
+ "descurl": "http://www.uceprotect.net/en/index.php",
+ "flag": "gz"
+ },
+ "uceprotect2": {
+ "url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/dnsbl-2.uceprotect.net.gz",
+ "rule_4": "BEGIN{IGNORECASE=1}/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]NET)/{printf \"%s,\\n\",$1}",
+ "focus": "spam protection level 2",
+ "descurl": "http://www.uceprotect.net/en/index.php",
+ "flag": "gz"
+ },
+ "uceprotect3": {
+ "url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/dnsbl-3.uceprotect.net.gz",
+ "rule_4": "BEGIN{IGNORECASE=1}/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]YOUR)/{printf \"%s,\\n\",$1}",
+ "focus": "spam protection level 3",
+ "descurl": "http://www.uceprotect.net/en/index.php",
+ "flag": "gz"
+ },
+ "urlhaus": {
+ "url_4": "https://urlhaus.abuse.ch/downloads/ids/",
+ "rule_4": "match($0,/(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5]))/){printf \"%s,\\n\",substr($0,RSTART,RLENGTH)}",
+ "focus": "urlhaus IDS IPs",
+ "descurl": "https://urlhaus.abuse.ch"
+ },
+ "urlvir": {
+ "url_4": "https://iplists.firehol.org/files/urlvir.ipset",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "malware related IPs",
+ "descurl": "https://iplists.firehol.org/?ipset=urlvir"
+ },
+ "voip": {
+ "url_4": "https://voipbl.org/update/",
+ "rule_4": "BEGIN{RS=\"(([0-9]{1,3}\\\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)\"}{if(RT)printf \"%s,\\n\",RT}",
+ "focus": "VoIP fraud blocklist",
+ "descurl": "https://voipbl.org"
+ },
+ "webclient": {
+ "url_4": "https://iplists.firehol.org/files/firehol_webclient.netset",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}",
+ "focus": "malware related IPs",
+ "descurl": "https://iplists.firehol.org/?ipset=firehol_webclient"
+ },
+ "yoyo": {
+ "url_4": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/yoyo-ipv4.txt",
+ "url_6": "https://raw.githubusercontent.com/dibdot/banIP-IP-blocklists/main/yoyo-ipv6.txt",
+ "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}",
+ "focus": "yoyo IPs",
+ "descurl": "https://github.com/dibdot/banIP-IP-blocklists"
+ }
+}
+++ /dev/null
-#!/bin/sh
-# firewall hotplug script for banIP
-# Copyright (c) 2019-2021 Dirk Brenken (dev@brenken.org)
-# This is free software, licensed under the GNU General Public License v3.
-
-if /etc/init.d/banip enabled && [ "${ACTION}" = "add" ] && [ -n "${INTERFACE}" ]; then
- if [ ! -s "/var/run/banip.pid" ] && uci_get banip global ban_ifaces | grep -q "${INTERFACE}"; then
- /etc/init.d/banip refresh
- fi
-fi
#!/bin/sh /etc/rc.common
-# Copyright (c) 2018-2021 Dirk Brenken (dev@brenken.org)
+# banIP init script - ban incoming and outgoing ip adresses/subnets via sets in nftables
+# Copyright (c) 2018-2023 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions
-# shellcheck disable=1091,2034,3043,3057,3060
+# shellcheck disable=all
START=30
USE_PROCD=1
-if type extra_command >/dev/null 2>&1; then
- extra_command "refresh" "Refresh ipsets without new list downloads"
- extra_command "suspend" "Suspend banIP processing"
- extra_command "resume" "Resume banIP processing"
- extra_command "query" "<IP> Query active banIP IPSets for a specific IP address"
- extra_command "report" "[<cli>|<mail>|<gen>|<json>] Print banIP related IPset statistics"
- extra_command "list" "[<add>|<add_asn>|<add_country>|<remove>|<remove_asn>|<remove_country>] <source(s)> List/Edit available sources"
- extra_command "timer" "[<add> <tasks> <hour> [<minute>] [<weekday>]]|[<remove> <line no.>] List/Edit cron update intervals"
-else
- EXTRA_COMMANDS="status refresh suspend resume query report list timer version"
- EXTRA_HELP=" status Service status
- refresh Refresh ipsets without new list downloads
- suspend Suspend banIP processing
- resume Resume banIP processing
- query <IP> Query active banIP IPSets for a specific IP address
- report [<cli>|<mail>|<gen>|<json>] Print banIP related IPset statistics
- list [<add>|<add_asn>|<add_country>|<remove>|<remove_asn>|<remove_country>] <source(s)> List/Edit available sources
- timer [<add> <tasks> <hour> [<minute>] [<weekday>]]|[<remove> <line no.>] List/Edit cron update intervals"
-fi
+extra_command "report" "[text|json|mail] Print banIP related set statistics"
+extra_command "search" "[<IPv4 address>|<IPv6 address>] Check if an element exists in the banIP sets"
ban_init="/etc/init.d/banip"
-ban_script="/usr/bin/banip.sh"
+ban_service="/usr/bin/banip-service.sh"
+ban_funlib="/usr/lib/banip-functions.sh"
ban_pidfile="/var/run/banip.pid"
+ban_lock="/var/run/banip.lock"
-if [ -s "${ban_pidfile}" ] && { [ "${action}" = "start" ] || [ "${action}" = "stop" ] ||
- [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "refresh" ] ||
- [ "${action}" = "suspend" ] || [ "${action}" = "resume" ] || [ "${action}" = "query" ] ||
- { [ "${action}" = "list" ] && [ -n "${1}" ]; } || { [ "${action}" = "report" ] && [ "${1}" != "json" ]; }; }; then
- exit 0
-fi
+[ ! -r "${ban_funlib}" ] && exit 1
+[ "${action}" = "stop" ] && ! /etc/init.d/banip running && exit 0
+[ -d "${ban_lock}" ] && { [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ]; } && exit 1
+[ ! -d "${ban_lock}" ] && { [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ]; } && mkdir -p "${ban_lock}"
boot() {
: >"${ban_pidfile}"
- rc_procd start_service
+ rc_procd start_service "boot"
}
start_service() {
if "${ban_init}" enabled; then
- if [ "${action}" = "boot" ]; then
- return 0
- fi
- procd_open_instance "banip"
- procd_set_param command "${ban_script}" "${@}"
+ [ "${action}" = "boot" ] && [ -n "$(uci_get banip global ban_trigger)" ] && return 0
+ [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
+ f_rmpid
+ procd_open_instance "banip-service"
+ procd_set_param command "${ban_service}" "${@:-"${action}"}"
procd_set_param pidfile "${ban_pidfile}"
- procd_set_param nice "$(uci_get banip global ban_nice "0")"
+ procd_set_param nice "$(uci_get banip global ban_nicelimit "0")"
+ procd_set_param limits nofile="$(uci_get banip global ban_filelimit "1024")"
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
+ else
+ [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
+ f_log "err" "banIP service autostart is currently disabled, please enable the service autostart with '/etc/init.d/banip enable'"
+ rm -rf "${ban_lock}"
fi
}
-version() {
- rc_procd "${ban_script}" version
-}
-
-refresh() {
- rc_procd start_service refresh
-}
-
reload_service() {
- rc_procd start_service reload
+ [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
+ f_rmpid
+ rc_procd start_service "reload"
}
stop_service() {
- rc_procd "${ban_script}" stop
+ [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
+ "${ban_nftcmd}" delete table inet banIP >/dev/null 2>&1
+ f_genstatus "stopped"
+ f_rmpid
}
restart() {
- rc_procd start_service restart
-}
-
-suspend() {
- rc_procd start_service suspend
-}
-
-resume() {
- rc_procd start_service resume
-}
-
-query() {
- rc_procd "${ban_script}" query "${1}"
-}
-
-list() {
- local src_archive src_file src_enabled key name enabled focus descurl url_4 rule_4 url_6 rule_6 action="${1}"
-
- if [ "${action%_*}" = "add" ] || [ "${action%_*}" = "remove" ]; then
- shift
- for name in "${@}"; do
- case "${action}" in
- "add")
- if ! uci_get banip global ban_sources | grep -q "${name}"; then
- uci_add_list banip global ban_sources "${name}"
- printf "%s\n" "::: banIP source '${name}' added to config"
- fi
- ;;
- "remove")
- if uci_get banip global ban_sources | grep -q "${name}"; then
- uci_remove_list banip global ban_sources "${name}"
- printf "%s\n" "::: banIP source '${name}' removed from config"
- fi
- ;;
- "add_asn")
- if ! uci_get banip global ban_asns | grep -q "${name}"; then
- uci_add_list banip global ban_asns "${name}"
- printf "%s\n" "::: banIP asn '${name}' added to config"
- fi
- ;;
- "remove_asn")
- if uci_get banip global ban_asns | grep -q "${name}"; then
- uci_remove_list banip global ban_asns "${name}"
- printf "%s\n" "::: banIP asn '${name}' removed from config"
- fi
- ;;
- "add_country")
- if ! uci_get banip global ban_countries | grep -q "${name}"; then
- uci_add_list banip global ban_countries "${name}"
- printf "%s\n" "::: banIP country '${name}' added to config"
- fi
- ;;
- "remove_country")
- if uci_get banip global ban_countries | grep -q "${name}"; then
- uci_remove_list banip global ban_countries "${name}"
- printf "%s\n" "::: banIP country '${name}' removed from config"
- fi
- ;;
- esac
- done
- if [ -n "$(uci -q changes banip)" ]; then
- uci_commit banip
- "${ban_init}" start
- fi
- else
- src_archive="$(uci_get banip global ban_srcarc "/etc/banip/banip.sources.gz")"
- src_file="$(uci_get banip global ban_srcfile "/tmp/ban_sources.json")"
- src_enabled="$(uci -q show banip.global.ban_sources)"
- if [ -r "${src_archive}" ]; then
- zcat "${src_archive}" >"${src_file}"
- else
- printf "%s\n" "::: banIP source archive '${src_archive}' not found"
- fi
- if [ -r "${src_file}" ]; then
- src_enabled="${src_enabled#*=}"
- src_enabled="${src_enabled//\'/}"
- printf "%s\n" "::: Available banIP sources"
- printf "%s\n" ":::"
- printf "%-25s%-10s%-36s%s\n" " Name" "Enabled" "Focus" "Info URL"
- printf "%s\n" " ---------------------------------------------------------------------------"
- json_load_file "${src_file}"
- json_get_keys keylist
- for key in ${keylist}; do
- json_select "${key}"
- json_get_var focus "focus"
- json_get_var descurl "descurl"
- json_get_var url_4 "url_4"
- json_get_var rule_4 "rule_4"
- json_get_var url_6 "url_6"
- json_get_var rule_6 "rule_6"
- if { [ -n "${url_4}" ] && [ -n "${rule_4}" ]; } || { [ -n "${url_6}" ] && [ -n "${rule_6}" ]; }; then
- if printf "%s" "${src_enabled}" | grep -q "${key}"; then
- enabled="x"
- else
- enabled=" "
- fi
- src_enabled="${src_enabled/${key}/}"
- printf " + %-21s%-10s%-36s%s\n" "${key:0:20}" "${enabled}" "${focus:0:35}" "${descurl:0:50}"
- else
- src_enabled="${src_enabled} ${key}"
- fi
- json_select ..
- done
- asn_list="$(uci_get banip global ban_asns "-")"
- country_list="$(uci_get banip global ban_countries "-")"
- printf "%s\n" " ---------------------------------------------------------------------------"
- printf " * %s\n" "Configured ASNs: ${asn_list// /, }"
- printf " * %s\n" "Configured Countries: ${country_list// /, }"
-
- if [ -n "${src_enabled// /}" ]; then
- printf "%s\n" " ---------------------------------------------------------------------------"
- printf "%s\n" " Sources without valid configuration"
- printf "%s\n" " ---------------------------------------------------------------------------"
- for key in ${src_enabled}; do
- printf " - %s\n" "${key:0:20}"
- done
- fi
- else
- printf "%s\n" "::: banIP source file '${src_file}' not found"
- fi
- fi
+ stop_service
+ rc_procd start_service "restart"
}
status() {
}
status_service() {
- local key keylist type value index_value values rtfile
-
- rtfile="$(uci_get banip global ban_rtfile "/tmp/ban_runtime.json")"
-
- json_load_file "${rtfile}" >/dev/null 2>&1
- json_get_keys keylist
- if [ -n "${keylist}" ]; then
- printf "%s\n" "::: banIP runtime information"
- for key in ${keylist}; do
- json_get_var value "${key}" >/dev/null 2>&1
- if [ "${key%_*}" = "active" ]; then
- printf " + %-15s : " "${key}"
- json_select "${key}" >/dev/null 2>&1
- values=""
- index=1
- while json_get_type type "${index}" && [ "${type}" = "object" ]; do
- json_get_values index_value "${index}" >/dev/null 2>&1
- if [ "${index}" = "1" ]; then
- values="${index_value}"
- else
- values="${values}, ${index_value}"
- fi
- index=$((index + 1))
- done
- values="$(printf "%s" "${values}" | awk '{NR=1;max=98;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max)}else{printf"%-22s%s\n","",substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')"
- printf "%s\n" "${values:-"-"}"
- json_select ".."
- else
- printf " + %-15s : %s\n" "${key}" "${value:-"-"}"
- fi
- done
- else
- printf "%s\n" "::: no banIP runtime information available"
- fi
+ [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
+ f_getstatus
}
report() {
- rc_procd "${ban_script}" report "${1:-"cli"}"
+ [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
+ f_report "${1:-"text"}"
}
-timer() {
- local cron_file cron_content cron_lineno action="${1:-"list"}" cron_tasks="${2}" hour="${3}" minute="${4:-0}" weekday="${5:-"*"}"
-
- cron_file="/etc/crontabs/root"
-
- if [ -s "${cron_file}" ] && [ "${action}" = "list" ]; then
- awk '{print NR "> " $0}' "${cron_file}"
- elif [ "${action}" = "add" ]; then
- hour="${hour//[[:alpha:]]/}"
- minute="${minute//[[:alpha:]]/}"
- if [ -n "${cron_tasks}" ] && [ -n "${hour}" ] && [ -n "${minute}" ] && [ -n "${weekday}" ] &&
- [ "${hour}" -ge 0 ] && [ "${hour}" -le 23 ] &&
- [ "${minute}" -ge 0 ] && [ "${minute}" -le 59 ]; then
- printf "%02d %02d %s\n" "${minute}" "${hour}" "* * ${weekday} ${ban_init} ${cron_tasks}" >>"${cron_file}"
- /etc/init.d/cron restart
- fi
- elif [ -s "${cron_file}" ] && [ "${action}" = "remove" ]; then
- cron_tasks="${cron_tasks//[[:alpha:]]/}"
- cron_lineno="$(awk 'END{print NR}' "${cron_file}")"
- cron_content="$(awk '{print $0}' "${cron_file}")"
- if [ "${cron_tasks:-"0"}" -le "${cron_lineno:-"1"}" ] && [ -n "${cron_content}" ]; then
- printf "%s\n" "${cron_content}" | awk "NR!~/^${cron_tasks}$/" >"${cron_file}"
- /etc/init.d/cron restart
- fi
- fi
+search() {
+ [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
+ f_search "${1}"
}
service_triggers() {
- local iface delay
+ local iface trigger delay
- iface="$(uci_get banip global ban_trigger)"
+ trigger="$(uci_get banip global ban_trigger)"
delay="$(uci_get banip global ban_triggerdelay "5")"
PROCD_RELOAD_DELAY=$((delay * 1000))
- if [ -z "${iface}" ]; then
- . "/lib/functions/network.sh"
- network_find_wan iface
- if [ -n "${iface}" ]; then
- uci_set banip global ban_trigger "${iface}"
- uci_commit "banip"
- fi
- fi
- if [ -n "${iface}" ]; then
+ for iface in ${trigger}; do
procd_add_interface_trigger "interface.*.up" "${iface}" "${ban_init}" "start"
- fi
+ done
procd_add_reload_trigger "banip"
}
+++ /dev/null
-#!/bin/sh
-# send mail script for banIP notifications
-# Copyright (c) 2020-2021 Dirk Brenken (dev@brenken.org)
-# This is free software, licensed under the GNU General Public License v3.
-
-# (s)hellcheck exceptions
-# shellcheck disable=1091,3040
-
-# Please note: you have to setup the package 'msmtp' before using this script
-
-export LC_ALL=C
-export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
-set -o pipefail
-
-. "/lib/functions.sh"
-ban_debug="$(uci_get banip global ban_debug "0")"
-ban_loglimit="$(uci_get banip global ban_loglimit "100")"
-ban_mailsender="$(uci_get banip global ban_mailsender "no-reply@banIP")"
-ban_mailreceiver="$(uci_get banip global ban_mailreceiver)"
-ban_mailtopic="$(uci_get banip global ban_mailtopic "banIP notification")"
-ban_mailprofile="$(uci_get banip global ban_mailprofile "ban_notify")"
-
-ban_mail="$(command -v msmtp)"
-ban_logger="$(command -v logger)"
-ban_logread="$(command -v logread)"
-
-if [ -z "${ban_mailreceiver}" ]; then
- f_log "err" "please set the mail receiver with the 'ban_mailreceiver' option"
- exit 1
-fi
-
-if [ "${ban_debug}" = "1" ]; then
- msmtp_debug="--debug"
-fi
-
-ban_mailhead="From: ${ban_mailsender}\nTo: ${ban_mailreceiver}\nSubject: ${ban_mailtopic}\nReply-to: ${ban_mailsender}\nMime-Version: 1.0\nContent-Type: text/html;charset=utf-8\nContent-Disposition: inline\n\n"
-
-# info preparation
-#
-sys_info="$(
- strings /etc/banner 2>/dev/null
- ubus call system board | awk 'BEGIN{FS="[{}\"]"}{if($2=="kernel"||$2=="hostname"||$2=="system"||$2=="model"||$2=="description")printf " + %-12s: %s\n",$2,$4}'
-)"
-ban_info="$(/etc/init.d/banip "status" 2>/dev/null)"
-rep_info="${1}"
-log_info="$("${ban_logread}" -l "${ban_loglimit}" -e "banIP-" 2>/dev/null | awk '{NR=1;max=120;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max)}else{print substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')"
-
-# mail body
-#
-ban_mailtext="<html><body><pre style='display:block;font-family:monospace;font-size:1rem;padding:20;background-color:#f3eee5;white-space:pre'>"
-ban_mailtext="${ban_mailtext}\n<strong>++\n++ System Information ++\n++</strong>\n${sys_info}"
-ban_mailtext="${ban_mailtext}\n\n<strong>++\n++ banIP Status ++\n++</strong>\n${ban_info}"
-if [ -n "${rep_info}" ]; then
- ban_mailtext="${ban_mailtext}\n\n<strong>++\n++ banIP Report ++\n++</strong>\n${rep_info}"
-fi
-ban_mailtext="${ban_mailtext}\n\n<strong>++\n++ Logfile Information ++\n++</strong>\n${log_info}"
-ban_mailtext="${ban_mailtext}</pre></body></html>"
-
-# send mail
-#
-printf "%b" "${ban_mailhead}${ban_mailtext}" 2>/dev/null | "${ban_mail}" ${msmtp_debug} -a "${ban_mailprofile}" "${ban_mailreceiver}" >/dev/null 2>&1
-"${ban_logger}" -p "info" -t "banIP-mail [${$}]" "mail sent to '${ban_mailreceiver}' with rc '${?}'" 2>/dev/null
+++ /dev/null
-#!/bin/sh
-# log service to trace suspicious logins and conditionally refresh banIP
-# Copyright (c) 2019-2021 Dirk Brenken (dev@brenken.org)
-# This is free software, licensed under the GNU General Public License v3.
-
-# (s)hellcheck exceptions
-# shellcheck disable=3040
-
-export LC_ALL=C
-export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
-set -o pipefail
-
-ban_search="${1}"
-ban_logger_cmd="$(command -v logger)"
-ban_logread_cmd="$(command -v logread)"
-
-if [ -x "${ban_logread_cmd}" ]; then
- "${ban_logger_cmd}" -p "info" -t "banIP-service [${$}]" "log/banIP service started" 2>/dev/null
- "${ban_logread_cmd}" -f |
- {
- grep -qE "${ban_search}" && {
- /etc/init.d/banip refresh
- exit 0
- }
- }
-else
- "${ban_logger_cmd}" -p "err" -t "banIP-service [${$}]" "can't start log/banIP service" 2>/dev/null
-fi
+++ /dev/null
-#!/bin/sh
-# banIP - ban incoming and outgoing ip adresses/subnets via ipset
-# Copyright (c) 2018-2021 Dirk Brenken (dev@brenken.org)
-# This is free software, licensed under the GNU General Public License v3.
-
-# (s)hellcheck exceptions
-# shellcheck disable=1091,2030,2031,2086,2183,3040,3043,3060
-
-# set initial defaults
-#
-export LC_ALL=C
-export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
-set -o pipefail
-ban_ver="0.7.10"
-ban_status=""
-ban_enabled="0"
-ban_mail_enabled="0"
-ban_proto4_enabled="0"
-ban_proto6_enabled="0"
-ban_logsrc_enabled="0"
-ban_logdst_enabled="0"
-ban_monitor_enabled="0"
-ban_autodetect="1"
-ban_autoblacklist="1"
-ban_autowhitelist="1"
-ban_whitelistonly="0"
-ban_logterms=""
-ban_loglimit="100"
-ban_ssh_logcount="3"
-ban_luci_logcount="3"
-ban_nginx_logcount="5"
-ban_mailactions=""
-ban_search=""
-ban_devs=""
-ban_ifaces=""
-ban_debug="0"
-ban_maxqueue="4"
-ban_fetchutil=""
-ban_fetchinsecure="0"
-ban_ip_cmd="$(command -v ip)"
-ban_ipt4_cmd="$(command -v iptables)"
-ban_ipt4_savecmd="$(command -v iptables-save)"
-ban_ipt4_restorecmd="$(command -v iptables-restore)"
-ban_ipt6_cmd="$(command -v ip6tables)"
-ban_ipt6_savecmd="$(command -v ip6tables-save)"
-ban_ipt6_restorecmd="$(command -v ip6tables-restore)"
-ban_ipset_cmd="$(command -v ipset)"
-ban_logger_cmd="$(command -v logger)"
-ban_logread_cmd="$(command -v logread)"
-ban_allsources=""
-ban_extrasources=""
-ban_sources=""
-ban_asns=""
-ban_countries=""
-ban_settype_src=""
-ban_settype_dst=""
-ban_settype_all=""
-ban_lan_inputchains_4=""
-ban_lan_inputchains_6=""
-ban_lan_forwardchains_4=""
-ban_lan_forwardchains_6=""
-ban_wan_inputchains_4=""
-ban_wan_inputchains_6=""
-ban_wan_forwardchains_4=""
-ban_wan_forwardchains_6=""
-ban_action="${1:-"start"}"
-ban_pidfile="/var/run/banip.pid"
-ban_bgpidfile="/var/run/banip_bg.pid"
-ban_tmpbase="/tmp"
-ban_rtfile="${ban_tmpbase}/ban_runtime.json"
-ban_srcfile="${ban_tmpbase}/ban_sources.json"
-ban_reportdir="${ban_tmpbase}/banIP-Report"
-ban_backupdir="${ban_tmpbase}/banIP-Backup"
-ban_srcarc="/etc/banip/banip.sources.gz"
-ban_dnsservice="/etc/banip/banip.dns"
-ban_mailservice="/etc/banip/banip.mail"
-ban_logservice="/etc/banip/banip.service"
-ban_maclist="/etc/banip/banip.maclist"
-ban_blacklist="/etc/banip/banip.blacklist"
-ban_whitelist="/etc/banip/banip.whitelist"
-ban_setcnt="0"
-ban_cnt="0"
-
-# load environment
-#
-f_load() {
- ban_sysver="$(ubus -S call system board 2>/dev/null | jsonfilter -q -e '@.model' -e '@.release.description' |
- awk 'BEGIN{RS="";FS="\n"}{printf "%s, %s",$1,$2}')"
-
- f_conf
- if [ "${ban_enabled}" = "0" ]; then
- f_bgsrv "stop"
- f_ipset "destroy"
- f_jsnup "disabled"
- f_rmbckp
- f_rmtmp
- f_log "info" "banIP is currently disabled, please set the config option 'ban_enabled' to '1' to use this service"
- exit 0
- fi
- f_dir "${ban_backupdir}"
- f_dir "${ban_reportdir}"
-}
-
-# check/create directories
-#
-f_dir() {
- local dir="${1}"
-
- if [ -d "${dir}" ]; then
- f_log "debug" "directory '${dir}' is used"
- else
- rm -f "${dir}"
- mkdir -p "${dir}"
- f_log "debug" "directory '${dir}' created"
- fi
-}
-
-# load banIP config
-#
-f_conf() {
- if [ ! -r "/etc/config/banip" ] || [ -z "$(uci -q show banip.global.ban_autodetect)" ]; then
- f_log "err" "no valid banIP config found, please re-install the package via opkg with the '--force-reinstall --force-maintainer' options"
- fi
-
- config_cb() {
- option_cb() {
- local option="${1}"
- local value="${2}"
- eval "${option}=\"${value}\""
- }
- list_cb() {
- local option="${1}"
- local value="${2}"
- if [ "${option}" = "ban_ifaces" ]; then
- eval "${option}=\"$(printf "%s" "${ban_ifaces}")${value} \""
- elif [ "${option}" = "ban_sources" ]; then
- eval "${option}=\"$(printf "%s" "${ban_sources}")${value} \""
- elif [ "${option}" = "ban_localsources" ]; then
- eval "${option}=\"$(printf "%s" "${ban_localsources}")${value} \""
- elif [ "${option}" = "ban_extrasources" ]; then
- eval "${option}=\"$(printf "%s" "${ban_extrasources}")${value} \""
- elif [ "${option}" = "ban_settype_src" ]; then
- eval "${option}=\"$(printf "%s" "${ban_settype_src}")${value} \""
- elif [ "${option}" = "ban_settype_dst" ]; then
- eval "${option}=\"$(printf "%s" "${ban_settype_dst}")${value} \""
- elif [ "${option}" = "ban_settype_all" ]; then
- eval "${option}=\"$(printf "%s" "${ban_settype_all}")${value} \""
- elif [ "${option}" = "ban_mailactions" ]; then
- eval "${option}=\"$(printf "%s" "${ban_mailactions}")${value} \""
- elif [ "${option}" = "ban_logterms" ]; then
- eval "${option}=\"$(printf "%s" "${ban_logterms}")${value} \""
- elif [ "${option}" = "ban_countries" ]; then
- eval "${option}=\"$(printf "%s" "${ban_countries}")${value} \""
- elif [ "${option}" = "ban_asns" ]; then
- eval "${option}=\"$(printf "%s" "${ban_asns}")${value} \""
- elif [ "${option}" = "ban_lan_inputchains_4" ]; then
- eval "${option}=\"$(printf "%s" "${ban_lan_inputchains_4}")${value} \""
- elif [ "${option}" = "ban_lan_inputchains_6" ]; then
- eval "${option}=\"$(printf "%s" "${ban_lan_inputchains_6}")${value} \""
- elif [ "${option}" = "ban_lan_forwardchains_4" ]; then
- eval "${option}=\"$(printf "%s" "${ban_lan_forwardchains_4}")${value} \""
- elif [ "${option}" = "ban_lan_forwardchains_6" ]; then
- eval "${option}=\"$(printf "%s" "${ban_lan_forwardchains_6}")${value} \""
- elif [ "${option}" = "ban_wan_inputchains_4" ]; then
- eval "${option}=\"$(printf "%s" "${ban_wan_inputchains_4}")${value} \""
- elif [ "${option}" = "ban_wan_inputchains_6" ]; then
- eval "${option}=\"$(printf "%s" "${ban_wan_inputchains_6}")${value} \""
- elif [ "${option}" = "ban_wan_forwardchains_4" ]; then
- eval "${option}=\"$(printf "%s" "${ban_wan_forwardchains_4}")${value} \""
- elif [ "${option}" = "ban_wan_forwardchains_6" ]; then
- eval "${option}=\"$(printf "%s" "${ban_wan_forwardchains_6}")${value} \""
- fi
- }
- }
- config_load banip
-
- ban_chain="${ban_chain:-"banIP"}"
- ban_global_settype="${ban_global_settype:-"src+dst"}"
- ban_target_src="${ban_target_src:-"DROP"}"
- ban_target_dst="${ban_target_dst:-"REJECT"}"
- ban_lan_inputchains_4="${ban_lan_inputchains_4:-"input_lan_rule"}"
- ban_lan_inputchains_6="${ban_lan_inputchains_6:-"input_lan_rule"}"
- ban_lan_forwardchains_4="${ban_lan_forwardchains_4:-"forwarding_lan_rule"}"
- ban_lan_forwardchains_6="${ban_lan_forwardchains_6:-"forwarding_lan_rule"}"
- ban_wan_inputchains_4="${ban_wan_inputchains_4:-"input_wan_rule"}"
- ban_wan_inputchains_6="${ban_wan_inputchains_6:-"input_wan_rule"}"
- ban_wan_forwardchains_4="${ban_wan_forwardchains_4:-"forwarding_wan_rule"}"
- ban_wan_forwardchains_6="${ban_wan_forwardchains_6:-"forwarding_wan_rule"}"
- ban_logchain_src="${ban_logchain_src:-"${ban_chain}_log_src"}"
- ban_logchain_dst="${ban_logchain_dst:-"${ban_chain}_log_dst"}"
- ban_logtarget_src="${ban_target_src}"
- ban_logtarget_dst="${ban_target_dst}"
- if [ "${ban_logsrc_enabled}" = "1" ]; then
- ban_logprefix_src="${ban_logprefix_src:-"[banIP-${ban_ver%-*}, src/${ban_target_src}] "}"
- ban_logopts_src="${ban_logopts_src:-"-m limit --limit 2/sec"}"
- ban_target_src="${ban_logchain_src}"
- fi
- if [ "${ban_logdst_enabled}" = "1" ]; then
- ban_logprefix_dst="${ban_logprefix_dst:-"[banIP-${ban_ver%-*}, dst/${ban_target_dst}] "}"
- ban_logopts_dst="${ban_logopts_dst:-"-m limit --limit 2/sec"}"
- ban_target_dst="${ban_logchain_dst}"
- fi
- ban_localsources="${ban_localsources:-"maclist whitelist blacklist"}"
- ban_logterms="${ban_logterms:-"dropbear sshd luci nginx"}"
- f_log "debug" "f_conf ::: ifaces: ${ban_ifaces:-"-"}, chain: ${ban_chain}, set_type: ${ban_global_settype}, log_chains (src/dst): ${ban_logchain_src}/${ban_logchain_dst}, targets (src/dst): ${ban_target_src}/${ban_target_dst}, whitelist_only: ${ban_whitelistonly}"
- f_log "debug" "f_conf ::: lan_inputs (4/6): ${ban_lan_inputchains_4}/${ban_lan_inputchains_6}, lan_forwards (4/6): ${ban_lan_forwardchains_4}/${ban_lan_forwardchains_6}, wan_inputs (4/6): ${ban_wan_inputchains_4}/${ban_wan_inputchains_6}, wan_forwards (4/6): ${ban_wan_forwardchains_4}/${ban_wan_forwardchains_6}"
- f_log "debug" "f_conf ::: local_sources: ${ban_localsources:-"-"}, extra_sources: ${ban_extrasources:-"-"}, log_terms: ${ban_logterms:-"-"}, log_prefixes (src/dst): ${ban_logprefix_src}/${ban_logprefix_dst}, log_options (src/dst): ${ban_logopts_src}/${ban_logopts_dst}"
-}
-
-# check environment
-#
-f_env() {
- local util utils packages iface insecure tmp cnt="0" cnt_max="10"
-
- ban_starttime="$(date "+%s")"
- f_jsnup "running"
- f_log "info" "start banIP processing (${ban_action})"
-
- f_tmp
-
- if [ "${ban_autodetect}" = "1" ] && [ -z "${ban_ifaces}" ]; then
- while [ "${cnt}" -le "${cnt_max}" ]; do
- network_find_wan iface
- if [ -n "${iface}" ] && ! printf "%s\n" "${ban_ifaces}" | grep -q "${iface}"; then
- ban_proto4_enabled="1"
- ban_ifaces="${ban_ifaces}${iface} "
- uci_set banip global ban_proto4_enabled "1"
- uci_add_list banip global ban_ifaces "${iface}"
- fi
- network_find_wan6 iface
- if [ -n "${iface}" ] && ! printf "%s\n" "${ban_ifaces}" | grep -q "${iface}"; then
- ban_proto6_enabled="1"
- ban_ifaces="${ban_ifaces}${iface} "
- uci_set banip global ban_proto6_enabled "1"
- uci_add_list banip global ban_ifaces "${iface}"
- fi
- if [ -z "${ban_ifaces}" ]; then
- if [ "${cnt}" -le "${cnt_max}" ]; then
- network_flush_cache
- cnt=$((cnt + 1))
- sleep 1
- else
- break
- fi
- else
- if [ -n "$(uci -q changes "banip")" ]; then
- uci_commit "banip"
- fi
- break
- fi
- done
- fi
-
- while [ "${cnt}" -le "${cnt_max}" ]; do
- for iface in ${ban_ifaces}; do
- network_get_device tmp "${iface}"
- if [ -n "${tmp}" ] && ! printf "%s\n" "${ban_devs}" | grep -q "${tmp}"; then
- ban_devs="${ban_devs} ${tmp}"
- else
- network_get_physdev tmp "${iface}"
- if [ -n "${tmp}" ] && ! printf "%s\n" "${ban_devs}" | grep -q "${tmp}"; then
- ban_devs="${ban_devs} ${tmp}"
- fi
- fi
- network_get_subnet tmp "${iface}"
- if [ -n "${tmp}" ] && ! printf "%s\n" "${ban_subnets}" | grep -q "${tmp}"; then
- ban_subnets="${ban_subnets} ${tmp}"
- fi
- network_get_subnet6 tmp "${iface}"
- if [ -n "${tmp}" ] && ! printf "%s\n" "${ban_subnets}" | grep -q "${tmp}"; then
- ban_subnets="${ban_subnets} ${tmp}"
- fi
- done
- if [ -z "${ban_devs}" ] || [ -z "${ban_subnets}" ]; then
- if [ "${cnt}" -le "${cnt_max}" ]; then
- network_flush_cache
- cnt=$((cnt + 1))
- sleep 1
- else
- break
- fi
- else
- break
- fi
- done
- ban_ipdevs="$("${ban_ip_cmd}" link show 2>/dev/null | awk 'BEGIN{FS="[@: ]"}/^[0-9:]/{if($3!="lo"){ORS=" ";print $3}}')"
-
- if [ -z "${ban_ifaces}" ] || [ -z "${ban_devs}" ] || [ -z "${ban_ipdevs}" ]; then
- f_log "err" "logical wan interface(s)/device(s) '${ban_ifaces:-"-"}/${ban_devs:-"-"}' not found, please check your configuration"
- elif [ -z "${ban_ipdevs}" ]; then
- f_log "err" "ip device(s) '${ban_ipdevs:-"-"}' not found, please check your configuration"
- fi
-
- if [ ! -x "${ban_ipset_cmd}" ]; then
- f_log "err" "ipset utility '${ban_ipset_cmd:-"-"}' not executable, please install package 'ipset'"
- fi
- if { [ "${ban_proto4_enabled}" = "1" ] && { [ ! -x "${ban_ipt4_cmd}" ] || [ ! -x "${ban_ipt4_savecmd}" ] || [ ! -x "${ban_ipt4_restorecmd}" ]; }; } ||
- { [ "${ban_proto6_enabled}" = "1" ] && { [ ! -x "${ban_ipt6_cmd}" ] || [ ! -x "${ban_ipt6_savecmd}" ] || [ ! -x "${ban_ipt6_restorecmd}" ]; }; }; then
- f_log "err" "iptables utilities '${ban_ipt4_cmd:-"-"}, ${ban_ipt4_savecmd:-"-"}, ${ban_ipt4_restorecmd:-"-"}/${ban_ipt6_cmd:-"-"}', ${ban_ipt6_savecmd:-"-"}, ${ban_ipt6_restorecmd:-"-"} not executable, please install the relevant iptables packages"
- fi
-
- if [ -z "${ban_fetchutil}" ]; then
- while [ -z "${packages}" ] && [ "${cnt}" -le "${cnt_max}" ]; do
- packages="$(opkg list-installed 2>/dev/null)"
- cnt=$((cnt + 1))
- sleep 1
- done
- if [ -z "${packages}" ]; then
- f_log "err" "local opkg package repository is not available, please set 'ban_fetchutil' manually"
- fi
-
- utils="aria2c curl wget uclient-fetch"
- for util in ${utils}; do
- if { [ "${util}" = "uclient-fetch" ] && printf "%s" "${packages}" | grep -q "^libustream-"; } ||
- { [ "${util}" = "wget" ] && printf "%s" "${packages}" | grep -q "^wget -"; } ||
- [ "${util}" = "curl" ] || [ "${util}" = "aria2c" ]; then
- if [ -x "$(command -v "${util}")" ]; then
- ban_fetchutil="${util}"
- uci_set banip global ban_fetchutil "${util}"
- uci_commit "banip"
- break
- fi
- fi
- done
- elif [ ! -x "$(command -v "${ban_fetchutil}")" ]; then
- unset ban_fetchutil
- fi
- case "${ban_fetchutil}" in
- "aria2c")
- if [ "${ban_fetchinsecure}" = "1" ]; then
- insecure="--check-certificate=false"
- fi
- ban_fetchparm="${ban_fetchparm:-"${insecure} --timeout=20 --allow-overwrite=true --auto-file-renaming=false --log-level=warn --dir=/ -o"}"
- ;;
- "curl")
- if [ "${ban_fetchinsecure}" = "1" ]; then
- insecure="--insecure"
- fi
- ban_fetchparm="${ban_fetchparm:-"${insecure} --connect-timeout 20 --silent --show-error --location -o"}"
- ;;
- "uclient-fetch")
- if [ "${ban_fetchinsecure}" = "1" ]; then
- insecure="--no-check-certificate"
- fi
- ban_fetchparm="${ban_fetchparm:-"${insecure} --timeout=20 -O"}"
- ;;
- "wget")
- if [ "${ban_fetchinsecure}" = "1" ]; then
- insecure="--no-check-certificate"
- fi
- ban_fetchparm="${ban_fetchparm:-"${insecure} --no-cache --no-cookies --max-redirect=0 --timeout=20 -O"}"
- ;;
- esac
- if [ -n "${ban_fetchutil}" ] && [ -n "${ban_fetchparm}" ]; then
- ban_fetchutil="$(command -v "${ban_fetchutil}")"
- else
- f_log "err" "download utility with SSL support not found, please install 'uclient-fetch' with a 'libustream-*' variant or another download utility like 'wget', 'curl' or 'aria2'"
- fi
-
- if [ ! -r "${ban_srcfile}" ]; then
- if [ -r "${ban_srcarc}" ]; then
- zcat "${ban_srcarc}" >"${ban_srcfile}"
- else
- f_log "err" "banIP source archive not found"
- fi
- fi
- if [ -r "${ban_srcfile}" ]; then
- json_init
- json_load_file "${ban_srcfile}"
- json_get_keys ban_allsources
- ban_allsources="${ban_allsources} maclist blacklist whitelist"
- else
- f_log "err" "banIP source file not found"
- fi
- f_log "debug" "f_env ::: auto_detect: ${ban_autodetect}, fetch_util: ${ban_fetchutil:-"-"}, fetch_parm: ${ban_fetchparm:-"-"}, src_file: ${ban_srcfile:-"-"}, log_terms: ${ban_logterms}, interfaces: ${ban_ifaces:-"-"}, devices: ${ban_devs:-"-"}, subnets: ${ban_subnets:-"-"}, ip_devices: ${ban_ipdevs:-"-"}, protocols (4/6): ${ban_proto4_enabled}/${ban_proto6_enabled}"
-}
-
-# create temporary files and directories
-#
-f_tmp() {
- f_dir "${ban_tmpbase}"
-
- ban_tmpdir="$(mktemp -p "${ban_tmpbase}" -d)"
- ban_tmpfile="$(mktemp -p "${ban_tmpdir}" -tu)"
-
- if [ ! -f "${ban_pidfile}" ] || [ ! -s "${ban_pidfile}" ]; then
- printf "%s" "${$}" >"${ban_pidfile}"
- fi
- f_log "debug" "f_tmp ::: tmp_base: ${ban_tmpbase:-"-"}, tmp_dir: ${ban_tmpdir:-"-"}, pid_file: ${ban_pidfile:-"-"}"
-}
-
-# remove temporary files and directories
-#
-f_rmtmp() {
- if [ -d "${ban_tmpdir}" ]; then
- rm -rf "${ban_tmpdir}"
- fi
- rm -f "${ban_srcfile}"
- : >"${ban_pidfile}"
- f_log "debug" "f_rmtmp ::: tmp_base: ${ban_tmpbase:-"-"}, tmp_dir: ${ban_tmpdir:-"-"}, pid_file: ${ban_pidfile:-"-"}"
-}
-
-# remove backup files
-#
-f_rmbckp() {
- if [ -d "${ban_backupdir}" ]; then
- rm -f "${ban_backupdir}/banIP."*".gz"
- fi
-}
-
-# status helper function
-#
-f_char() {
- local result input="${1}"
-
- if [ "${input}" = "1" ]; then
- result="✔"
- else
- result="✘"
- fi
- printf "%s" "${result}"
-}
-
-# apply iptables rules
-#
-f_iptrule() {
- local rc timeout="-w 5" action="${1}" chain="${2}" rule="${3}" pos="${4}"
-
- if [ "${ban_proto4_enabled}" = "1" ] && { [ "${src_name}" = "maclist" ] || [ "${src_name##*_}" = "4" ]; }; then
- rc="$(
- "${ban_ipt4_cmd}" "${timeout}" -C ${chain} ${rule} 2>/dev/null
- printf "%u" ${?}
- )"
- if { [ "${rc}" != "0" ] && { [ "${action}" = "-A" ] || [ "${action}" = "-I" ]; }; } ||
- { [ "${rc}" = "0" ] && [ "${action}" = "-D" ]; }; then
- "${ban_ipt4_cmd}" "${timeout}" "${action}" ${chain} ${pos} ${rule} 2>/dev/null
- rc="${?}"
- else
- rc=0
- fi
- fi
- if [ "${ban_proto6_enabled}" = "1" ] && { [ "${src_name}" = "maclist" ] || [ "${src_name##*_}" = "6" ]; }; then
- rc="$(
- "${ban_ipt6_cmd}" "${timeout}" -C ${chain} ${rule} 2>/dev/null
- printf "%u" ${?}
- )"
- if { [ "${rc}" != "0" ] && { [ "${action}" = "-A" ] || [ "${action}" = "-I" ]; }; } ||
- { [ "${rc}" = "0" ] && [ "${action}" = "-D" ]; }; then
- "${ban_ipt6_cmd}" "${timeout}" "${action}" ${chain} ${pos} ${rule} 2>/dev/null
- rc="${?}"
- else
- rc=0
- fi
- fi
- if [ -n "${rc}" ] && [ "${rc}" != "0" ]; then
- : >"${tmp_err}"
- f_log "info" "${src_name}: iptables action '${action:-"-"}' failed with '${chain}, ${pos:-"-"}, ${rule:-"-"}'"
- fi
-}
-
-# iptables controller
-#
-f_iptables() {
- local ipt_cmd chain chainsets dev pos timeout="-w 5" destroy="${1}"
-
- if [ "${ban_action}" != "refresh" ] && [ "${ban_action}" != "resume" ]; then
- for dev in ${ban_ipdevs}; do
- if [ "${src_name}" = "maclist" ]; then
- f_iptrule "-D" "${ban_chain}" "-o ${dev} -m set --match-set ${src_name} src -j RETURN"
- elif [ "${src_name%_*}" = "whitelist" ]; then
- f_iptrule "-D" "${ban_chain}" "-i ${dev} -m set ! --match-set ${src_name} src -j ${ban_logtarget_src}"
- f_iptrule "-D" "${ban_chain}" "-o ${dev} -m set ! --match-set ${src_name} dst -j ${ban_logtarget_dst}"
- f_iptrule "-D" "${ban_chain}" "-i ${dev} -m set ! --match-set ${src_name} src -j ${ban_logchain_src}"
- f_iptrule "-D" "${ban_chain}" "-o ${dev} -m set ! --match-set ${src_name} dst -j ${ban_logchain_dst}"
- f_iptrule "-D" "${ban_chain}" "-i ${dev} -m set --match-set ${src_name} src -j RETURN"
- f_iptrule "-D" "${ban_chain}" "-o ${dev} -m set --match-set ${src_name} dst -j RETURN"
- else
- f_iptrule "-D" "${ban_chain}" "-i ${dev} -m set --match-set ${src_name} src -j ${ban_logtarget_src}"
- f_iptrule "-D" "${ban_chain}" "-o ${dev} -m set --match-set ${src_name} dst -j ${ban_logtarget_dst}"
- f_iptrule "-D" "${ban_chain}" "-i ${dev} -m set --match-set ${src_name} src -j ${ban_logchain_src}"
- f_iptrule "-D" "${ban_chain}" "-o ${dev} -m set --match-set ${src_name} dst -j ${ban_logchain_dst}"
- fi
- done
- fi
- if [ -z "${destroy}" ] && { [ "${cnt}" -gt "0" ] || [ "${src_name%_*}" = "blacklist" ] || [ "${src_name%_*}" = "whitelist" ]; }; then
- if [ "${src_name##*_}" = "4" ]; then
- ipt_cmd="${ban_ipt4_cmd}"
- if [ ! -f "${ban_tmpfile}.${src_name##*_}.chains" ]; then
- : >"${ban_tmpfile}.${src_name##*_}.chains"
- chainsets="${ban_lan_inputchains_4} ${ban_wan_inputchains_4} ${ban_lan_forwardchains_4} ${ban_wan_forwardchains_4}"
- for chain in ${chainsets}; do
- f_iptrule "-I" "${chain}" "-j ${ban_chain}"
- done
- f_iptrule "-A" "${ban_chain}" "-p udp --dport 67:68 --sport 67:68 -j RETURN"
- f_iptrule "-A" "${ban_chain}" "-m conntrack ! --ctstate NEW -j RETURN"
- fi
- elif [ "${src_name##*_}" = "6" ]; then
- ipt_cmd="${ban_ipt6_cmd}"
- if [ ! -f "${ban_tmpfile}.${src_name##*_}.chains" ]; then
- : >"${ban_tmpfile}.${src_name##*_}.chains"
- chainsets="${ban_lan_inputchains_6} ${ban_wan_inputchains_6} ${ban_lan_forwardchains_6} ${ban_wan_forwardchains_6}"
- for chain in ${chainsets}; do
- f_iptrule "-I" "${chain}" "-j ${ban_chain}"
- done
- f_iptrule "-A" "${ban_chain}" "-p ipv6-icmp -s fe80::/10 -d fe80::/10 -j RETURN"
- f_iptrule "-A" "${ban_chain}" "-p udp -s fc00::/6 --sport 547 -d fc00::/6 --dport 546 -j RETURN"
- f_iptrule "-A" "${ban_chain}" "-m conntrack ! --ctstate NEW -j RETURN"
- fi
- fi
- if [ "${src_settype}" != "dst" ]; then
- for dev in ${ban_devs}; do
- if [ "${src_name}" = "maclist" ]; then
- f_iptrule "-I" "${ban_chain}" "-o ${dev} -m set --match-set ${src_name} src -j RETURN" "1"
- elif [ "${src_name%_*}" = "whitelist" ]; then
- pos="$(($("${ipt_cmd}" "${timeout}" -vnL "${ban_chain}" --line-numbers | grep -cF "RETURN") + 1))"
- if [ "${ban_whitelistonly}" = "1" ]; then
- f_iptrule "-I" "${ban_chain}" "-i ${dev} -m set ! --match-set ${src_name} src -j ${ban_target_src}" "${pos}"
- else
- f_iptrule "-I" "${ban_chain}" "-i ${dev} -m set --match-set ${src_name} src -j RETURN" "${pos}"
- fi
- else
- f_iptrule "${action:-"-A"}" "${ban_chain}" "-i ${dev} -m set --match-set ${src_name} src -j ${ban_target_src}"
- fi
- done
- fi
- if [ "${src_settype}" != "src" ]; then
- for dev in ${ban_devs}; do
- if [ "${src_name%_*}" = "whitelist" ]; then
- pos="$(($("${ipt_cmd}" "${timeout}" -vnL "${ban_chain}" --line-numbers | grep -cF "RETURN") + 1))"
- if [ "${ban_whitelistonly}" = "1" ]; then
- f_iptrule "-I" "${ban_chain}" "-o ${dev} -m set ! --match-set ${src_name} dst -j ${ban_target_dst}" "${pos}"
- else
- f_iptrule "-I" "${ban_chain}" "-o ${dev} -m set --match-set ${src_name} dst -j RETURN" "${pos}"
- fi
- elif [ "${src_name}" != "maclist" ]; then
- f_iptrule "${action:-"-A"}" "${ban_chain}" "-o ${dev} -m set --match-set ${src_name} dst -j ${ban_target_dst}"
- fi
- done
- fi
- else
- "${ban_ipset_cmd}" -q destroy "${src_name}"
- fi
-}
-
-# ipset controller
-#
-f_ipset() {
- local src src_list action rule ipt_cmd out_rc max="0" cnt="0" cnt_ip="0" cnt_cidr="0" cnt_mac="0" timeout="-w 5" mode="${1}" in_rc="4"
-
- case "${mode}" in
- "backup")
- gzip -cf "${tmp_load}" 2>/dev/null >"${ban_backupdir}/banIP.${src_name}.gz"
- out_rc="${?}"
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
- return "${out_rc}"
- ;;
- "restore")
- if [ -f "${ban_backupdir}/banIP.${src_name}.gz" ]; then
- zcat "${ban_backupdir}/banIP.${src_name}.gz" 2>/dev/null >"${tmp_load}"
- out_rc="${?}"
- else
- out_rc="${in_rc}"
- fi
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
- return "${out_rc}"
- ;;
- "remove")
- if [ -f "${ban_backupdir}/banIP.${src_name}.gz" ]; then
- rm -f "${ban_backupdir}/banIP.${src_name}.gz"
- out_rc="${?}"
- else
- out_rc="${in_rc}"
- fi
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
- return "${out_rc}"
- ;;
- "initial")
- for proto in "4" "6"; do
- if [ "${proto}" = "4" ] && [ "${ban_proto4_enabled}" = "1" ]; then
- ipt_cmd="${ban_ipt4_cmd}"
- chainsets="${ban_lan_inputchains_4} ${ban_lan_forwardchains_4} ${ban_wan_inputchains_4} ${ban_wan_forwardchains_4}"
- elif [ "${proto}" = "6" ] && [ "${ban_proto6_enabled}" = "1" ]; then
- ipt_cmd="${ban_ipt6_cmd}"
- chainsets="${ban_lan_inputchains_6} ${ban_lan_forwardchains_6} ${ban_wan_inputchains_6} ${ban_wan_forwardchains_6}"
- fi
-
- if { [ "${proto}" = "4" ] && [ "${ban_proto4_enabled}" = "1" ]; } ||
- { [ "${proto}" = "6" ] && [ "${ban_proto6_enabled}" = "1" ]; }; then
- if [ -z "$("${ipt_cmd}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]; then
- "${ipt_cmd}" "${timeout}" -N "${ban_chain}" 2>/dev/null
- out_rc="${?}"
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, chain: ${ban_chain:-"-"}, out_rc: ${out_rc}"
- else
- out_rc=0
- for chain in ${chainsets}; do
- f_iptrule "-D" "${chain}" "-j ${ban_chain}"
- done
- fi
-
- if [ "${ban_logsrc_enabled}" = "1" ] && [ "${out_rc}" = "0" ] && [ -z "$("${ipt_cmd}" "${timeout}" -nL "${ban_logchain_src}" 2>/dev/null)" ]; then
- "${ipt_cmd}" "${timeout}" -N "${ban_logchain_src}" 2>/dev/null
- out_rc="${?}"
- if [ "${out_rc}" = "0" ]; then
- "${ipt_cmd}" "${timeout}" -A "${ban_logchain_src}" -j LOG ${ban_logopts_src} --log-prefix "${ban_logprefix_src}"
- out_rc="${?}"
- if [ "${out_rc}" = "0" ]; then
- "${ipt_cmd}" "${timeout}" -A "${ban_logchain_src}" -j "${ban_logtarget_src}"
- out_rc="${?}"
- fi
- fi
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, logchain_src: ${ban_logchain_src:-"-"}, out_rc: ${out_rc}"
- fi
-
- if [ "${ban_logdst_enabled}" = "1" ] && [ "${out_rc}" = "0" ] && [ -z "$("${ipt_cmd}" "${timeout}" -nL "${ban_logchain_dst}" 2>/dev/null)" ]; then
- "${ipt_cmd}" "${timeout}" -N "${ban_logchain_dst}" 2>/dev/null
- out_rc="${?}"
- if [ "${out_rc}" = "0" ]; then
- "${ipt_cmd}" "${timeout}" -A "${ban_logchain_dst}" -j LOG ${ban_logopts_dst} --log-prefix "${ban_logprefix_dst}"
- out_rc="${?}"
- if [ "${out_rc}" = "0" ]; then
- "${ipt_cmd}" "${timeout}" -A "${ban_logchain_dst}" -j "${ban_logtarget_dst}"
- out_rc="${?}"
- fi
- fi
- f_log "debug" "f_ipset ::: name: initial, mode: ${mode:-"-"}, logchain_dst: ${ban_logchain_dst:-"-"}, out_rc: ${out_rc}"
- fi
- fi
- done
- out_rc="${out_rc:-"${in_rc}"}"
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
- return "${out_rc}"
- ;;
- "create")
- if [ -z "$("${ban_ipset_cmd}" -q -n list "${src_name}")" ] &&
- { [ -s "${tmp_file}" ] || [ "${src_name%_*}" = "whitelist" ] || [ "${src_name%_*}" = "blacklist" ]; }; then
- max="$(awk 'END{print NR}' "${tmp_file}" 2>/dev/null)"
- max=$((max + 262144))
- if [ "${src_name}" = "maclist" ]; then
- "${ban_ipset_cmd}" create "${src_name}" hash:mac hashsize 64 maxelem "${max}" counters timeout "${ban_maclist_timeout:-"0"}"
- out_rc="${?}"
- elif [ "${src_name%_*}" = "whitelist" ]; then
- "${ban_ipset_cmd}" create "${src_name}" hash:net hashsize 64 maxelem "${max}" family "${src_ipver}" counters timeout "${ban_whitelist_timeout:-"0"}"
- out_rc="${?}"
- elif [ "${src_name%_*}" = "blacklist" ]; then
- "${ban_ipset_cmd}" create "${src_name}" hash:net hashsize 64 maxelem "${max}" family "${src_ipver}" counters timeout "${ban_blacklist_timeout:-"0"}"
- out_rc="${?}"
- else
- "${ban_ipset_cmd}" create "${src_name}" hash:net hashsize 64 maxelem "${max}" family "${src_ipver}" counters
- out_rc="${?}"
- fi
- elif [ -n "$("${ban_ipset_cmd}" -q -n list "${src_name}")" ]; then
- "${ban_ipset_cmd}" -q flush "${src_name}"
- out_rc="${?}"
- fi
- if [ -s "${tmp_file}" ] && [ "${out_rc}" = "0" ]; then
- "${ban_ipset_cmd}" -q -! restore <"${tmp_file}"
- out_rc="${?}"
- if [ "${out_rc}" = "0" ]; then
- src_list="$("${ban_ipset_cmd}" -q list "${src_name}")"
- cnt="$(printf "%s\n" "${src_list}" | awk '/^Number of entries:/{print $4}')"
- cnt_mac="$(printf "%s\n" "${src_list}" | grep -cE "^(([0-9A-Z][0-9A-Z]:){5}[0-9A-Z]{2} )")"
- cnt_cidr="$(printf "%s\n" "${src_list}" | grep -cE "(/[0-9]{1,3} )")"
- cnt_ip=$((cnt - cnt_cidr - cnt_mac))
- printf "%s\n" "${cnt}" >"${tmp_cnt}"
- fi
- fi
- f_iptables
- end_ts="$(date +%s)"
- out_rc="${out_rc:-"${in_rc}"}"
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, ipver: ${src_ipver:-"-"}, settype: ${src_settype:-"-"}, count(sum/ip/cidr/mac): ${cnt}/${cnt_ip}/${cnt_cidr}/${cnt_mac}, time: $((end_ts - start_ts)), out_rc: ${out_rc}"
- return "${out_rc}"
- ;;
- "refresh")
- if [ -n "$("${ban_ipset_cmd}" -q -n list "${src_name}")" ]; then
- out_rc=0
- src_list="$("${ban_ipset_cmd}" -q list "${src_name}")"
- cnt="$(printf "%s\n" "${src_list}" | awk '/^Number of entries:/{print $4}')"
- cnt_mac="$(printf "%s\n" "${src_list}" | grep -cE "^(([0-9A-Z][0-9A-Z]:){5}[0-9A-Z]{2} )")"
- cnt_cidr="$(printf "%s\n" "${src_list}" | grep -cE "(/[0-9]{1,3} )")"
- cnt_ip=$((cnt - cnt_cidr - cnt_mac))
- printf "%s\n" "${cnt}" >"${tmp_cnt}"
- f_iptables
- fi
- end_ts="$(date +%s)"
- out_rc="${out_rc:-"${in_rc}"}"
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, count(sum/ip/cidr/mac): ${cnt}/${cnt_ip}/${cnt_cidr}/${cnt_mac}, time: $((end_ts - start_ts)), out_rc: ${out_rc}"
- return "${out_rc}"
- ;;
- "suspend")
- for src in ${ban_sources} ${ban_localsources}; do
- if [ "${src}" = "maclist" ] && [ -n "$("${ban_ipset_cmd}" -q -n list "${src}")" ]; then
- tmp_file="${ban_backupdir}/${src}.file"
- "${ban_ipset_cmd}" -q save "${src}" | tail -n +2 >"${tmp_file}"
- "${ban_ipset_cmd}" -q flush "${src}"
- else
- for proto in "4" "6"; do
- if [ -n "$("${ban_ipset_cmd}" -q -n list "${src}_${proto}")" ]; then
- tmp_file="${ban_backupdir}/${src}_${proto}.file"
- "${ban_ipset_cmd}" -q save "${src}_${proto}" | tail -n +2 >"${tmp_file}"
- "${ban_ipset_cmd}" -q flush "${src}_${proto}"
- fi
- done
- fi
- done
- f_log "debug" "f_ipset ::: name: ${src:-"-"}, mode: ${mode:-"-"}"
- ;;
- "resume")
- if [ -f "${ban_backupdir}/${src_name}.file" ]; then
- "${ban_ipset_cmd}" -q -! restore <"${ban_backupdir}/${src_name}.file"
- out_rc="${?}"
- if [ "${out_rc}" = "0" ]; then
- rm -f "${ban_backupdir}/${src_name}.file"
- src_list="$("${ban_ipset_cmd}" -q list "${src_name}")"
- cnt="$(printf "%s\n" "${src_list}" | awk '/^Number of entries:/{print $4}')"
- cnt_mac="$(printf "%s\n" "${src_list}" | grep -cE "^(([0-9A-Z][0-9A-Z]:){5}[0-9A-Z]{2} )")"
- cnt_cidr="$(printf "%s\n" "${src_list}" | grep -cE "(/[0-9]{1,3} )")"
- cnt_ip=$((cnt - cnt_cidr - cnt_mac))
- printf "%s\n" "${cnt}" >"${tmp_cnt}"
- fi
- f_iptables
- fi
- end_ts="$(date +%s)"
- out_rc="${out_rc:-"${in_rc}"}"
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, ipver: ${src_ipver:-"-"}, settype: ${src_settype:-"-"}, count(sum/ip/cidr/mac): ${cnt}/${cnt_ip}/${cnt_cidr}/${cnt_mac}, time: $((end_ts - start_ts)), out_rc: ${out_rc}"
- return "${out_rc}"
- ;;
- "flush")
- if [ -n "$("${ban_ipset_cmd}" -q -n list "${src_name}")" ]; then
- f_iptables "destroy"
- out_rc=0
- fi
- out_rc="${out_rc:-"${in_rc}"}"
- f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
- return "${out_rc}"
- ;;
- "destroy")
- for chain in ${ban_chain} ${ban_logchain_src} ${ban_logchain_dst}; do
- if [ -n "$("${ban_ipt4_cmd}" "${timeout}" -nL "${chain}" 2>/dev/null)" ]; then
- "${ban_ipt4_savecmd}" | grep -v -- "-j ${chain}" | "${ban_ipt4_restorecmd}"
- "${ban_ipt4_cmd}" "${timeout}" -F "${chain}" 2>/dev/null
- "${ban_ipt4_cmd}" "${timeout}" -X "${chain}" 2>/dev/null
- fi
- if [ -n "$("${ban_ipt6_cmd}" "${timeout}" -nL "${chain}" 2>/dev/null)" ]; then
- "${ban_ipt6_savecmd}" | grep -v -- "-j ${chain}" | "${ban_ipt6_restorecmd}"
- "${ban_ipt6_cmd}" "${timeout}" -F "${chain}" 2>/dev/null
- "${ban_ipt6_cmd}" "${timeout}" -X "${chain}" 2>/dev/null
- fi
- done
- for src in ${ban_sources} maclist blacklist whitelist; do
- if [ "${src}" = "maclist" ] && [ -n "$("${ban_ipset_cmd}" -q -n list "${src}")" ]; then
- "${ban_ipset_cmd}" -q destroy "${src}"
- else
- for proto in "4" "6"; do
- if [ -n "$("${ban_ipset_cmd}" -q -n list "${src}_${proto}")" ]; then
- "${ban_ipset_cmd}" -q destroy "${src}_${proto}"
- fi
- done
- 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}" = "1" ]; }; then
- if [ -x "${ban_logger_cmd}" ]; then
- "${ban_logger_cmd}" -p "${class}" -t "banIP-${ban_ver%-*}[${$}]" "${log_msg}"
- else
- printf "%s %s %s\n" "${class}" "banIP-${ban_ver%-*}[${$}]" "${log_msg}"
- fi
- if [ "${class}" = "err" ]; then
- f_jsnup "error"
- f_ipset "destroy"
- f_rmbckp
- f_rmtmp
- exit 1
- fi
- fi
-}
-
-# kill all relevant background processes
-#
-f_pidx() {
- local pids ppid="${1}"
-
- pids="$(pgrep -P "${ppid}" 2>/dev/null | awk '{ORS=" ";print $0}')"
- kill -HUP "${ppid}" "${pids}" 2>/dev/null
- : >"${ban_bgpidfile}"
-}
-
-# start log service to trace failed ssh/luci logins
-#
-f_bgsrv() {
- local bg_pid action="${1}"
-
- bg_pid="$(cat "${ban_bgpidfile}" 2>/dev/null)"
- if [ "${action}" = "start" ] && [ -x "${ban_logservice}" ] && [ "${ban_monitor_enabled}" = "1" ] && [ "${ban_whitelistonly}" = "0" ]; then
- if [ -n "${bg_pid}" ]; then
- f_pidx "${bg_pid}"
- fi
- if printf "%s\n" "${ban_logterms}" | grep -q "dropbear"; then
- ban_search="Exit before auth from|"
- fi
- if printf "%s\n" "${ban_logterms}" | grep -q "sshd"; then
- ban_search="${ban_search}error: maximum authentication attempts exceeded|sshd.*Connection closed by.*\[preauth\]|"
- fi
- if printf "%s\n" "${ban_logterms}" | grep -q "luci"; then
- ban_search="${ban_search}luci: failed login|"
- fi
- if printf "%s\n" "${ban_logterms}" | grep -q "nginx"; then
- ban_search="${ban_search}nginx(\[[0-9]+\])?:.*\[error\].*open().*client: [[:alnum:].:]+|"
- fi
- (
- "${ban_logservice}" "${ban_search%?}" &
- printf "%s" "${!}" >"${ban_bgpidfile}"
- )
- elif { [ "${action}" = "stop" ] || [ "${ban_monitor_enabled}" = "0" ]; } && [ -n "${bg_pid}" ]; then
- f_pidx "${bg_pid}"
- fi
- f_log "debug" "f_bgsrv ::: action: ${action:-"-"}, bg_pid (old/new): ${bg_pid}/$(cat "${ban_bgpidfile}" 2>/dev/null), monitor_enabled: ${ban_monitor_enabled:-"-"}, log_service: ${ban_logservice:-"-"}"
-}
-
-# download controller
-#
-f_down() {
- local src_name="${1}" proto="${2}" src_ipver="${3}" src_url="${4}" src_rule="${5}" src_comp="${6}"
- local ip start_ts end_ts src_settype src_log src_rc tmp_load tmp_file tmp_raw tmp_cnt tmp_err
-
- start_ts="$(date +%s)"
- if printf "%s\n" "${ban_settype_src}" | grep -q "${src_name}"; then
- src_settype="src"
- elif printf "%s\n" "${ban_settype_dst}" | grep -q "${src_name}"; then
- src_settype="dst"
- elif printf "%s\n" "${ban_settype_all}" | grep -q "${src_name}"; then
- src_settype="src+dst"
- else
- src_settype="${ban_global_settype}"
- fi
- src_name="${src_name}_${proto}"
- tmp_load="${ban_tmpfile}.${src_name}.load"
- tmp_file="${ban_tmpfile}.${src_name}.file"
- tmp_raw="${tmp_file}.raw"
- tmp_cnt="${tmp_file}.cnt"
- tmp_err="${tmp_file}.err"
-
- # 'resume' mode
- #
- if [ "${ban_action}" = "resume" ]; then
- if [ "${src_name%_*}" = "maclist" ]; then
- src_name="maclist"
- fi
- f_ipset "resume"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- return
- fi
- fi
-
- # handle local downloads
- #
- case "${src_name%_*}" in
- "blacklist" | "whitelist")
- printf "%s\n" "0" >"${tmp_cnt}"
- awk "${src_rule}" "${src_url}" >"${tmp_file}"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- f_ipset "create"
- if [ ! -f "${tmp_dns}" ] && { { [ "${proto}" = "4" ] && [ "${ban_proto4_enabled}" = "1" ]; } ||
- { [ "${proto}" = "6" ] && [ "${ban_proto6_enabled}" = "1" ] && [ "${ban_proto4_enabled}" = "0" ]; }; }; then
- tmp_dns="${ban_tmpbase}/${src_name%_*}.dns"
- src_rule="/^([[:alnum:]_-]{1,63}\\.)+[[:alpha:]]+([[:space:]]|$)/{print tolower(\$1)}"
- awk "${src_rule}" "${src_url}" >"${tmp_dns}"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ] && [ -s "${tmp_dns}" ]; then
- ("${ban_dnsservice}" "${src_name%_*}" "${tmp_dns}" &)
- else
- rm -f "${tmp_dns}"
- fi
- fi
- else
- f_log "debug" "f_down ::: name: ${src_name}, url: ${src_url}, rule: ${src_rule}, rc: ${src_rc}"
- fi
- return
- ;;
- "maclist")
- src_name="${src_name%_*}"
- tmp_file="${ban_tmpfile}.${src_name}.file"
- tmp_cnt="${tmp_file}.cnt"
- tmp_err="${tmp_file}.err"
- awk "${src_rule}" "${src_url}" >"${tmp_file}"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- f_ipset "create"
- else
- f_log "debug" "f_down ::: name: ${src_name}, url: ${src_url}, rule: ${src_rule}, rc: ${src_rc}"
- fi
- return
- ;;
- esac
-
- # 'refresh' mode
- #
- if [ "${ban_action}" = "refresh" ]; then
- f_ipset "refresh"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- return
- fi
- fi
-
- # 'start' mode
- #
- if [ "${ban_action}" = "start" ]; then
- f_ipset "restore"
- fi
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- awk "${src_rule}" "${tmp_load}" 2>/dev/null >"${tmp_file}"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- f_ipset "create"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- return
- fi
- fi
- fi
-
- # handle country related downloads
- #
- if [ "${src_name%_*}" = "country" ]; then
- for country in ${ban_countries}; do
- src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}${country}-aggregated.zone" 2>&1)"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- cat "${tmp_raw}" 2>/dev/null >>"${tmp_load}"
- else
- continue
- fi
- done
-
- # handle asn related downloads
- #
- elif [ "${src_name%_*}" = "asn" ]; then
- for asn in ${ban_asns}; do
- src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}AS${asn}" 2>&1)"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- cat "${tmp_raw}" 2>/dev/null >>"${tmp_load}"
- else
- continue
- fi
- done
-
- # handle compressed downloads
- #
- elif [ -n "${src_comp}" ]; then
- case "${src_comp}" in
- "gz")
- src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}" 2>&1)"
- src_rc="${?}"
- if [ "${src_rc}" -eq 0 ]; then
- zcat "${tmp_raw}" 2>/dev/null >"${tmp_load}"
- src_rc="${?}"
- fi
- ;;
- esac
-
- # handle normal downloads
- #
- else
- src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_load}" "${src_url}" 2>&1)"
- src_rc="${?}"
- fi
-
- # download post-processing
- #
- if [ "${src_rc}" = "0" ]; then
- f_ipset "backup"
- src_rc="${?}"
- elif [ "${ban_action}" != "start" ] && [ "${ban_action}" != "refresh" ]; then
- f_ipset "restore"
- src_rc="${?}"
- fi
- if [ "${src_rc}" = "0" ]; then
- awk "${src_rule}" "${tmp_load}" 2>/dev/null >"${tmp_file}"
- src_rc="${?}"
- if [ "${src_rc}" = "0" ]; then
- f_ipset "create"
- src_rc="${?}"
- elif [ "${ban_action}" != "refresh" ]; then
- f_ipset "refresh"
- src_rc="${?}"
- fi
- else
- src_log="$(printf "%s" "${src_log}" | awk '{ORS=" ";print $0}')"
- if [ "${ban_action}" != "refresh" ]; then
- f_ipset "refresh"
- src_rc="${?}"
- fi
- f_log "debug" "f_down ::: name: ${src_name}, url: ${src_url}, rule: ${src_rule}, rc: ${src_rc}, log: ${src_log:-"-"}"
- fi
-}
-
-# main controller
-#
-f_main() {
- local src_name src_url_4 src_rule_4 src_url_6 src_rule_6 src_comp src_rc src_ts log_raw log_merge log_ips log_count hold err_file cnt_file cnt=0
-
- # prepare logfile excerpts
- #
- if [ "${ban_autoblacklist}" = "1" ] || [ "${ban_monitor_enabled}" = "1" ]; then
- log_raw="$(${ban_logread_cmd} -l "${ban_loglimit}")"
- if printf "%s\n" "${ban_logterms}" | grep -q "dropbear"; then
- log_ips="$(printf "%s\n" "${log_raw}" | grep -E "Exit before auth from" |
- awk 'match($0,/<[0-9A-f:\.]+:/){printf "%s\n",substr($0,RSTART+1,RLENGTH-2)}' | awk '!seen[$NF]++' | awk '{ORS=" ";print $NF}')"
- for ip in ${log_ips}; do
- log_count="$(printf "%s\n" "${log_raw}" | grep -cE "Exit before auth from <${ip}")"
- if [ "${log_count}" -ge "${ban_ssh_logcount}" ]; then
- log_merge="${log_merge} ${ip}"
- fi
- done
- fi
- if printf "%s\n" "${ban_logterms}" | grep -q "sshd"; then
- log_ips="$(printf "%s\n" "${log_raw}" | grep -E "error: maximum authentication attempts exceeded|sshd.*Connection closed by.*\[preauth\]" |
- awk 'match($0,/[0-9A-f:\.]+ port/){printf "%s\n",substr($0,RSTART,RLENGTH-5)}' | awk '!seen[$NF]++' | awk '{ORS=" ";print $NF}')"
- for ip in ${log_ips}; do
- log_count="$(printf "%s\n" "${log_raw}" | grep -cE "error: maximum authentication attempts exceeded.*${ip}|sshd.*Connection closed by.*${ip}.*\[preauth\]")"
- if [ "${log_count}" -ge "${ban_ssh_logcount}" ]; then
- log_merge="${log_merge} ${ip}"
- fi
- done
- fi
- if printf "%s\n" "${ban_logterms}" | grep -q "luci"; then
- log_ips="$(printf "%s\n" "${log_raw}" | grep -E "luci: failed login on " |
- awk 'match($0,/[0-9A-f:\.]+$/){printf "%s\n",substr($0,RSTART,RLENGTH)}' | awk '!seen[$NF]++' | awk '{ORS=" ";print $NF}')"
- for ip in ${log_ips}; do
- log_count="$(printf "%s\n" "${log_raw}" | grep -cE "luci: failed login on .*from ${ip}")"
- if [ "${log_count}" -ge "${ban_luci_logcount}" ]; then
- log_merge="${log_merge} ${ip}"
- fi
- done
- fi
- if printf "%s\n" "${ban_logterms}" | grep -q "nginx"; then
- log_ips="$(printf "%s\n" "${log_raw}" | grep -oE "nginx(\[[0-9]+\])?:.*\[error\].*open\(\).*client: [[:alnum:].:]+" |
- awk '!seen[$NF]++' | awk '{ORS=" ";print $NF}')"
- for ip in ${log_ips}; do
- log_count="$(printf "%s\n" "${log_raw}" | grep -cE "nginx(\[[0-9]+\])?:.*\[error\].*open\(\).*client: ${ip}")"
- if [ "${log_count}" -ge "${ban_nginx_logcount}" ]; then
- log_merge="${log_merge} ${ip}"
- fi
- done
- fi
- fi
-
- # prepare new black- and whitelist entries
- #
- if [ "${ban_autowhitelist}" = "1" ] && [ -f "${ban_whitelist}" ]; then
- for ip in ${ban_subnets}; do
- if ! grep -q "${ip}" "${ban_whitelist}"; then
- src_ts="# added on $(date "+%d.%m.%Y %H:%M:%S")"
- printf "%-42s%s\n" "${ip}" "${src_ts}" >>"${ban_whitelist}"
- f_log "info" "IP address '${ip}' added to whitelist"
- fi
- done
- fi
- if [ "${ban_autoblacklist}" = "1" ] && [ -f "${ban_blacklist}" ]; then
- for ip in ${log_merge}; do
- if ! grep -q "${ip}" "${ban_blacklist}"; then
- src_ts="# added on $(date "+%d.%m.%Y %H:%M:%S")"
- printf "%-42s%s\n" "${ip}" "${src_ts}" >>"${ban_blacklist}"
- f_log "info" "IP address '${ip}' added to blacklist"
- fi
- done
- fi
-
- # initial ipset/iptables creation
- #
- if ! f_ipset "initial"; then
- f_log "err" "banIP processing failed, fatal error during ipset/iptables creation (${ban_sysver})"
- fi
-
- # load local source files (maclist, blacklist, whitelist)
- #
- for src_name in ${ban_localsources}; do
- if [ "${src_name}" = "maclist" ] && [ -s "${ban_maclist}" ]; then
- (
- src_rule_4="/^([0-9A-z][0-9A-z]:){5}[0-9A-z]{2}([[:space:]]|$)/{print \"add ${src_name} \"toupper(\$1)}"
- f_down "${src_name}" "mac" "mac" "${ban_maclist}" "${src_rule_4}"
- ) &
- fi
- if [ "${ban_proto4_enabled}" = "1" ]; then
- if [ "${src_name}" = "blacklist" ] && [ -s "${ban_blacklist}" ] && [ "${ban_whitelistonly}" = "0" ]; then
- (
- src_rule_4="/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add ${src_name}_4 \"\$1}"
- f_down "${src_name}" "4" "inet" "${ban_blacklist}" "${src_rule_4}"
- ) &
- elif [ "${src_name}" = "whitelist" ] && [ -s "${ban_whitelist}" ]; then
- (
- src_rule_4="/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add ${src_name}_4 \"\$1}"
- f_down "${src_name}" "4" "inet" "${ban_whitelist}" "${src_rule_4}"
- ) &
- fi
- else
- (
- src_name="${src_name}_4"
- f_ipset "flush"
- ) &
- fi
- if [ "${ban_proto6_enabled}" = "1" ]; then
- if [ "${src_name}" = "blacklist" ] && [ -s "${ban_blacklist}" ] && [ "${ban_whitelistonly}" = "0" ]; then
- (
- src_rule_6="/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add ${src_name}_6 \"\$1}"
- f_down "${src_name}" "6" "inet6" "${ban_blacklist}" "${src_rule_6}"
- ) &
- elif [ "${src_name}" = "whitelist" ] && [ -s "${ban_whitelist}" ]; then
- (
- src_rule_6="/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add ${src_name}_6 \"\$1}"
- f_down "${src_name}" "6" "inet6" "${ban_whitelist}" "${src_rule_6}"
- ) &
- fi
- else
- (
- src_name="${src_name}_6"
- f_ipset "flush"
- ) &
- fi
- done
- wait
-
- # loop over all external sources
- #
- if [ "${ban_whitelistonly}" = "0" ]; then
- for src_name in ${ban_sources}; do
- # get source data from JSON file
- #
- if ! json_select "${src_name}" >/dev/null 2>&1; then
- continue
- fi
- json_objects="url_4 rule_4 url_6 rule_6 comp"
- for object in ${json_objects}; do
- eval json_get_var src_${object} '${object}' >/dev/null 2>&1
- done
- json_select ..
-
- # handle external IPv4 source downloads in a subshell
- #
- if [ "${ban_proto4_enabled}" = "1" ] && [ -n "${src_url_4}" ] && [ -n "${src_rule_4}" ]; then
- (
- f_down "${src_name}" "4" "inet" "${src_url_4}" "${src_rule_4}" "${src_comp}"
- ) &
- fi
-
- # handle external IPv6 source downloads in a subshell
- #
- if [ "${ban_proto6_enabled}" = "1" ] && [ -n "${src_url_6}" ] && [ -n "${src_rule_6}" ]; then
- (
- f_down "${src_name}" "6" "inet6" "${src_url_6}" "${src_rule_6}" "${src_comp}"
- ) &
- fi
-
- # control/limit download queues
- #
- hold=$((cnt % ban_maxqueue))
- if [ "${hold}" = "0" ]; then
- wait
- fi
- cnt=$((cnt + 1))
- done
- wait
- fi
-
- # error out
- #
- for err_file in "${ban_tmpfile}."*".err"; do
- if [ -f "${err_file}" ]; then
- f_log "err" "banIP processing failed, fatal iptables errors during subshell processing (${ban_sysver})"
- fi
- done
-
- # finish processing
- #
- ban_sources=""
- 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))
- src_name="$(printf "%s" "${cnt_file}" | grep -Eo "[a-z0-9_]+.file.cnt")"
- src_name="${src_name%%.*}"
- if ! printf "%s" "${ban_sources}" | grep -q "${src_name%_*}"; then
- ban_sources="${ban_sources} ${src_name%_*}"
- ban_allsources="${ban_allsources//${src_name%_*}/}"
- fi
- fi
- done
- for src_name in ${ban_allsources}; do
- if [ "${src_name}" = "maclist" ]; then
- f_ipset "flush"
- else
- for proto in "4" "6"; do
- src_name="${src_name%_*}_${proto}"
- f_ipset "flush"
- if [ "${src_name%_*}" != "blacklist" ] && [ "${src_name%_*}" != "whitelist" ]; then
- f_ipset "remove"
- fi
- done
- fi
- done
- f_log "info" "${ban_setcnt} IPSets with overall ${ban_cnt} IPs/Prefixes loaded successfully (${ban_sysver})"
- f_jsnup
- f_rmtmp
- f_bgsrv "start"
-}
-
-# query ipsets for certain IP
-#
-f_query() {
- local src proto result query_start query_end query_timeout="30" match="0" search="${1}"
-
- if [ -z "${search}" ]; then
- printf "%s\n" "::: missing search term, please submit a single ip or mac address :::"
- else
- query_start="$(date "+%s")"
- printf "%s\n%s\n%s\n" ":::" "::: search '${search}' in banIP related IPSets" ":::"
-
- for src in ${ban_localsources} ${ban_sources} ${ban_extrasources}; do
- if [ "${src}" = "maclist" ] && [ -n "$("${ban_ipset_cmd}" -q -n list "${src}")" ]; then
- result="$(
- ipset -q test ${src} ${search} >/dev/null 2>&1
- printf "%u" "${?}"
- )"
- if [ "${result}" = "0" ]; then
- match="1"
- printf "%s\n" " - found in IPSet '${src}'"
- break
- fi
- else
- for proto in "4" "6"; do
- if [ -n "$("${ban_ipset_cmd}" -q -n list "${src}_${proto}")" ]; then
- result="$(
- ipset -q test ${src}_${proto} ${search} >/dev/null 2>&1
- printf "%u" "${?}"
- )"
- if [ "${result}" = "0" ]; then
- match="1"
- printf "%s\n" " - found in IPSet '${src}_${proto}'"
- fi
- fi
- done
- fi
- query_end="$(date "+%s")"
- if [ "$((query_end - query_start))" -gt "${query_timeout}" ]; then
- printf "%s\n\n" " - [...]"
- break
- fi
- done
- if [ "${match}" = "0" ]; then
- printf "%s\n\n" " - no match"
- fi
- fi
-}
-
-# generate statistics
-#
-f_report() {
- local report_json report_txt bg_pid content proto src src_list detaillist type jsnval jsnvals jsnval1 jsnval2 jsnval3 jsnval4 jsnval5 jsnval6 jsnval7
- local cnt cnt_mac cnt_cidr cnt_ip cnt_acc cnt_sum="0" cnt_set_sum="1" cnt_acc_sum="0" cnt_mac_sum="0" cnt_ip_sum="0" cnt_cidr_sum="0" cnt_set_sum="0" action="${1}"
-
- report_json="${ban_reportdir}/ban_report.json"
- report_txt="${ban_reportdir}/ban_mailreport.txt"
-
- # build json file
- #
- if [ "${action}" != "json" ] && { "${ban_ipt4_savecmd}" | grep -q " ${ban_chain} " || "${ban_ipt6_savecmd}" | grep -q " ${ban_chain} "; }; then
- : >"${report_json}"
- printf "%s\n" "{" >>"${report_json}"
- printf "%s\n" '"ipsets": {' >>"${report_json}"
- for src in ${ban_localsources} ${ban_sources} ${ban_extrasources}; do
- if printf "%s" "${ban_extrasources}" | grep -q "${src}"; then
- set_type="n/a"
- else
- if printf "%s\n" "${ban_settype_src}" | grep -q "${src}"; then
- set_type="src"
- elif printf "%s\n" "${ban_settype_dst}" | grep -q "${src}"; then
- set_type="dst"
- elif printf "%s\n" "${ban_settype_all}" | grep -q "${src}"; then
- set_type="src+dst"
- else
- set_type="${ban_global_settype}"
- fi
- fi
- if [ "${src}" = "maclist" ]; then
- src_list="$("${ban_ipset_cmd}" -q list "${src}")"
- if [ -n "${src_list}" ]; then
- cnt="$(printf "%s" "${src_list}" | awk '/^Number of entries:/{print $4}')"
- cnt_acc="$(printf "%s" "${src_list}" | grep -cE "packets [1-9]+")"
- cnt_acc_sum=$((cnt_acc_sum + cnt_acc))
- cnt_mac_sum="${cnt}"
- cnt_sum=$((cnt_sum + cnt))
- {
- if [ "${cnt_set_sum}" != "0" ]; then
- printf "%s\n" ","
- fi
- printf "\t%s\n" "\"${src}\": {"
- printf "\t\t%s\n" "\"type\": \"${set_type}\","
- printf "\t\t%s\n" "\"count\": \"${cnt}\","
- printf "\t\t%s\n" '"count_ip": "0",'
- printf "\t\t%s\n" '"count_cidr": "0",'
- printf "\t\t%s\n" "\"count_mac\": \"${cnt}\","
- printf "\t\t%s" "\"count_acc\": \"${cnt_acc}\""
- printf ",\n\t\t%s" '"member_acc": ['
- printf "%s" "${src_list}" | awk 'match($0,/ packets [1-9]+/){printf "%s %s\n",$1,substr($0,RSTART+9,RLENGTH-9)}' |
- awk 'BEGIN{i=0};{i=i+1;if(i==1){printf "{\n\t\t\t\"member\": \"%s\",\n\t\t\t\"packets\": \"%s\"\n\t\t}",$1,$2}
- else{printf ",\n\t\t{\n\t\t\t\"member\": \"%s\",\n\t\t\t\"packets\": \"%s\"\n\t\t}",$1,$2}}'
- printf "%s\n" "]"
- printf "\t%s" "}"
- } >>"${report_json}"
- cnt_set_sum=$((cnt_set_sum + 1))
- fi
- else
- for proto in "4" "6"; do
- src_list="$("${ban_ipset_cmd}" -q list "${src}_${proto}")"
- if [ -n "${src_list}" ]; then
- cnt="$(printf "%s\n" "${src_list}" | awk '/^Number of entries:/{print $4}')"
- cnt_cidr="$(printf "%s\n" "${src_list}" | grep -cE "/[0-9]{1,3} ")"
- cnt_ip=$((cnt - cnt_cidr - cnt_mac))
- cnt_acc="$(printf "%s\n" "${src_list}" | grep -cE "packets [1-9]+")"
- cnt_cidr_sum=$((cnt_cidr_sum + cnt_cidr))
- cnt_ip_sum=$((cnt_ip_sum + cnt_ip))
- cnt_acc_sum=$((cnt_acc_sum + cnt_acc))
- cnt_sum=$((cnt_sum + cnt))
- {
- if [ "${cnt_set_sum}" != "0" ]; then
- printf "%s\n" ","
- fi
- printf "\t%s\n" "\"${src}_${proto}\": {"
- printf "\t\t%s\n" "\"type\": \"${set_type}\","
- printf "\t\t%s\n" "\"count\": \"${cnt}\","
- printf "\t\t%s\n" "\"count_ip\": \"${cnt_ip}\","
- printf "\t\t%s\n" "\"count_cidr\": \"${cnt_cidr}\","
- printf "\t\t%s\n" '"count_mac": "0",'
- printf "\t\t%s" "\"count_acc\": \"${cnt_acc}\""
- printf ",\n\t\t%s" '"member_acc": ['
- printf "%s" "${src_list}" | awk 'match($0,/ packets [1-9]+/){printf "%s %s\n",$1,substr($0,RSTART+9,RLENGTH-9)}' |
- awk 'BEGIN{i=0};{i=i+1;if(i==1){printf "{\n\t\t\t\"member\": \"%s\",\n\t\t\t\"packets\": \"%s\"\n\t\t}",$1,$2}
- else{printf ",\n\t\t{\n\t\t\t\"member\": \"%s\",\n\t\t\t\"packets\": \"%s\"\n\t\t}",$1,$2}}'
- printf "%s\n" "]"
- printf "\t%s" "}"
- } >>"${report_json}"
- cnt_set_sum=$((cnt_set_sum + 1))
- fi
- done
- fi
- done
- {
- printf "\n%s" "}"
- printf ",\n%s\n" "\"timestamp\": \"$(date "+%d.%m.%Y %H:%M:%S")\","
- printf "%s\n" "\"cnt_set_sum\": \"${cnt_set_sum}\","
- printf "%s\n" "\"cnt_ip_sum\": \"${cnt_ip_sum}\","
- printf "%s\n" "\"cnt_cidr_sum\": \"${cnt_cidr_sum}\","
- printf "%s\n" "\"cnt_mac_sum\": \"${cnt_mac_sum}\","
- printf "%s\n" "\"cnt_sum\": \"${cnt_sum}\","
- printf "%s\n" "\"cnt_acc_sum\": \"${cnt_acc_sum}\""
- printf "%s\n" "}"
- } >>"${report_json}"
- fi
-
- # output preparation
- #
- if [ -s "${report_json}" ] && { [ "${action}" = "cli" ] || [ "${action}" = "mail" ]; }; then
- : >"${report_txt}"
- json_init
- if json_load_file "${report_json}" >/dev/null 2>&1; then
- json_get_var jsnval1 "timestamp" >/dev/null 2>&1
- json_get_var jsnval2 "cnt_set_sum" >/dev/null 2>&1
- json_get_var jsnval3 "cnt_sum" >/dev/null 2>&1
- json_get_var jsnval4 "cnt_ip_sum" >/dev/null 2>&1
- json_get_var jsnval5 "cnt_cidr_sum" >/dev/null 2>&1
- json_get_var jsnval6 "cnt_mac_sum" >/dev/null 2>&1
- json_get_var jsnval7 "cnt_acc_sum" >/dev/null 2>&1
- {
- printf "%s\n%s\n%s\n" ":::" "::: report on all banIP related IPSets" ":::"
- printf " + %s\n" "Report timestamp ::: ${jsnval1:-"-"}"
- printf " + %s\n" "Number of all IPSets ::: ${jsnval2:-"0"}"
- printf " + %s\n" "Number of all entries ::: ${jsnval3:-"0"}"
- printf " + %s\n" "Number of IP entries ::: ${jsnval4:-"0"}"
- printf " + %s\n" "Number of CIDR entries ::: ${jsnval5:-"0"}"
- printf " + %s\n" "Number of MAC entries ::: ${jsnval6:-"0"}"
- printf " + %s\n" "Number of accessed entries ::: ${jsnval7:-"0"}"
- } >>"${report_txt}"
-
- json_select "ipsets"
- json_get_keys ipsetlist
- if [ -n "${ipsetlist}" ]; then
- {
- printf "%s\n%s\n%s\n" ":::" "::: IPSet details" ":::"
- printf "%-25s%-12s%-11s%-10s%-10s%-10s%-10s%s\n" " Name" "Type" "Count" "Cnt_IP" "Cnt_CIDR" "Cnt_MAC" "Cnt_ACC" "Entry details (Entry/Count)"
- printf "%s\n" " --------------------------------------------------------------------------------------------------------------------"
- } >>"${report_txt}"
- fi
- for ipset in ${ipsetlist}; do
- set_info="${ipset}"
- acc_info=""
- json_select "${ipset}"
- json_get_keys detaillist
- for detail in ${detaillist}; do
- if [ "${detail}" != "member_acc" ]; then
- json_get_var jsnval "${detail}" >/dev/null 2>&1
- set_info="${set_info} ${jsnval}"
- elif [ "${detail}" = "member_acc" ]; then
- index=1
- json_select "${detail}"
- while json_get_type type "${index}" && [ "${type}" = "object" ]; do
- json_get_values jsnvals "${index}" >/dev/null 2>&1
- acc_info="${acc_info} ${jsnvals}"
- index=$((index + 1))
- done
- json_select ".."
- fi
- done
- {
- printf " %-21s%-12s%-11s%-10s%-10s%-10s%s\n" ${set_info}
- if [ -n "${acc_info}" ]; then
- printf " %-25s%s\n" ${acc_info}
- fi
- printf "%s\n" " --------------------------------------------------------------------------------------------------------------------"
- } >>"${report_txt}"
- json_select ".."
- done
- content="$(cat "${report_txt}" 2>/dev/null)"
- rm -f "${report_txt}"
- fi
- fi
-
- # report output
- #
- if [ "${action}" = "cli" ]; then
- printf "%s\n" "${content}"
- elif [ "${action}" = "json" ]; then
- cat "${ban_reportdir}/ban_report.json"
- elif [ "${action}" = "mail" ] && [ "${ban_mail_enabled}" = "1" ] && [ -x "${ban_mailservice}" ]; then
- ("${ban_mailservice}" "${content}" >/dev/null 2>&1) &
- bg_pid="${!}"
- fi
- f_log "debug" "f_report ::: action: ${action}, report_json: ${report_json}, report_txt: ${report_txt}, bg_pid: ${bg_pid:-"-"}"
-}
-
-# update runtime information
-#
-f_jsnup() {
- local memory entry runtime cnt_info status="${1:-"enabled"}"
-
- if [ "${status}" = "enabled" ] || [ "${status}" = "error" ]; then
- ban_endtime="$(date "+%s")"
- cnt_info="${ban_setcnt} IPSets with ${ban_cnt} IPs/Prefixes"
- memory="$(awk '/^MemTotal|^MemFree|^MemAvailable/{ORS="/"; print int($2/1000)}' "/proc/meminfo" 2>/dev/null | awk '{print substr($0,1,length($0)-1)}')"
- if [ "$(((ban_endtime - ban_starttime) / 60))" -lt "60" ]; then
- runtime="${ban_action}, $(((ban_endtime - ban_starttime) / 60))m $(((ban_endtime - ban_starttime) % 60))s, ${memory:-0}, $(date "+%d.%m.%Y %H:%M:%S")"
- else
- runtime="${ban_action}, n/a, ${memory:-0}, $(date "+%d.%m.%Y %H:%M:%S")"
- fi
- fi
-
- : >"${ban_rtfile}"
- json_init
- json_load_file "${ban_rtfile}" >/dev/null 2>&1
- json_add_string "status" "${status}"
- json_add_string "version" "${ban_ver}"
- json_add_string "ipset_info" "${cnt_info:-"-"}"
- json_add_array "active_sources"
- if [ "${status}" = "running" ] || [ "${status}" = "error" ]; then
- json_add_object
- json_add_string "source" "-"
- json_close_object
- else
- for entry in ${ban_sources}; do
- json_add_object
- json_add_string "source" "${entry}"
- json_close_object
- done
- fi
- json_close_array
- json_add_array "active_devs"
- for entry in ${ban_devs}; do
- json_add_object
- json_add_string "dev" "${entry}"
- json_close_object
- done
- json_close_array
- json_add_array "active_ifaces"
- for entry in ${ban_ifaces}; do
- json_add_object
- json_add_string "iface" "${entry}"
- json_close_object
- done
- json_close_array
- json_add_array "active_logterms"
- for entry in ${ban_logterms}; do
- json_add_object
- json_add_string "term" "${entry}"
- json_close_object
- done
- json_close_array
- json_add_array "active_subnets"
- for entry in ${ban_subnets}; do
- json_add_object
- json_add_string "subnet" "${entry}"
- json_close_object
- done
- json_close_array
- json_add_string "run_infos" "settype: ${ban_global_settype}, backup_dir: ${ban_backupdir}, report_dir: ${ban_reportdir}"
- json_add_string "run_flags" "protocols (4/6): $(f_char ${ban_proto4_enabled})/$(f_char ${ban_proto6_enabled}), log (src/dst): $(f_char ${ban_logsrc_enabled})/$(f_char ${ban_logdst_enabled}), monitor: $(f_char ${ban_monitor_enabled}), mail: $(f_char ${ban_mail_enabled}), whitelist only: $(f_char ${ban_whitelistonly})"
- json_add_string "last_run" "${runtime:-"-"}"
- json_add_string "system" "${ban_sysver}"
- json_dump >"${ban_rtfile}"
-
- if [ "${ban_mail_enabled}" = "1" ] && [ -x "${ban_mailservice}" ] && { [ "${status}" = "error" ] ||
- { [ "${status}" = "enabled" ] && { [ -z "${ban_mailactions}" ] || printf "%s\n" "${ban_mailactions}" | grep -q "${ban_action}"; }; }; }; then
- ("${ban_mailservice}" "${ban_ver}" >/dev/null 2>&1) &
- bg_pid="${!}"
- fi
- f_log "debug" "f_jsnup ::: status: ${status:-"-"}, action: ${ban_action}, mail_enabled: ${ban_mail_enabled}, mail_actions: ${ban_mailactions}, mail_service: ${ban_mailservice}, mail_pid: ${bg_pid:-"-"}"
-}
-
-# 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
-
-if [ "${ban_action}" = "suspend" ] || [ "${ban_action}" = "resume" ] ||
- [ "${ban_action}" = "report" ] || [ "${ban_action}" = "query" ]; then
- json_init
- json_load_file "${ban_rtfile}" >/dev/null 2>&1
- json_get_var ban_status "status"
-fi
-
-# handle different banIP actions
-#
-f_load
-case "${ban_action}" in
- "stop")
- f_bgsrv "stop"
- f_ipset "destroy"
- f_jsnup "stopped"
- f_rmbckp
- ;;
- "restart")
- f_ipset "destroy"
- f_rmbckp
- f_env
- f_main
- ;;
- "suspend")
- if [ "${ban_status}" = "enabled" ] && [ "${ban_whitelistonly}" = "0" ]; then
- f_bgsrv "stop"
- f_jsnup "running"
- f_ipset "suspend"
- f_jsnup "paused"
- fi
- f_rmtmp
- ;;
- "resume")
- if [ "${ban_status}" = "paused" ] && [ "${ban_whitelistonly}" = "0" ]; then
- f_env
- f_main
- else
- f_rmtmp
- fi
- ;;
- "query")
- if [ "${ban_status}" = "enabled" ]; then
- f_query "${2}"
- fi
- ;;
- "report")
- if [ "${ban_status}" = "enabled" ] || [ "${2}" = "json" ]; then
- f_report "${2}"
- fi
- ;;
- "start" | "reload" | "refresh")
- f_env
- f_main
- ;;
-esac
+++ /dev/null
-{
- "asn": {
- "url_4": "https://asn.ipinfo.app/api/text/list/",
- "url_6": "https://asn.ipinfo.app/api/text/list/",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add asn_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add asn_6 \"$1}",
- "focus": "ASN blocks",
- "descurl": "https://asn.ipinfo.app"
- },
- "bogon": {
- "url_4": "https://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt",
- "url_6": "https://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add bogon_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add bogon_6 \"$1}",
- "focus": "Bogon prefixes",
- "descurl": "https://team-cymru.com"
- },
- "country": {
- "url_4": "http://www.ipdeny.com/ipblocks/data/aggregated/",
- "url_6": "http://www.ipdeny.com/ipv6/ipaddresses/aggregated/",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add country_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add country_6 \"$1}",
- "focus": "Country blocks",
- "descurl": "http://www.ipdeny.com/ipblocks"
- },
- "darklist": {
- "url_4": "https://darklist.de/raw.php",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add darklist_4 \"$1}",
- "focus": "Blocks suspicious attacker IPs",
- "descurl": "https://darklist.de"
- },
- "debl": {
- "url_4": "https://www.blocklist.de/downloads/export-ips_all.txt",
- "url_6": "https://www.blocklist.de/downloads/export-ips_all.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add debl_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add debl_6 \"$1}",
- "focus": "Fail2ban IP blacklist",
- "descurl": "https://www.blocklist.de"
- },
- "doh": {
- "url_4": "https://raw.githubusercontent.com/dibdot/DoH-IP-blocklists/master/doh-ipv4.txt",
- "url_6": "https://raw.githubusercontent.com/dibdot/DoH-IP-blocklists/master/doh-ipv6.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add doh_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add doh_6 \"$1}",
- "focus": "Public DoH-Provider",
- "descurl": "https://github.com/dibdot/DoH-IP-blocklists"
- },
- "drop": {
- "url_4": "https://www.spamhaus.org/drop/drop.txt",
- "url_6": "https://www.spamhaus.org/drop/dropv6.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add drop_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add drop_6 \"$1}",
- "focus": "Spamhaus drop compilation",
- "descurl": "https://www.spamhaus.org"
- },
- "dshield": {
- "url_4": "https://feeds.dshield.org/block.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add dshield_4 \"$1 \"/\"$3}",
- "focus": "Dshield IP blocklist",
- "descurl": "https://www.dshield.org"
- },
- "edrop": {
- "url_4": "https://www.spamhaus.org/drop/edrop.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add edrop_4 \"$1}",
- "focus": "Spamhaus edrop compilation",
- "descurl": "https://www.spamhaus.org"
- },
- "feodo": {
- "url_4": "https://feodotracker.abuse.ch/downloads/ipblocklist.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add feodo_4 \"$1}",
- "focus": "Feodo Tracker",
- "descurl": "https://feodotracker.abuse.ch"
- },
- "firehol1": {
- "url_4": "https://iplists.firehol.org/files/firehol_level1.netset",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add firehol1_4 \"$1}",
- "focus": "Firehol Level 1 compilation",
- "descurl": "https://iplists.firehol.org/?ipset=firehol_level1"
- },
- "firehol2": {
- "url_4": "https://iplists.firehol.org/files/firehol_level2.netset",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add firehol2_4 \"$1}",
- "focus": "Firehol Level 2 compilation",
- "descurl": "https://iplists.firehol.org/?ipset=firehol_level2"
- },
- "firehol3": {
- "url_4": "https://iplists.firehol.org/files/firehol_level3.netset",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add firehol3_4 \"$1}",
- "focus": "Firehol Level 3 compilation",
- "descurl": "https://iplists.firehol.org/?ipset=firehol_level3"
- },
- "firehol4": {
- "url_4": "https://iplists.firehol.org/files/firehol_level4.netset",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add firehol4_4 \"$1}",
- "focus": "Firehol Level 4 compilation",
- "descurl": "https://iplists.firehol.org/?ipset=firehol_level4"
- },
- "greensnow": {
- "url_4": "https://blocklist.greensnow.co/greensnow.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add greensnow_4 \"$1}",
- "focus": "Blocks suspicious server IPs",
- "descurl": "https://greensnow.co"
- },
- "iblockads": {
- "url_4": "https://list.iblocklist.com/?list=dgxtneitpuvgqqcpfulq&fileformat=cidr&archiveformat=gz",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add iblockads_4 \"$1}",
- "focus": "Advertising blocklist",
- "descurl": "https://www.iblocklist.com",
- "comp": "gz"
- },
- "iblockspy": {
- "url_4": "https://list.iblocklist.com/?list=llvtlsjyoyiczbkjsxpf&fileformat=cidr&archiveformat=gz",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add iblockspy_4 \"$1}",
- "focus": "Malicious spyware blocklist",
- "descurl": "https://www.iblocklist.com",
- "comp": "gz"
- },
- "myip": {
- "url_4": "https://myip.ms/files/blacklist/general/latest_blacklist.txt",
- "url_6": "https://myip.ms/files/blacklist/general/latest_blacklist.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add myip_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add myip_6 \"$1}",
- "focus": "Myip Live IP blacklist",
- "descurl": "https://myip.ms"
- },
- "nixspam": {
- "url_4": "http://www.dnsbl.manitu.net/download/nixspam-ip.dump.gz",
- "rule_4": "/(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add nixspam_4 \"$2}",
- "focus": "iX spam protection",
- "descurl": "http://www.nixspam.org",
- "comp": "gz"
- },
- "proxy": {
- "url_4": "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/proxylists.ipset",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add proxy_4 \"$1}",
- "focus": "Firehol list of open proxies",
- "descurl": "https://iplists.firehol.org/?ipset=proxylists"
- },
- "sslbl": {
- "url_4": "https://sslbl.abuse.ch/blacklist/sslipblacklist.csv",
- "rule_4": "BEGIN{FS=\",\"}/(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)/{print \"add sslbl_4 \"$2}",
- "focus": "SSL botnet IP blacklist",
- "descurl": "https://sslbl.abuse.ch"
- },
- "talos": {
- "url_4": "https://www.talosintelligence.com/documents/ip-blacklist",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add talos_4 \"$1}",
- "focus": "Cisco Talos IP Blacklist",
- "descurl": "https://talosintelligence.com/reputation_center"
- },
- "threat": {
- "url_4": "https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add threat_4 \"$1}",
- "focus": "Emerging Threats",
- "descurl": "https://rules.emergingthreats.net"
- },
- "tor": {
- "url_4": "https://lists.fissionrelays.net/tor/exits-ipv4.txt",
- "url_6": "https://lists.fissionrelays.net/tor/exits-ipv6.txt",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add tor_4 \"$1}",
- "rule_6": "/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add tor_6 \"$1}",
- "focus": "Tor exit nodes",
- "descurl": "https://fissionrelays.net/lists"
- },
- "uceprotect1": {
- "url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/dnsbl-1.uceprotect.net.gz",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{print \"add uceprotect1_4 \"$1}",
- "focus": "Spam protection level 1",
- "descurl": "http://www.uceprotect.net/en/index.php",
- "comp": "gz"
- },
- "uceprotect2": {
- "url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/dnsbl-2.uceprotect.net.gz",
- "rule_4": "BEGIN{IGNORECASE=1}/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]+NET[[:space:]]+)/{print \"add uceprotect2_4 \"$1}",
- "focus": "Spam protection level 2",
- "descurl": "http://www.uceprotect.net/en/index.php",
- "comp": "gz"
- },
- "voip": {
- "url_4": "http://www.voipbl.org/update/",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add voip_4 \"$1}",
- "focus": "VoIP fraud blocklist",
- "descurl": "http://www.voipbl.org"
- },
- "yoyo": {
- "url_4": "https://pgl.yoyo.org/adservers/iplist.php?ipformat=plain&showintro=0&mimetype=plaintext",
- "rule_4": "/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add yoyo_4 \"$1}",
- "focus": "Ad protection blacklist",
- "descurl": "https://pgl.yoyo.org/adservers/"
- }
-}
--- /dev/null
+# banIP mail template/include
+# Copyright (c) 2020-2023 Dirk Brenken (dev@brenken.org)
+# This is free software, licensed under the GNU General Public License v3.
+
+# info preparation
+#
+local banip_info report_info log_info system_info mail_text
+
+banip_info="$(/etc/init.d/banip status 2>/dev/null)"
+report_info="$(cat ${ban_reportdir}/ban_report.txt 2>/dev/null)"
+log_info="$("${ban_logreadcmd}" -l 100 -e "banIP_" 2>/dev/null | awk '{NR=1;max=120;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max)}else{print substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')"
+system_info="$(
+ strings /etc/banner 2>/dev/null
+ ubus call system board | awk 'BEGIN{FS="[{}\"]"}{if($2=="kernel"||$2=="hostname"||$2=="system"||$2=="model"||$2=="description")printf " + %-12s: %s\n",$2,$4}'
+)"
+
+# mail body
+#
+mail_text="$(printf "%s\n" "<html><body><pre style='display:block;font-family:monospace;font-size:1rem;padding:20;background-color:#f3eee5;white-space:pre'>")"
+mail_text="$(printf "%s\n" "${mail_text}\n<strong>++\n++ System Information ++\n++</strong>\n${system_info:-"-"}")"
+mail_text="$(printf "%s\n" "${mail_text}\n\n<strong>++\n++ banIP Status ++\n++</strong>\n${banip_info:-"-"}")"
+mail_text="$(printf "%s\n" "${mail_text}\n\n<strong>++\n++ banIP Report ++\n++</strong>\n${report_info:-"-"}")"
+mail_text="$(printf "%s\n" "${mail_text}\n\n<strong>++\n++ Logfile Information ++\n++</strong>\n${log_info}")"
+mail_text="$(printf "%s\n" "${mail_text}</pre></body></html>")"