banip: release 1.8.0-1

* hardened the uci config parsing
* added a fast, flexible & secure IPv4/IPv6 validator function, it eliminates > 99 % of garbage inputs
  Please note: The ‘rule’ in the feed file now only contains parameters for the IP validator;
  details can be found in the readme file. Old custom feed files are not compatible and will be
  backed up/removed via the uci-defaults script
* added BCP38 support: to block packets with spoofed source IP addresses in all supported chains
* optimized the log monitor plus performance improvements
* removed the pallebone feed (discontinued)
* added the ipexdbl feed
* various small improvements
* LuCI: add the BC38 option under Table/Chain Settings
* LuCI: updating the custom feed editor
* LuCI: small usability improvements
* readme update

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken
2026-01-12 22:59:19 +01:00
parent 9aaf2ffb96
commit 396c65e670
9 changed files with 470 additions and 305 deletions

View File

@@ -1,11 +1,11 @@
# banIP - ban incoming and outgoing IPs via named nftables Sets
# Copyright (c) 2018-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2018-2026 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:=1.6.0
PKG_VERSION:=1.8.0
PKG_RELEASE:=1
PKG_LICENSE:=GPL-3.0-or-later
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (c) 2015-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2015-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions
@@ -33,4 +33,10 @@ for option in ${old_options}; do
uci -q delete "${config}.global.${option}"
done
[ -n "$(uci -q changes "${config}")" ] && uci -q commit "${config}"
custom_feed="/etc/banip/banip.custom.feeds"
if grep -q '"rule_4"' "${custom_feed}"; then
mv -f "${custom_feed}" "${custom_feed}.backup.$(date "+%Y%m%d%H%M%S")"
: > "${custom_feed}"
fi
exit 0

View File

@@ -39,11 +39,11 @@ IP address blocking is commonly used to protect against brute force attacks, pre
| greensnow | suspicious server IPs | x | | | [Link](https://greensnow.co) |
| hagezi | Threat IP blocklist | | x | tcp, udp: 80, 443 | [Link](https://github.com/hagezi/dns-blocklists) |
| ipblackhole | blackhole IPs | x | | | [Link](https://github.com/BlackHoleMonster/IP-BlackHole) |
| ipexdbl | IPEX dynamic blocklists | x | | | [Link](https://github.com/ZEROF/ipextractor) |
| ipsum | malicious IPs | x | | | [Link](https://github.com/stamparm/ipsum) |
| ipthreat | hacker and botnet TPs | x | | | [Link](https://ipthreat.net) |
| myip | real-time IP blocklist | x | | | [Link](https://myip.ms) |
| nixspam | iX spam protection | x | | | [Link](http://www.nixspam.org) |
| pallebone | curated IP blocklist | x | | | [Link](https://github.com/pallebone/StrictBlockPAllebone) |
| proxy | open proxies | x | | | [Link](https://iplists.firehol.org/?ipset=proxylists) |
| threat | emerging threats | x | | | [Link](https://rules.emergingthreats.net) |
| threatview | malicious IPs | x | | | [Link](https://threatview.io) |
@@ -82,6 +82,7 @@ IP address blocking is commonly used to protect against brute force attacks, pre
* Supports external allowlist URLs to reference additional IPv4/IPv6 feeds
* Optionally always allow certain protocols/destination ports in the inbound chain
* Deduplicate IPs accross all Sets (single IPs only, no intervals)
* Implements BCP38 ingress filtering to prevent IP address spoofing
* Provides comprehensive runtime information
* Provides a detailed Set report, incl. a map that shows the geolocation of your own uplink addresses (in green) and the location of potential attackers (in red)
* Provides a Set search engine for certain IPs
@@ -108,7 +109,7 @@ IP address blocking is commonly used to protect against brute force attacks, pre
<a id="installation-and-usage"></a>
## Installation and Usage
* Update your local opkg/apk repository
* Update your routers apk repository (apk Update)
* Install the LuCI companion package 'luci-app-banip' which also installs the main 'banip' package as a dependency
* Enable the banIP system service (System -> Startup) and enable banIP itself (banIP -> General Settings)
* 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
@@ -191,6 +192,7 @@ Available commands:
| ban_nftexpiry | option | - | expiry time for auto added blocklist members, e.g. '5m', '2h' or '1d' |
| ban_nftretry | option | 5 | number of Set load attempts in case of an error |
| ban_nftcount | option | 0 | enable nft counter for every Set element |
| ban_bcp38 | option | 0 | block packets with spoofed source IP addresses in all supported chains |
| ban_map | option | 0 | enable a GeoIP Map with suspicious Set elements |
| 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' |
@@ -227,13 +229,14 @@ Available commands:
:::
::: banIP Set Statistics
:::
Timestamp: 2025-06-08 23:24:54
Timestamp: 2026-01-12 19:33:11
------------------------------
blocked syn-flood packets : 0
blocked udp-flood packets : 0
blocked icmp-flood packets : 0
blocked invalid ct packets : 133
blocked udp-flood packets : 10
blocked icmp-flood packets : 11480
blocked invalid ct packets : 1653
blocked invalid tcp packets: 0
blocked bcp38 packets : 0
---
auto-added IPs to allowlist: 0
auto-added IPs to blocklist: 0
@@ -241,118 +244,41 @@ Available commands:
Set | Count | Inbound (packets) | Outbound (packets) | Port/Protocol | Elements (max. 50)
---------------------+--------------+-----------------------+-----------------------+-----------------------+------------------------
allowlist.v4 | 1 | ON: 0 | ON: 0 | - |
allowlist.v4MAC | 1 | - | ON: 177 | - | 65:34:31:1f:a5:b1
allowlist.v4MAC | 0 | - | ON: 0 | - |
allowlist.v6 | 1 | ON: 0 | ON: 0 | - |
allowlist.v6MAC | 1 | - | ON: 264 | - | 65:34:31:1f:a5:b1
blocklist.v4 | 2 | ON: 0 | ON: 0 | - |
allowlist.v6MAC | 0 | - | ON: 0 | - |
blocklist.v4 | 7 | ON: 358 | ON: 812 | - | 5.187.35.0, 20.160.0.0,
| | | | | 45.135.232.0, 91.202.233
| | | | | .0
blocklist.v4MAC | 0 | - | ON: 0 | - |
blocklist.v6 | 0 | ON: 0 | ON: 0 | - |
blocklist.v6 | 0 | ON: 4 | ON: 0 | - |
blocklist.v6MAC | 0 | - | ON: 0 | - |
cinsscore.v4 | 11498 | ON: 444 | - | - | 3.92.139.143, 5.39.61.11
| | | | | 8, 8.137.54.171, 8.211.4
| | | | | 7.67, 8.219.147.10, 8.21
| | | | | 9.159.103, 8.219.206.212
| | | | | , 8.221.142.130, 8.222.1
| | | | | 60.62, 8.222.187.153, 18
| | | | | .212.38.183, 20.14.75.2,
| | | | | 20.15.164.37, 20.15.200
| | | | | .1, 20.46.231.114, 20.64
| | | | | .106.91, 20.65.193.0, 20
| | | | | .65.194.143, 20.80.83.86
| | | | | , 20.98.164.46, 20.118.3
| | | | | 2.59, 20.118.217.162, 20
| | | | | .118.217.181, 20.163.76.
| | | | | 6, 20.168.7.168, 20.168.
| | | | | 122.52, 20.168.122.88, 3
| | | | | 1.14.32.4, 34.147.75.236
| | | | | , 34.207.164.186, 35.203
| | | | | .210.7, 35.203.210.43, 3
| | | | | 5.203.210.90, 35.203.210
| | | | | .128, 35.203.210.141, 35
| | | | | .203.210.196, 35.203.210
| | | | | .213, 35.203.210.243, 35
| | | | | .203.211.3, 35.203.211.3
| | | | | 4, 35.203.211.76, 35.203
| | | | | .211.123, 35.203.211.156
| | | | | , 35.203.211.162, 35.203
| | | | | .211.175, 35.203.211.206
| | | | | , 35.203.211.242, 40.90.
| | | | | 235.65, 40.124.173.90, 4
| | | | | 2.112.20.235
country.v4 | 36432 | ON: 221 | - | - | 15.236.0.0, 24.56.0.0, 2
| | | | | 7.34.232.0, 27.148.0.0,
| | | | | 32.0.0.0, 36.96.0.0, 37.
| | | | | 254.0.0, 42.63.0.0, 43.1
| | | | | 76.0.0, 45.150.236.0, 46
| | | | | .100.0.0, 47.56.0.0, 51.
| | | | | 254.0.0, 57.101.0.0, 58.
| | | | | 192.0.0, 59.88.0.0, 59.1
| | | | | 72.0.0, 64.59.224.0, 64.
| | | | | 226.64.0, 68.183.0.0, 71
| | | | | .20.0.0, 83.239.0.0, 84.
| | | | | 22.128.0, 87.103.128.0,
| | | | | 91.196.148.0, 94.253.0.0
| | | | | , 95.144.0.0, 100.0.0.0,
| | | | | 103.141.110.0, 103.203.
| | | | | 56.0, 104.248.0.0, 110.5
| | | | | .128.0, 113.62.0.0, 116.
| | | | | 95.0.0, 117.122.0.0, 118
| | | | | .139.192.0, 119.161.120.
| | | | | 0, 120.52.0.0, 123.4.0.0
| | | | | , 125.64.0.0, 129.79.0.0
| | | | | , 129.144.0.0, 134.209.0
| | | | | .0, 138.67.0.0, 147.182.
| | | | | 0.0, 147.185.108.0, 150.
| | | | | 107.176.0, 152.32.128.0,
| | | | | 157.245.0.0, 159.59.0.0
country.v6 | 23665 | ON: 0 | - | - |
debl.v4 | 13147 | ON: 19 | - | - | 54.37.81.238, 57.129.64.
| | | | | 237, 78.153.140.224, 87.
| | | | | 255.194.135, 91.196.152.
| | | | | 3, 93.123.109.230, 111.6
| | | | | 7.199.209, 141.98.11.147
| | | | | , 147.185.132.58, 176.65
| | | | | .148.10, 194.0.234.19, 2
| | | | | 05.210.31.65
debl.v6 | 136 | ON: 0 | - | - |
doh.v4 | 1727 | - | ON: 2233 | tcp, udp: 53, 80, 443 | 8.8.8.8
doh.v6 | 1217 | - | ON: 0 | tcp, udp: 53, 80, 443 |
hagezi.v4 | 35287 | - | ON: 0 | tcp, udp: 80, 443 |
threat.v4 | 1041 | ON: 107 | - | - | 45.135.193.0, 45.153.34.
| | | | | 0, 80.94.95.0, 83.222.19
| | | | | 0.0, 87.121.84.0, 141.98
| | | | | .10.0, 176.65.137.0, 176
| | | | | .65.148.0, 196.251.69.0,
| | | | | 196.251.83.0, 204.76.20
| | | | | 3.0, 213.209.143.0
turris.v4 | 4553 | ON: 131 | - | - | 74.50.211.178, 109.205.2
| | | | | 13.115, 109.205.213.123,
| | | | | 109.205.213.248, 109.20
| | | | | 5.213.250, 109.205.213.2
| | | | | 52, 122.222.152.65, 186.
| | | | | 91.25.141, 190.203.106.1
| | | | | 13, 200.123.238.20
turris.v6 | 44 | ON: 0 | - | - |
dns.v4 | 95493 | - | ON: 2039 | tcp, udp: 53, 853 | 8.8.8.8
dns.v6 | 251 | - | ON: 0 | tcp, udp: 53, 853 |
doh.v4 | 1663 | - | ON: 0 | tcp, udp: 80, 443 |
doh.v6 | 1204 | - | ON: 0 | tcp, udp: 80, 443 |
hagezi.v4 | 39535 | - | ON: 0 | tcp, udp: 80, 443 |
---------------------+--------------+-----------------------+-----------------------+-----------------------+------------------------
19 | 128753 | 12 (922) | 11 (2674) | 8 | 137
13 | 138155 | 4 (362) | 13 (2851) | 10 | 5
```
**banIP runtime information**
```
~# /etc/init.d/banip status
::: banIP runtime information
+ status : active (nft: ✔, monitor: ✔)
+ frontend_ver : 1.6.0-r1
+ backend_ver : 1.6.0-r1
+ element_count : 223 563 (chains: 7, sets: 22, rules: 75)
+ active_feeds : allowlist.v4MAC, allowlist.v6MAC, allowlist.v4, allowlist.v6, cinsscore.v4, debl.v4, country.v6, debl.v6, country.v4, dns.v4, dns.v6, doh.v4, doh.v6, firehol1.v4, hagezi.v4, threat.v4, turris.v4, turris.v6, blocklist.v4MAC, blocklist.v6MAC, blocklist.v4, blocklist.v6
+ frontend_ver : 1.8.0-r1
+ backend_ver : 1.8.0-r1
+ element_count : 138 148 (chains: 7, sets: 13, rules: 50)
+ active_feeds : allowlist.v4MAC, allowlist.v6MAC, allowlist.v4, allowlist.v6, dns.v4, blocklist.v4MAC, blocklist.v6MAC, doh.v6, blocklist.v4, doh.v4, blocklist.v6, dns.v6, hagezi.v4
+ active_devices : wan: pppoe-wan / wan-if: wan, wan_6 / vlan-allow: - / vlan-block: -
+ active_uplink : 5.73.187.13, 2a04:5700:104:c65a:dc41:4131:409:227c
+ nft_info : ver: 1.1.5-r1, priority: -100, policy: performance, loglevel: warn, expiry: 2h, limit (icmp/syn/udp): 25/10/100
+ active_uplink : 5.73.162.23, 2a13:4800:204:319e:b26d:238b:d7fe:8213
+ nft_info : ver: 1.1.6-r1, priority: -100, policy: performance, loglevel: warn, expiry: 2h, limit (icmp/syn/udp): 25/10/100
+ run_info : base: /mnt/data/banIP, backup: /mnt/data/banIP/backup, report: /mnt/data/banIP/report, error: /mnt/data/banIP/error
+ run_flags : auto: ✔, proto (4/6): ✔/✔, log (pre/in/out): ✔/✔/✔, count: ✔, dedup: ✔, split: ✘, custom feed: ✘, allowed only: ✘
+ last_run : mode: restart, 2025-12-04 10:00:41, duration: 0m 48s, memory: 1361.54 MB available
+ system_info : cores: 4, log: logread, fetch: curl, Bananapi BPI-R3, mediatek/filogic, OpenWrt SNAPSHOT r32101-28cc1c368c
+ run_flags : auto: ✔, proto (4/6): ✔/✔, bcp38: ✔, log (pre/in/out): ✘/✘/✔, count: ✔, dedup: ✔, split: ✘, custom feed: ✘, allowed only: ✘
+ last_run : mode: restart, 2026-01-12 06:16:19, duration: 0m 36s, memory: 1446.84 MB available
+ system_info : cores: 4, log: logread, fetch: curl, Bananapi BPI-R3, mediatek/filogic, OpenWrt SNAPSHOT (r32542-bf46d119a2)
```
**banIP search information**
@@ -492,6 +418,12 @@ The MAC-address logging format in nftables is a little bit unusual. It is genera
68:34:21:1f:a7:b1 → the destination MAC address
08:00 → the EtherType for IPv4 (0x0800)
```
**BCP38**
BCP38 (**B**est **C**urrent **P**ractice, RFC 2827) defines ingress filtering to prevent IP address spoofing. In practice, this means:
* dropping packets arriving on the WAN whose source address is not valid or routable via that interface
* dropping packets leaving LAN => WAN whose source address does not belong to the local/internal prefixes
In banIP, the BCP38 implementation uses nftables FIB lookup to enforce this. It checks whether the packets source address is not valid for the incoming interface or whether the routing table reports no route for this source on this interface. Packets that fail this check are dropped.
**Set reporting, enable the GeoIP Map**
banIP includes a powerful reporting tool on the Set Reporting tab which shows the latest NFT banIP Set statistics. To get the latest statistics always press the "Refresh" button.
@@ -573,16 +505,21 @@ A valid JSON source object contains the following information, e.g.:
"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": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "out",
"descr": "public DoH-Provider",
"descr": "public DoH-Server",
"flag": "tcp udp 80 443"
},
[...]
```
Add an unique feed name (no spaces, no special chars) and make the required changes: adapt at least the URL, the regex, the chain and the description for a new feed.
Add an unique feed name (no spaces, no special chars) and make the required changes: adapt at least the URL, check/change the rule, the size and the description for a new feed.
The rule consist of max. 4 individual, space separated parameters:
1. type: 'feed' or 'suricata' (required)
2. prefix: an optional search term (a string literal, no regex) to identify valid IP list entries
3. column: the IP column within the feed file, e.g. '1' (required)
4. separator: an optional field separator, default is the character class '[[:space:]]'
Please note: the flag field is optional, it's a space separated list of options: supported are 'gz' as an archive format and protocols 'tcp' or 'udp' with port numbers/port ranges for destination port limitations.
**Debug options**

View File

@@ -1,5 +1,5 @@
# banIP shared function library/include - ban incoming and outgoing IPs via named nftables Sets
# Copyright (c) 2018-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2018-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions
@@ -28,7 +28,7 @@ ban_rdapfile="/var/run/banip_rdap.json"
ban_rdapurl="https://rdap.db.ripe.net/ip/"
ban_geourl="http://ip-api.com/batch"
ban_lock="/var/run/banip.lock"
ban_logreadfile="/var/log/messages"
ban_logreadfile=""
ban_logreadcmd=""
ban_mailsender="no-reply@banIP"
ban_mailreceiver=""
@@ -41,9 +41,10 @@ ban_nftloglevel="warn"
ban_nftpriority="-100"
ban_nftpolicy="memory"
ban_nftexpiry=""
ban_nftretry="5"
ban_nftretry="3"
ban_nftcount="0"
ban_map="0"
ban_bcp38="0"
ban_icmplimit="25"
ban_synlimit="10"
ban_udplimit="100"
@@ -108,7 +109,7 @@ f_system() {
ban_bver="$(printf "%s" "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages.banip')"
ban_fver="$(printf "%s" "${ban_packages}" | "${ban_jsoncmd}" -ql1 -e '@.packages["luci-app-banip"]')"
ban_sysver="$("${ban_ubuscmd}" -S call system board 2>/dev/null | "${ban_jsoncmd}" -ql1 -e '@.model' -e '@.release.target' -e '@.release.distribution' -e '@.release.version' -e '@.release.revision' |
"${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s, %s %s %s %s",$1,$2,$3,$4,$5,$6}')"
"${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s, %s %s (%s)",$1,$2,$3,$4,$5}')"
if [ -z "${ban_cores}" ]; then
cpu="$("${ban_grepcmd}" -c '^processor' /proc/cpuinfo 2>/dev/null)"
@@ -171,7 +172,7 @@ f_tmp() {
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:-"-"}"
f_log "debug" "f_tmp ::: base_dir: ${ban_basedir:-"-"}, tmp_dir: ${ban_tmpdir:-"-"}"
}
# remove directories
@@ -181,7 +182,7 @@ f_rmdir() {
if [ -d "${dir}" ]; then
rm -rf "${dir}"
f_log "debug" "f_rmdir ::: directory: ${dir}"
f_log "debug" "f_rmdir ::: directory: ${dir}"
fi
}
@@ -265,17 +266,30 @@ f_conf() {
option_cb() {
local option="${1}" value="${2//\"/\\\"}"
eval "${option}=\"${value}\""
case "${option}" in
*[!a-zA-Z0-9_]*)
;;
*)
eval "${option}=\"\${value}\""
;;
esac
}
list_cb() {
local append option="${1}" value="${2//\"/\\\"}"
eval "append=\"\${${option}}\""
case "${option}" in
*[!a-zA-Z0-9_]*)
;;
"ban_logterm")
eval "${option}=\"${append}${value}\\|\""
eval "append=\"\${${option}}\""
if [ -n "${append}" ]; then
eval "${option}=\"${append}\\|${value}\""
else
eval "${option}=\"${value}\""
fi
;;
*)
eval "append=\"\${${option}}\""
eval "${option}=\"${append}${value} \""
;;
esac
@@ -283,7 +297,11 @@ f_conf() {
}
config_load banip
[ -f "${ban_logreadfile}" ] && ban_logreadcmd="$(command -v tail)" || ban_logreadcmd="$(command -v logread)"
if [ -f "${ban_logreadfile}" ]; then
ban_logreadcmd="$(command -v tail)"
else
ban_logreadcmd="$(command -v logread)"
fi
for rir in ${ban_region}; do
while read -r ccode region country; do
@@ -294,6 +312,134 @@ f_conf() {
done
}
# IPv4/IPv6 validation
#
f_chkip() {
local ipv type prefix separator col1 col2
ipv="${1}"
type="${2}"
case "${type}" in
"feed"|"local")
case "${3}" in
[0-9][0-9])
prefix=""
col1="${3:0:1}"
col2="${3:1:1}"
separator="${4:-[[:space:]]+}"
;;
[0-9])
prefix=""
col1="${3}"
col2=""
separator="${4:-[[:space:]]+}"
;;
*)
prefix="${3}"
col1="${4}"
col2=""
separator="${5:-[[:space:]]+}"
;;
esac
;;
"suricata")
prefix=""
col1="${3}"
col2=""
separator="${4:-[[:space:]]+}"
;;
esac
"${ban_awkcmd}" -v ipv="${ipv}" -v type="${type}" -v pre="${prefix}" -v col1="${col1}" -v col2="${col2}" -F "${separator}" '
{
# suricata pre-processing
if (type == "suricata") {
delete M
if (ipv == "4") {
match($0, /content:"(([0-9]{1,3}\.){3}[0-9]{1,3})"/, M)
} else if (ipv == "6") {
match($0, /content:"(([A-Fa-f0-9]{0,4}:){2,7}[A-Fa-f0-9]{0,4})"/, M)
}
if (M[1] == "") next
$col1 = M[1]
}
ip = $col1
gsub(/\r|^[[:space:]]+|[[:space:]]+$/, "", ip)
# prefix filter
if (pre != "" && $1 != pre) next
# skip empty lines or comments
if (ip == "" || ip ~ /^#/) next
# reject invalid lengths
len = length(ip)
if (len < 3 || len > 43) next
# reject MAC addresses when ipv=6
if (ipv == "6" && ip ~ /^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$/) next
# reject IPv4 when ipv=6
if (ipv == "6" && ip ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) next
# reject IPv6 when ipv=4
if (ipv == "4" && ip ~ /:/) next
# apply mask
if (col2 != "") {
mask = $col2
lowip = (ipv == "4") ? ip "/" mask : tolower(ip "/" mask)
} else {
lowip = (ipv == "4") ? ip : tolower(ip)
}
# CIDR check
if (lowip ~ /\//) {
if (split(lowip, C, "/") != 2) next
base = C[1]
mask = C[2]
if (mask !~ /^[0-9]+$/) next
# IPv4 CIDR
if (ipv == "4") {
if (base ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {
if (mask < 0 || mask > 32) next
n = split(base, A, ".")
if (n != 4) next
if (A[1] == 127 || base == "0.0.0.0") next
for (i=1; i<=4; i++) if (A[i] < 0 || A[i] > 255) next
print lowip ", "
next
}
}
# IPv6 CIDR
if (ipv == "6") {
#if (base ~ /^([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}$/) {
if (base ~ /^[0-9a-f:]+$/ && base ~ /:/) {
if (mask < 0 || mask > 128) next
if (base == "::1" || base == "::") next
if (base ~ /^fe80:/) next
print lowip ", "
next
}
}
}
# IPv4 check
if (ipv == "4") {
if (lowip ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {
n = split(lowip, A, ".")
if (n != 4) next
if (A[1] == 127 || lowip == "0.0.0.0") next
for (i=1; i<=4; i++) if (A[i] < 0 || A[i] > 255) next
print lowip ", "
next
}
}
# IPv6 check
if (ipv == "6") {
#if (lowip ~ /^([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}$/) {
if (lowip ~ /^[0-9a-f:]+$/ && lowip ~ /:/) {
if (lowip == "::1" || lowip == "::") next
if (lowip ~ /^fe80:/) next
print lowip ", "
next
}
}
}'
f_log "debug" "f_chkip ::: feed: ${feed}, ipver: ${ipv}, type: ${type}, prefix: ${prefix:-"-"}, col1: ${col1:-"-"}, col2: ${col2:-"-"}, separator: ${separator:-"-"}"
}
# get nft/monitor actuals
#
f_actual() {
@@ -324,7 +470,7 @@ f_actual() {
# get fetch utility
#
f_getfetch() {
f_getdl() {
local fetch fetch_list insecure update="0"
ban_fetchcmd="$(command -v "${ban_fetchcmd}")"
@@ -375,7 +521,7 @@ f_getfetch() {
;;
esac
f_log "debug" "f_getfetch ::: auto/update: ${ban_autodetect}/${update}, cmd: ${ban_fetchcmd:-"-"}"
f_log "debug" "f_getdl ::: auto/update: ${ban_autodetect}/${update}, cmd: ${ban_fetchcmd:-"-"}"
}
# get wan interfaces
@@ -424,7 +570,7 @@ f_getif() {
ban_ifv6="$(f_trim "${ban_ifv6}")"
[ -z "${ban_ifv4}" ] && [ -z "${ban_ifv6}" ] && f_log "err" "no wan interfaces"
f_log "debug" "f_getif ::: auto/update: ${ban_autodetect}/${update}, interfaces (4/6): ${ban_ifv4}/${ban_ifv6}, protocols (4/6): ${ban_protov4}/${ban_protov6}"
f_log "debug" "f_getif ::: auto/update: ${ban_autodetect}/${update}, interfaces (4/6): ${ban_ifv4}/${ban_ifv6}, protocols (4/6): ${ban_protov4}/${ban_protov6}"
}
# get wan devices
@@ -459,12 +605,12 @@ f_getdev() {
ban_dev="$(f_trim "${ban_dev}")"
[ -z "${ban_dev}" ] && f_log "err" "no wan devices"
f_log "debug" "f_getdev ::: auto/update: ${ban_autodetect}/${update}, wan_devices: ${ban_dev}"
f_log "debug" "f_getdev ::: auto/update: ${ban_autodetect}/${update}, wan_devices: ${ban_dev}"
}
# get local uplink
#
f_getuplink() {
f_getup() {
local uplink iface ip
if [ "${ban_autoallowlist}" = "1" ] && [ "${ban_autoallowuplink}" != "disable" ]; then
@@ -505,7 +651,7 @@ f_getuplink() {
"${ban_sedcmd}" -i "/# uplink added on /d" "${ban_allowlist}"
fi
f_log "debug" "f_getuplink ::: auto-allow/auto-uplink: ${ban_autoallowlist}/${ban_autoallowuplink}, uplink: ${ban_uplink:-"-"}"
f_log "debug" "f_getup ::: auto-allow/auto-uplink: ${ban_autoallowlist}/${ban_autoallowuplink}, uplink: ${ban_uplink:-"-"}"
}
# get feed information
@@ -562,14 +708,14 @@ f_etag() {
fi
fi
f_log "debug" "f_etag ::: feed: ${feed}, suffix: ${feed_suffix:-"-"}, http_code: ${http_code:-"-"}, feed/etag: ${feed_cnt}/${etag_cnt:-"0"}, rc: ${out_rc}"
f_log "debug" "f_etag ::: feed: ${feed}, suffix: ${feed_suffix:-"-"}, http_code: ${http_code:-"-"}, feed/etag: ${feed_cnt}/${etag_cnt:-"0"}, rc: ${out_rc}"
return "${out_rc}"
}
# load file in nftset
#
f_nftload() {
local cnt="1" max_cnt="${ban_nftretry:-"5"}" load_rc="4" file="${1}" errmsg="${2}"
local cnt="1" max_cnt="${ban_nftretry:-"3"}" load_rc="4" file="${1}" errmsg="${2}"
while [ "${load_rc}" != "0" ]; do
"${ban_nftcmd}" -f "${file}" >/dev/null 2>&1
@@ -585,7 +731,7 @@ f_nftload() {
cnt="$((cnt + 1))"
done
f_log "debug" "f_nftload ::: file: ${file##*/}, load_rc: ${load_rc}, cnt: ${cnt}, max_cnt: ${max_cnt}"
f_log "debug" "f_nftload ::: file: ${file##*/}, load_rc: ${load_rc}, cnt/max_cnt: ${cnt}/${max_cnt}"
return "${load_rc}"
}
@@ -654,6 +800,7 @@ f_nftinit() {
printf "%s\n" "add counter inet banIP cnt_synflood"
printf "%s\n" "add counter inet banIP cnt_tcpinvalid"
printf "%s\n" "add counter inet banIP cnt_ctinvalid"
printf "%s\n" "add counter inet banIP cnt_bcp38"
# default reject chain rules
#
@@ -703,12 +850,15 @@ f_nftinit() {
# default wan-input rules
#
printf "%s\n" "add rule inet banIP wan-input iifname != { ${wan_dev} } counter accept"
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 != { ${wan_dev} } counter accept"
printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv4 udp sport 67-68 udp dport 67-68 counter accept"
printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 udp sport 547 udp dport 546 counter accept"
printf "%s\n" "add rule inet banIP wan-input meta nfproto ipv6 icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } ip6 hoplimit 255 counter accept"
[ -n "${allow_dport}" ] && printf "%s\n" "add rule inet banIP wan-input ${allow_dport} counter accept"
if [ "${ban_bcp38}" = "1" ]; then
printf "%s\n" "add rule inet banIP wan-input fib saddr . iif oif missing counter name cnt_bcp38 drop"
fi
if [ "${ban_loginbound}" = "1" ]; then
printf "%s\n" "add rule inet banIP wan-input meta mark set 1 counter jump _inbound"
else
@@ -717,9 +867,12 @@ f_nftinit() {
# default wan-forward rules
#
printf "%s\n" "add rule inet banIP wan-forward iifname != { ${wan_dev} } counter accept"
printf "%s\n" "add rule inet banIP wan-forward ct state established,related counter accept"
printf "%s\n" "add rule inet banIP wan-forward iifname != { ${wan_dev} } counter accept"
[ -n "${allow_dport}" ] && printf "%s\n" "add rule inet banIP wan-forward ${allow_dport} counter accept"
if [ "${ban_bcp38}" = "1" ]; then
printf "%s\n" "add rule inet banIP wan-forward fib saddr . iif oif missing counter name cnt_bcp38 drop"
fi
if [ "${ban_loginbound}" = "1" ]; then
printf "%s\n" "add rule inet banIP wan-forward meta mark set 2 counter jump _inbound"
else
@@ -728,10 +881,13 @@ f_nftinit() {
# default lan-forward rules
#
printf "%s\n" "add rule inet banIP lan-forward oifname != { ${wan_dev} } counter accept"
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 != { ${wan_dev} } counter accept"
[ -n "${vlan_allow}" ] && printf "%s\n" "add rule inet banIP lan-forward iifname { ${vlan_allow} } counter accept"
[ -n "${vlan_block}" ] && printf "%s\n" "add rule inet banIP lan-forward iifname { ${vlan_block} } counter goto _reject"
if [ "${ban_bcp38}" = "1" ]; then
printf "%s\n" "add rule inet banIP lan-forward fib saddr . iif oif missing counter name cnt_bcp38 drop"
fi
printf "%s\n" "add rule inet banIP lan-forward counter jump _outbound"
} >"${file}"
@@ -741,7 +897,7 @@ f_nftinit() {
feed_rc="${?}"
[ "${feed_rc}" = "0" ] && f_log "info" "initialize banIP nftables namespace"
f_log "debug" "f_nftinit ::: wan_dev: ${wan_dev}, vlan_allow: ${vlan_allow:-"-"}, vlan_block: ${vlan_block:-"-"}, allowed_dports: ${allow_dport:-"-"}, priority: ${ban_nftpriority}, policy: ${ban_nftpolicy}, icmp_limit: ${ban_icmplimit}, syn_limit: ${ban_synlimit}, udp_limit: ${ban_udplimit}, loglevel: ${ban_nftloglevel}, rc: ${feed_rc:-"-"}"
f_log "debug" "f_nftinit ::: wan_dev: ${wan_dev}, vlan_allow: ${vlan_allow:-"-"}, vlan_block: ${vlan_block:-"-"}, allowed_dports: ${allow_dport:-"-"}, priority: ${ban_nftpriority}, policy: ${ban_nftpolicy}, icmp_limit: ${ban_icmplimit}, syn_limit: ${ban_synlimit}, udp_limit: ${ban_udplimit}, loglevel: ${ban_nftloglevel}, rc: ${feed_rc:-"-"}"
: >"${file}"
return "${feed_rc}"
}
@@ -751,10 +907,10 @@ f_nftinit() {
f_down() {
local log_inbound log_outbound start_ts end_ts tmp_raw tmp_load tmp_file split_file table_json handles handle etag_rc etag_cnt element_count
local expr cnt_set cnt_dl restore_rc feed_direction feed_policy feed_rc feed_comp feed_complete feed_target feed_dport chain flag
local tmp_proto tmp_port asn country feed="${1}" proto="${2}" feed_url="${3}" feed_rule="${4}" feed_chain="${5}" feed_flag="${6}"
local tmp_proto tmp_port asn country feed="${1}" feed_ipv="${2}" feed_url="${3}" feed_rule="${4}" feed_chain="${5}" feed_flag="${6}"
start_ts="$(date +%s)"
feed="${feed}.v${proto}"
feed="${feed}.v${feed_ipv}"
tmp_load="${ban_tmpfile}.${feed}.load"
tmp_raw="${ban_tmpfile}.${feed}.raw"
tmp_split="${ban_tmpfile}.${feed}.split"
@@ -953,7 +1109,7 @@ f_down() {
{
printf "%s\n\n" "#!${ban_nftcmd} -f"
[ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
case "${proto}" in
case "${feed_ipv}" in
"4MAC")
"${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}(\/([0-9]|[1-3][0-9]|4[0-8]))?([[:space:]]+([1-9][0-9]?[0-9]?\.){1}([0-9]{1,3}\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?([[:space:]]+#.*$|[[:space:]]*$)|[[:space:]]+#.*$|$)/{if(!$2||$2~/#/)$2="0.0.0.0/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${tmp_allow}" >"${tmp_file}"
printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
@@ -965,7 +1121,7 @@ f_down() {
[ -z "${feed_direction##*outbound*}" ] && printf "%s\n" "add rule inet banIP _outbound ether saddr . ip6 saddr @${feed} counter accept"
;;
"4")
"${ban_awkcmd}" '/^127\./{next}/^(([1-9][0-9]?[0-9]?\.){1}([0-9]{1,3}\.){2}(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}' "${tmp_allow}" >"${tmp_file}"
f_chkip ${feed_ipv} local 1 < "${tmp_allow}" >"${tmp_file}"
printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
if [ -z "${feed_direction##*inbound*}" ]; then
if [ "${ban_allowlistonly}" = "1" ]; then
@@ -989,8 +1145,7 @@ f_down() {
fi
;;
"6")
"${ban_awkcmd}" '!/^([0-9A-f]{2}:){5}[0-9A-f]{2}.*/{printf "%s\n",$1}' "${tmp_allow}" |
"${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}"
f_chkip ${feed_ipv} local 1 < "${tmp_allow}" >"${tmp_file}"
printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
if [ -z "${feed_direction##*inbound*}" ]; then
if [ "${ban_allowlistonly}" = "1" ]; then
@@ -1021,7 +1176,7 @@ f_down() {
{
printf "%s\n\n" "#!${ban_nftcmd} -f"
[ -s "${tmp_flush}" ] && "${ban_catcmd}" "${tmp_flush}"
case "${proto}" in
case "${feed_ipv}" in
"4MAC")
"${ban_awkcmd}" '/^([0-9A-f]{2}:){5}[0-9A-f]{2}(\/([0-9]|[1-3][0-9]|4[0-8]))?([[:space:]]+([1-9][0-9]?[0-9]?\.){1}([0-9]{1,3}\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/(1?[0-9]|2?[0-9]|3?[0-2]))?([[:space:]]+#.*$|[[:space:]]*$)|[[:space:]]+#.*$|$)/{if(!$2||$2~/#/)$2="0.0.0.0/0";if(!seen[$1]++)printf "%s . %s, ",tolower($1),$2}' "${ban_blocklist}" >"${tmp_file}"
printf "%s\n" "add set inet banIP ${feed} { type ether_addr . ipv4_addr; flags interval; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
@@ -1033,8 +1188,7 @@ f_down() {
[ -z "${feed_direction##*outbound*}" ] && printf "%s\n" "add rule inet banIP _outbound ether saddr . ip6 saddr @${feed} counter goto _reject"
;;
"4")
"${ban_awkcmd}" '/^127\./{next}/^(([1-9][0-9]?[0-9]?\.){1}([0-9]{1,3}\.){2}(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}" |
"${ban_awkcmd}" '{ORS=" ";print}' >"${tmp_file}"
f_chkip ${feed_ipv} local 1 < "${ban_blocklist}" >"${tmp_file}"
printf "%s\n" "add set inet banIP ${feed} { type ipv4_addr; flags interval, timeout; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
if [ -z "${feed_direction##*inbound*}" ]; then
if [ "${ban_loginbound}" = "1" ]; then
@@ -1050,9 +1204,7 @@ f_down() {
fi
;;
"6")
"${ban_awkcmd}" '!/^([0-9A-f]{2}:){5}[0-9A-f]{2}.*/{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)}' |
"${ban_awkcmd}" '{ORS=" ";print}' >"${tmp_file}"
f_chkip ${feed_ipv} local 1 < "${ban_blocklist}" >"${tmp_file}"
printf "%s\n" "add set inet banIP ${feed} { type ipv6_addr; flags interval, timeout; auto-merge; policy ${ban_nftpolicy}; ${element_count}; $(f_getelements "${tmp_file}") }"
if [ -z "${feed_direction##*inbound*}" ]; then
if [ "${ban_loginbound}" = "1" ]; then
@@ -1164,11 +1316,11 @@ f_down() {
# deduplicate Sets
#
if [ "${ban_deduplicate}" = "1" ] && [ "${feed_url}" != "local" ] && [ -z "${feed_complete}" ]; then
"${ban_awkcmd}" '{sub("\r$", "");print}' "${tmp_load}" 2>/dev/null | "${ban_awkcmd}" "${feed_rule}" 2>/dev/null >"${tmp_raw}"
f_chkip ${feed_ipv} ${feed_rule} < "${tmp_load}" >"${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}"
feed_rc="${?}"
else
"${ban_awkcmd}" '{sub("\r$", "");print}' "${tmp_load}" 2>/dev/null | "${ban_awkcmd}" "${feed_rule}" 2>/dev/null >"${tmp_split}"
f_chkip ${feed_ipv} ${feed_rule} < "${tmp_load}" >"${tmp_split}"
feed_rc="${?}"
fi
: >"${tmp_raw}" >"${tmp_load}"
@@ -1189,7 +1341,7 @@ f_down() {
# build nft file
#
if [ "${feed_rc}" = "0" ] && [ -s "${tmp_file}.1" ]; then
if [ "${proto}" = "4" ]; then
if [ "${feed_ipv}" = "4" ]; then
{
# nft header (IPv4 Set) incl. inbound and outbound rules
#
@@ -1209,7 +1361,7 @@ f_down() {
printf "%s\n" "add rule inet banIP _outbound ${feed_dport} ip daddr @${feed} counter goto _reject"
fi
} >"${tmp_nft}"
elif [ "${proto}" = "6" ]; then
elif [ "${feed_ipv}" = "6" ]; then
{
# nft header (IPv6 Set) incl. inbound and outbound rules
#
@@ -1272,7 +1424,7 @@ f_down() {
: >"${tmp_nft}"
end_ts="$(date +%s)"
f_log "debug" "f_down ::: feed: ${feed}, policy: ${feed_policy}, complete: ${feed_complete:-"-"}, cnt_dl: ${cnt_dl:-"-"}, cnt_set: ${cnt_set:-"-"}, split_size: ${ban_splitsize:-"-"}, time: $((end_ts - start_ts)), rc: ${feed_rc:-"-"}"
f_log "debug" "f_down ::: feed: ${feed}, policy: ${feed_policy}, complete: ${feed_complete:-"-"}, cnt_dl: ${cnt_dl:-"-"}, cnt_set: ${cnt_set:-"-"}, split_size: ${ban_splitsize:-"-"}, time: $((end_ts - start_ts)), rc: ${feed_rc:-"-"}"
}
# backup feeds
@@ -1285,7 +1437,7 @@ f_backup() {
backup_rc="${?}"
fi
f_log "debug" "f_backup ::: feed: ${feed}, file: banIP.${feed}.gz, rc: ${backup_rc}"
f_log "debug" "f_backup ::: feed: ${feed}, file: banIP.${feed}.gz, rc: ${backup_rc}"
return "${backup_rc}"
}
@@ -1300,7 +1452,7 @@ f_restore() {
restore_rc="${?}"
fi
f_log "debug" "f_restore ::: feed: ${feed}, file: banIP.${tmp_feed}.gz, in_rc: ${in_rc:-"-"}, rc: ${restore_rc}"
f_log "debug" "f_restore ::: feed: ${feed}, file: banIP.${tmp_feed}.gz, in_rc: ${in_rc:-"-"}, rc: ${restore_rc}"
return "${restore_rc}"
}
@@ -1367,7 +1519,7 @@ f_rmset() {
fi
: >"${tmp_del}"
f_log "debug" "f_rmset ::: nfset: ${del_set:-"-"}, rc: ${feed_rc:-"-"}"
f_log "debug" "f_rmset ::: feed: ${del_set:-"-"}, rc: ${feed_rc:-"-"}"
}
# generate status information
@@ -1437,7 +1589,7 @@ f_genstatus() {
json_close_array
json_add_string "nft_info" "ver: ${nft_ver:-"-"}, priority: ${ban_nftpriority}, policy: ${ban_nftpolicy}, loglevel: ${ban_nftloglevel}, expiry: ${ban_nftexpiry:-"-"}, limit (icmp/syn/udp): ${ban_icmplimit}/${ban_synlimit}/${ban_udplimit}"
json_add_string "run_info" "base: ${ban_basedir}, backup: ${ban_backupdir}, report: ${ban_reportdir}, error: ${ban_errordir}"
json_add_string "run_flags" "auto: $(f_char ${ban_autodetect}), proto (4/6): $(f_char ${ban_protov4})/$(f_char ${ban_protov6}), log (pre/in/out): $(f_char ${ban_logprerouting})/$(f_char ${ban_loginbound})/$(f_char ${ban_logoutbound}), count: $(f_char ${ban_nftcount}), dedup: $(f_char ${ban_deduplicate}), split: $(f_char ${split}), custom feed: $(f_char ${custom_feed}), allowed only: $(f_char ${ban_allowlistonly})"
json_add_string "run_flags" "auto: $(f_char ${ban_autodetect}), proto (4/6): $(f_char ${ban_protov4})/$(f_char ${ban_protov6}), bcp38: $(f_char ${ban_bcp38}), log (pre/in/out): $(f_char ${ban_logprerouting})/$(f_char ${ban_loginbound})/$(f_char ${ban_logoutbound}), count: $(f_char ${ban_nftcount}), dedup: $(f_char ${ban_deduplicate}), split: $(f_char ${split}), custom feed: $(f_char ${custom_feed}), allowed only: $(f_char ${ban_allowlistonly})"
json_add_string "last_run" "${runtime:-"-"}"
json_add_string "system_info" "cores: ${ban_cores}, log: ${ban_logreadcmd##*/}, fetch: ${ban_fetchcmd##*/}, ${ban_sysver}"
json_dump >"${ban_rtfile}"
@@ -1523,7 +1675,7 @@ f_lookup() {
end_time="$(date "+%s")"
duration="$(((end_time - start_time) / 60))m $(((end_time - start_time) % 60))s"
f_log "debug" "f_lookup ::: feed: ${feed}, domains: ${cnt_domain}, IPs: ${cnt_ip}, duration: ${duration}"
f_log "debug" "f_lookup ::: feed: ${feed}, domains: ${cnt_domain}, IPs: ${cnt_ip}, duration: ${duration}"
}
# table statistics
@@ -1531,7 +1683,8 @@ f_lookup() {
f_report() {
local report_jsn report_txt tmp_val table_json item table_sets set_cnt set_inbound set_outbound set_cntinbound set_cntoutbound set_proto set_dport set_details
local expr detail jsnval timestamp autoadd_allow autoadd_block sum_sets sum_setinbound sum_setoutbound sum_cntelements sum_cntinbound sum_cntoutbound
local quantity chunk map_jsn chain set_elements set_json sum_setelements sum_synflood sum_udpflood sum_icmpflood sum_ctinvalid sum_tcpinvalid output="${1}"
local quantity chunk map_jsn chain set_elements set_json sum_setelements sum_synflood sum_udpflood sum_icmpflood sum_ctinvalid sum_tcpinvalid
local sum_bcp38 output="${1}"
f_conf
f_mkdir "${ban_reportdir}"
@@ -1559,6 +1712,7 @@ f_report() {
sum_icmpflood="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_icmpflood"].*.packets')"
sum_ctinvalid="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_ctinvalid"].*.packets')"
sum_tcpinvalid="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_tcpinvalid"].*.packets')"
sum_bcp38="$(printf "%s" "${table_json}" | "${ban_jsoncmd}" -qe '@.nftables[@.counter.name="cnt_bcp38"].*.packets')"
timestamp="$(date "+%Y-%m-%d %H:%M:%S")"
cnt="1"
@@ -1614,9 +1768,25 @@ f_report() {
set_cntoutbound=""
fi
if [ "${cnt}" = "1" ]; then
printf "%s\n" "{ \"sets\":{ \"${item}\":{ \"cnt_elements\": \"${set_cnt}\", \"cnt_inbound\": \"${set_cntinbound}\", \"inbound\": \"${set_inbound}\", \"cnt_outbound\": \"${set_cntoutbound}\", \"outbound\": \"${set_outbound}\", \"port\": \"${set_dport:-"-"}\", \"set_elements\": [ ${set_elements%%??} ] }" >>"${report_jsn}"
printf "%s\n" "{ \
\"sets\":{ \"${item}\":{ \"cnt_elements\": \"${set_cnt}\", \
\"cnt_inbound\": \"${set_cntinbound}\", \
\"inbound\": \"${set_inbound}\", \
\"cnt_outbound\": \"${set_cntoutbound}\", \
\"outbound\": \"${set_outbound}\", \
\"port\": \"${set_dport:-"-"}\", \
\"set_elements\": [ ${set_elements%%??} ] \
}" >>"${report_jsn}"
else
printf "%s\n" ", \"${item}\":{ \"cnt_elements\": \"${set_cnt}\", \"cnt_inbound\": \"${set_cntinbound}\", \"inbound\": \"${set_inbound}\", \"cnt_outbound\": \"${set_cntoutbound}\", \"outbound\": \"${set_outbound}\", \"port\": \"${set_dport:-"-"}\", \"set_elements\": [ ${set_elements%%??} ] }" >>"${report_jsn}"
printf "%s\n" ", \
\"${item}\":{ \"cnt_elements\": \"${set_cnt}\", \
\"cnt_inbound\": \"${set_cntinbound}\", \
\"inbound\": \"${set_inbound}\", \
\"cnt_outbound\": \"${set_cntoutbound}\", \
\"outbound\": \"${set_outbound}\", \
\"port\": \"${set_dport:-"-"}\", \
\"set_elements\": [ ${set_elements%%??} ] \
}" >>"${report_jsn}"
fi
) &
[ "${cnt}" -eq "1" ] || [ "${cnt}" -gt "${ban_cores}" ] && wait -n
@@ -1686,7 +1856,25 @@ f_report() {
json_select ".."
done
"${ban_sedcmd}" -i ':a;$!N;1,1ba;P;$d;D' "${report_jsn}"
printf "%s\n" "}, \"timestamp\": \"${timestamp}\", \"autoadd_allow\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_allowlist}")\", \"autoadd_block\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_blocklist}")\", \"sum_synflood\": \"${sum_synflood}\", \"sum_udpflood\": \"${sum_udpflood}\", \"sum_icmpflood\": \"${sum_icmpflood}\", \"sum_ctinvalid\": \"${sum_ctinvalid}\", \"sum_tcpinvalid\": \"${sum_tcpinvalid}\", \"sum_sets\": \"${sum_sets}\", \"sum_setinbound\": \"${sum_setinbound}\", \"sum_setoutbound\": \"${sum_setoutbound}\", \"sum_cntelements\": \"${sum_cntelements}\", \"sum_cntinbound\": \"${sum_cntinbound}\", \"sum_cntoutbound\": \"${sum_cntoutbound}\", \"sum_setports\": \"${sum_setports}\", \"sum_setelements\": \"${sum_setelements}\" }" >>"${report_jsn}"
printf "%s\n" "}, \
\"timestamp\": \"${timestamp}\", \
\"autoadd_allow\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_allowlist}")\", \
\"autoadd_block\": \"$("${ban_grepcmd}" -c "added on ${timestamp% *}" "${ban_blocklist}")\", \
\"sum_synflood\": \"${sum_synflood}\", \
\"sum_udpflood\": \"${sum_udpflood}\", \
\"sum_icmpflood\": \"${sum_icmpflood}\", \
\"sum_ctinvalid\": \"${sum_ctinvalid}\", \
\"sum_tcpinvalid\": \"${sum_bcp38}\", \
\"sum_bcp38\": \"${sum_bcp38}\", \
\"sum_sets\": \"${sum_sets}\", \
\"sum_setinbound\": \"${sum_setinbound}\", \
\"sum_setoutbound\": \"${sum_setoutbound}\", \
\"sum_cntelements\": \"${sum_cntelements}\", \
\"sum_cntinbound\": \"${sum_cntinbound}\", \
\"sum_cntoutbound\": \"${sum_cntoutbound}\", \
\"sum_setports\": \"${sum_setports}\", \
\"sum_setelements\": \"${sum_setelements}\" \
}" >>"${report_jsn}"
fi
fi
@@ -1694,7 +1882,7 @@ f_report() {
#
if [ "${ban_nftcount}" = "1" ] && [ "${ban_map}" = "1" ] && [ -s "${report_jsn}" ]; then
cnt="1"
f_getfetch
f_getdl
json_init
if json_load_file "${ban_rtfile}" >/dev/null 2>&1; then
json_get_values jsnval "active_uplink" >/dev/null 2>&1
@@ -1768,6 +1956,7 @@ f_report() {
json_get_var sum_icmpflood "sum_icmpflood" >/dev/null 2>&1
json_get_var sum_ctinvalid "sum_ctinvalid" >/dev/null 2>&1
json_get_var sum_tcpinvalid "sum_tcpinvalid" >/dev/null 2>&1
json_get_var sum_bcp38 "sum_bcp38" >/dev/null 2>&1
json_get_var sum_sets "sum_sets" >/dev/null 2>&1
json_get_var sum_setinbound "sum_setinbound" >/dev/null 2>&1
json_get_var sum_setoutbound "sum_setoutbound" >/dev/null 2>&1
@@ -1785,6 +1974,7 @@ f_report() {
printf "%s\n" " blocked icmp-flood packets : ${sum_icmpflood}"
printf "%s\n" " blocked invalid ct packets : ${sum_ctinvalid}"
printf "%s\n" " blocked invalid tcp packets: ${sum_tcpinvalid}"
printf "%s\n" " blocked bcp38 packets : ${sum_bcp38}"
printf "%s\n" " ---"
printf "%s\n" " auto-added IPs to allowlist: ${autoadd_allow}"
printf "%s\n\n" " auto-added IPs to blocklist: ${autoadd_block}"
@@ -1957,90 +2147,131 @@ f_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"
printf "%b" "${ban_mailhead}${mail_text}" | "${ban_mailcmd}" --timeout=10 ${msmtp_debug} -a "${ban_mailprofile}" "${ban_mailreceiver}" >/dev/null 2>&1
f_log "debug" "f_mail ::: notification: ${ban_mailnotification}, template: ${ban_mailtemplate}, profile: ${ban_mailprofile}, receiver: ${ban_mailreceiver}, rc: ${?}"
f_log "debug" "f_mail ::: notification: ${ban_mailnotification}, template: ${ban_mailtemplate}, profile: ${ban_mailprofile}, receiver: ${ban_mailreceiver}, rc: ${?}"
}
# log monitor
#
f_monitor() {
local daemon logread_cmd loglimit_cmd nft_expiry line proto ip log_raw log_count idx prefix cidr rdap_log rdap_rc rdap_idx rdap_info
local daemon logread_cmd loglimit_cmd logread_filter nft_expiry line ip_proto ip proto log_count idx base cidr rdap_log rdap_rc rdap_idx rdap_info
if [ -f "${ban_logreadfile}" ]; then
logread_cmd="${ban_logreadcmd} -qf ${ban_logreadfile} 2>/dev/null | ${ban_grepcmd} -e \"${ban_logterm%%??}\" 2>/dev/null"
if [ -f "${ban_logreadfile}" ] && [ -x "${ban_logreadcmd}" ] && [ "${ban_logreadcmd##*/}" = "tail" ]; then
logread_cmd="${ban_logreadcmd} -qf ${ban_logreadfile} 2>/dev/null"
loglimit_cmd="${ban_logreadcmd} -qn ${ban_loglimit} ${ban_logreadfile} 2>/dev/null"
else
logread_cmd="${ban_logreadcmd} -fe \"${ban_logterm%%??}\" 2>/dev/null"
logread_filter="${ban_grepcmd} -e \"${ban_logterm}\" 2>/dev/null"
elif [ -x "${ban_logreadcmd}" ] && [ "${ban_logreadcmd##*/}" = "logread" ]; then
logread_cmd="${ban_logreadcmd} -fe \"${ban_logterm}\" 2>/dev/null"
loglimit_cmd="${ban_logreadcmd} -l ${ban_loglimit} 2>/dev/null"
logread_filter=""
fi
if [ -x "${ban_logreadcmd}" ] && [ -n "${logread_cmd}" ] && [ -n "${loglimit_cmd}" ] && [ -n "${ban_logterm%%??}" ] && [ "${ban_loglimit}" != "0" ]; then
if [ -n "${logread_cmd}" ] && [ -n "${loglimit_cmd}" ] && [ -n "${ban_logterm}" ] && [ "${ban_loglimit}" != "0" ]; then
f_log "info" "start detached banIP log service (${ban_logreadcmd})"
[ -n "${ban_nftexpiry}" ] && nft_expiry="timeout $(printf "%s" "${ban_nftexpiry}" | "${ban_grepcmd}" -oE "([0-9]+[d|h|m|s])+$")"
eval "${logread_cmd}" |
while read -r line; do
proto=""
: >"${ban_rdapfile}"
if [ -z "${daemon}" ]; then
daemon="$(printf "%s" "${line}" | "${ban_awkcmd}" 'BEGIN{RS="dropbear"}{if(!seen[RT]++)printf "%s",RT}')"
[ -z "${daemon}" ] && daemon="sshd"
fi
ip="$(printf "%s" "${line}" | "${ban_awkcmd}" 'BEGIN{RS="(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5]))+"}{if(!seen[RT]++)printf "%s ",RT}')"
ip="$(f_trim "${ip}")"
ip="${ip##* }"
[ -n "${ip}" ] && [ "${ip%%.*}" != "127" ] && [ "${ip%%.*}" != "0" ] && proto=".v4"
if [ -z "${proto}" ]; then
if [ "${daemon}" = "dropbear" ]; then
ip="$(printf "%s" "${line}" | "${ban_awkcmd}" 'BEGIN{RS="([A-Fa-f0-9]{1,4}::?){3,7}([A-Fa-f0-9]:?)+"}{if(!seen[RT]++)printf "%s ",RT}')"
ip="${ip%:*}"
# retrieve/cache current allowlist/blocklist content
#
allow_v4="$("${ban_nftcmd}" list set inet banIP allowlist.v4 2>/dev/null)"
allow_v6="$("${ban_nftcmd}" list set inet banIP allowlist.v6 2>/dev/null)"
block_v4="$("${ban_nftcmd}" list set inet banIP blocklist.v4 2>/dev/null)"
block_v6="$("${ban_nftcmd}" list set inet banIP blocklist.v6 2>/dev/null)"
# log monitoring loop
#
pipeline_cmd="${logread_cmd}"
[ -n "${logread_filter}" ] && pipeline_cmd="${pipeline_cmd} | ${logread_filter}"
eval "${pipeline_cmd}" | while read -r line; do
proto=""
base=""
: >"${ban_rdapfile}"
# IP detection
#
ip_proto=$(printf "%s" "${line}" | "${ban_awkcmd}" '
{
gsub(/[<>[\]]/, "", $0)
sub(/%.*/, "", $0)
sub(/:[0-9]+([ >]|$)/, "\\1", $0)
if (match($0, /([0-9]{1,3}\.){3}[0-9]{1,3}/, m4)) {
if (m4[0] !~ /^127\./ && m4[0] !~ /^0\./) {
print m4[0] " .v4"
exit
}
}
if (match($0, /([A-Fa-f0-9]{1,4}:){2,7}[A-Fa-f0-9]{1,4}/, m6)) {
if (m6[0] ~ /^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}$/) next
if (m6[0] !~ /^([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}$/) {
print m6[0] " .v6"
exit
}
}
}'
)
ip="${ip_proto% *}"
proto="${ip_proto#* }"
# process detected IP
#
if [ -n "${proto}" ]; then
case "${proto}" in
.v4)
case "${allow_v4} ${block_v4}" in
*" ${ip} "* )
continue
;;
esac
;;
.v6)
case "${allow_v6} ${block_v6}" in
*" ${ip} "* )
continue
;;
esac
;;
esac
f_log "info" "suspicious IP '${ip}'"
log_count="$(${loglimit_cmd} | "${ban_grepcmd}" -F -c "suspicious IP '${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" "add IP '${ip}' (expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set"
[ "${proto}" = ".v4" ] && block_v4="$("${ban_nftcmd}" list set inet banIP blocklist.v4 2>/dev/null)"
[ "${proto}" = ".v6" ] && block_v6="$("${ban_nftcmd}" list set inet banIP blocklist.v6 2>/dev/null)"
else
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}')"
f_log "info" "failed to add IP '${ip}' to blocklist${proto} set"
fi
ip="$(f_trim "${ip}")"
ip="${ip##* }"
[ -n "${ip%%::*}" ] && proto=".v6"
fi
if [ -n "${proto}" ] && ! "${ban_nftcmd}" get element inet banIP allowlist"${proto}" "{ ${ip} }" >/dev/null 2>&1 &&
! "${ban_nftcmd}" get element inet banIP blocklist"${proto}" "{ ${ip} }" >/dev/null 2>&1; then
f_log "info" "suspicious IP '${ip}'"
log_raw="$(eval ${loglimit_cmd})"
log_count="$(printf "%s\n" "${log_raw}" | "${ban_grepcmd}" -c "suspicious IP '${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" "add IP '${ip}' (expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set"
fi
if [ "${ban_autoblocksubnet}" = "1" ]; then
rdap_log="$("${ban_fetchcmd}" ${ban_rdapparm} "${ban_rdapfile}" "${ban_rdapurl}${ip}" 2>&1)"
rdap_rc="${?}"
if [ "${rdap_rc}" = "0" ] && [ -s "${ban_rdapfile}" ]; then
[ "${proto}" = ".v4" ] && rdap_idx="$("${ban_jsoncmd}" -i "${ban_rdapfile}" -qe '@.cidr0_cidrs[@.v4prefix].*' | "${ban_awkcmd}" '{ORS=" "; print}')"
[ "${proto}" = ".v6" ] && rdap_idx="$("${ban_jsoncmd}" -i "${ban_rdapfile}" -qe '@.cidr0_cidrs[@.v6prefix].*' | "${ban_awkcmd}" '{ORS=" "; print}')"
rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}" -qe '@.country' -qe '@.notices[@.title="Source"].description[1]' | "${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s",$1,$2}')"
[ -z "${rdap_info}" ] && rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}" -qe '@.notices[0].links[0].value' | "${ban_awkcmd}" 'BEGIN{FS="[/.]"}{printf"%s, %s","n/a",toupper($4)}')"
for idx in ${rdap_idx}; do
if [ -z "${prefix}" ]; then
prefix="${idx}"
continue
else
if [ -n "${prefix%%::*}" ] && [ "${prefix%%.*}" != "127" ] && [ "${prefix%%.*}" != "0" ]; then
cidr="${prefix}/${idx}"
if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" { ${cidr} ${nft_expiry} } >/dev/null 2>&1; then
f_log "info" "add IP range '${cidr}' (source: ${rdap_info:-"n/a"} ::: expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set"
fi
if [ "${ban_autoblocksubnet}" = "1" ]; then
rdap_log="$("${ban_fetchcmd}" ${ban_rdapparm} "${ban_rdapfile}" "${ban_rdapurl}${ip}" 2>&1)"
rdap_rc="${?}"
if [ "${rdap_rc}" = "0" ] && [ -s "${ban_rdapfile}" ]; then
[ "${proto}" = ".v4" ] && rdap_idx="$("${ban_jsoncmd}" -i "${ban_rdapfile}" -qe '@.cidr0_cidrs[@.v4prefix].*' | "${ban_awkcmd}" '{ORS=" "; print}')"
[ "${proto}" = ".v6" ] && rdap_idx="$("${ban_jsoncmd}" -i "${ban_rdapfile}" -qe '@.cidr0_cidrs[@.v6prefix].*' | "${ban_awkcmd}" '{ORS=" "; print}')"
rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}" -qe '@.country' -qe '@.notices[@.title="Source"].description[1]' | "${ban_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s",$1,$2}')"
[ -z "${rdap_info}" ] && rdap_info="$("${ban_jsoncmd}" -l1 -i "${ban_rdapfile}" -qe '@.notices[0].links[0].value' | "${ban_awkcmd}" 'BEGIN{FS="[/.]"}{printf"%s, %s","n/a",toupper($4)}')"
for idx in ${rdap_idx}; do
if [ -z "${base}" ]; then
base="${idx}"
continue
else
if [ -n "${base%%::*}" ] && [ "${base%%.*}" != "127" ] && [ "${base%%.*}" != "0" ]; then
cidr="${base}/${idx}"
if "${ban_nftcmd}" add element inet banIP "blocklist${proto}" { ${cidr} ${nft_expiry} } >/dev/null 2>&1; then
f_log "info" "add IP range '${cidr}' (source: ${rdap_info:-"n/a"} ::: expiry: ${ban_nftexpiry:-"-"}) to blocklist${proto} set"
fi
prefix=""
fi
done
else
f_log "info" "rdap request failed (rc: ${rdap_rc:-"-"}/log: ${rdap_log})"
fi
fi
if [ -z "${ban_nftexpiry}" ] && [ "${ban_autoblocklist}" = "1" ] && ! "${ban_grepcmd}" -q "^${ip}" "${ban_blocklist}"; then
printf "%-45s%s\n" "${ip}" "# added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_blocklist}"
f_log "info" "add IP '${ip}' to local blocklist"
base=""
fi
done
else
f_log "info" "rdap request failed (rc: ${rdap_rc:-"-"}/log: ${rdap_log})"
fi
fi
if [ -z "${ban_nftexpiry}" ] && [ "${ban_autoblocklist}" = "1" ] && ! "${ban_grepcmd}" -q "^${ip}" "${ban_blocklist}"; then
printf "%-45s%s\n" "${ip}" "# added on $(date "+%Y-%m-%d %H:%M:%S")" >>"${ban_blocklist}"
f_log "info" "add IP '${ip}' to local blocklist"
fi
fi
done
fi
done
else
f_log "info" "start detached no-op banIP service"
sleep infinity

View File

@@ -1,6 +1,6 @@
#!/bin/sh
# banIP main service script - ban incoming and outgoing IPs via named nftables Sets
# Copyright (c) 2018-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2018-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions
@@ -18,10 +18,10 @@ f_conf
f_log "info" "start banIP processing (${ban_action}, ${ban_bver:-"n/a"})"
f_genstatus "processing"
f_tmp
f_getfetch
f_getdl
f_getif
f_getdev
f_getuplink
f_getup
f_mkdir "${ban_backupdir}"
f_mkfile "${ban_allowlist}"
f_mkfile "${ban_blocklist}"
@@ -74,7 +74,7 @@ for feed in allowlist ${ban_feed} blocklist; do
uci_commit "banip"
continue
fi
json_objects="url_4 rule_4 url_6 rule_6 chain flag"
json_objects="url_4 url_6 rule chain flag"
for object in ${json_objects}; do
eval json_get_var feed_"${object}" '${object}' >/dev/null 2>&1
done
@@ -82,46 +82,47 @@ for feed in allowlist ${ban_feed} blocklist; do
# skip incomplete feeds
#
if { { [ -n "${feed_url_4}" ] && [ -z "${feed_rule_4}" ]; } || { [ -z "${feed_url_4}" ] && [ -n "${feed_rule_4}" ]; }; } ||
{ { [ -n "${feed_url_6}" ] && [ -z "${feed_rule_6}" ]; } || { [ -z "${feed_url_6}" ] && [ -n "${feed_rule_6}" ]; }; } ||
{ [ -z "${feed_url_4}" ] && [ -z "${feed_rule_4}" ] && [ -z "${feed_url_6}" ] && [ -z "${feed_rule_6}" ]; }; then
if { [ -z "$feed_url_4" ] && [ -z "$feed_url_6" ]; } || \
{ { [ -n "$feed_url_4" ] || [ -n "$feed_url_6" ]; } && [ -z "$feed_rule" ]; }; then
f_log "info" "skip incomplete feed '${feed}'"
continue
fi
# handle IPv4/IPv6 feeds
#
if [ "${ban_protov4}" = "1" ] && [ -n "${feed_url_4}" ] && [ -n "${feed_rule_4}" ]; then
if [ "${ban_protov4}" = "1" ] && [ -n "${feed_url_4}" ] && [ -n "${feed_rule}" ]; then
feed_ipv="4"
if [ "${feed}" = "country" ] && [ "${ban_countrysplit}" = "1" ]; then
for country in ${ban_country}; do
f_down "${feed}.${country}" "4" "${feed_url_4}" "${feed_rule_4}" "${feed_chain:-"in"}" "${feed_flag}"
f_down "${feed}.${country}" "${feed_ipv}" "${feed_url_4}" "${feed_rule}" "${feed_chain:-"in"}" "${feed_flag}"
done
elif [ "${feed}" = "asn" ] && [ "${ban_asnsplit}" = "1" ]; then
for asn in ${ban_asn}; do
f_down "${feed}.${asn}" "4" "${feed_url_4}" "${feed_rule_4}" "${feed_chain:-"in"}" "${feed_flag}"
f_down "${feed}.${asn}" "${feed_ipv}" "${feed_url_4}" "${feed_rule}" "${feed_chain:-"in"}" "${feed_flag}"
done
else
if [ "${feed_url_4}" = "${feed_url_6}" ]; then
feed_url_6="local"
f_down "${feed}" "4" "${feed_url_4}" "${feed_rule_4}" "${feed_chain:-"in"}" "${feed_flag}"
f_down "${feed}" "${feed_ipv}" "${feed_url_4}" "${feed_rule}" "${feed_chain:-"in"}" "${feed_flag}"
else
(f_down "${feed}" "4" "${feed_url_4}" "${feed_rule_4}" "${feed_chain:-"in"}" "${feed_flag}") &
(f_down "${feed}" "${feed_ipv}" "${feed_url_4}" "${feed_rule}" "${feed_chain:-"in"}" "${feed_flag}") &
[ "${cnt}" -gt "${ban_cores}" ] && wait -n
cnt="$((cnt + 1))"
fi
fi
fi
if [ "${ban_protov6}" = "1" ] && [ -n "${feed_url_6}" ] && [ -n "${feed_rule_6}" ]; then
if [ "${ban_protov6}" = "1" ] && [ -n "${feed_url_6}" ] && [ -n "${feed_rule}" ]; then
feed_ipv="6"
if [ "${feed}" = "country" ] && [ "${ban_countrysplit}" = "1" ]; then
for country in ${ban_country}; do
f_down "${feed}.${country}" "6" "${feed_url_6}" "${feed_rule_6}" "${feed_chain:-"in"}" "${feed_flag}"
f_down "${feed}.${country}" "${feed_ipv}" "${feed_url_6}" "${feed_rule}" "${feed_chain:-"in"}" "${feed_flag}"
done
elif [ "${feed}" = "asn" ] && [ "${ban_asnsplit}" = "1" ]; then
for asn in ${ban_asn}; do
f_down "${feed}.${asn}" "6" "${feed_url_6}" "${feed_rule_6}" "${feed_chain:-"in"}" "${feed_flag}"
f_down "${feed}.${asn}" "${feed_ipv}" "${feed_url_6}" "${feed_rule}" "${feed_chain:-"in"}" "${feed_flag}"
done
else
(f_down "${feed}" "6" "${feed_url_6}" "${feed_rule_6}" "${feed_chain:-"in"}" "${feed_flag}") &
(f_down "${feed}" "${feed_ipv}" "${feed_url_6}" "${feed_rule}" "${feed_chain:-"in"}" "${feed_flag}") &
[ "${cnt}" -gt "${ban_cores}" ] && wait -n
cnt="$((cnt + 1))"
fi

View File

@@ -1,6 +1,6 @@
#!/bin/sh
# banIP cgi remote logging script - ban incoming and outgoing IPs via named nftables Sets
# Copyright (c) 2018-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2018-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions

View File

@@ -2,71 +2,66 @@
"asn":{
"url_4": "https://asn.ipinfo.app/api/text/list/",
"url_6": "https://asn.ipinfo.app/api/text/list/",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "ASN IP segments"
},
"backscatterer":{
"url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/ips.backscatterer.org.gz",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "backscatterer IPs",
"flag": "gz"
},
"becyber":{
"url_4": "https://raw.githubusercontent.com/duggytuxy/Data-Shield_IPv4_Blocklist/refs/heads/main/prod_data-shield_ipv4_blocklist.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "malicious attacker IPs"
},
"binarydefense":{
"url_4": "https://iplists.firehol.org/files/bds_atif.ipset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "binary defense banlist"
},
"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": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "bogon prefixes"
},
"bruteforceblock":{
"url_4": "https://danger.rulez.sk/projects/bruteforceblocker/blist.php",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "bruteforceblocker IPs"
},
"cinsscore":{
"url_4": "https://cinsscore.com/list/ci-badguys.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "suspicious attacker IPs"
},
"country":{
"url_4": "https://www.ipdeny.com/ipblocks/data/aggregated/",
"url_6": "https://www.ipdeny.com/ipv6/ipaddresses/aggregated/",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "country blocks"
},
"debl":{
"url_4": "https://lists.blocklist.de/lists/all.txt",
"url_6": "https://lists.blocklist.de/lists/all.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "fail2ban IP blocklist"
},
"dns":{
"url_4": "https://public-dns.info/nameservers-all.txt",
"url_6": "https://public-dns.info/nameservers-all.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "out",
"descr": "public DNS-Server",
"flag": "tcp udp 53 853"
@@ -74,8 +69,7 @@
"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": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "out",
"descr": "public DoH-Server",
"flag": "tcp udp 80 443"
@@ -83,81 +77,86 @@
"drop":{
"url_4": "https://www.spamhaus.org/drop/drop.txt",
"url_6": "https://www.spamhaus.org/drop/dropv6.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "spamhaus drop compilation"
},
"dshield":{
"url_4": "https://feeds.dshield.org/block.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 13",
"chain": "in",
"descr": "dshield IP blocklist"
},
"etcompromised":{
"url_4": "https://iplists.firehol.org/files/et_compromised.ipset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "ET compromised hosts"
},
"feodo":{
"url_4": "https://feodotracker.abuse.ch/downloads/ipblocklist.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "feodo tracker"
},
"firehol1":{
"url_4": "https://iplists.firehol.org/files/firehol_level1.netset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "firehol level 1 compilation"
},
"firehol2":{
"url_4": "https://iplists.firehol.org/files/firehol_level2.netset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "firehol level 2 compilation"
},
"firehol3":{
"url_4": "https://iplists.firehol.org/files/firehol_level3.netset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "firehol level 3 compilation"
},
"firehol4":{
"url_4": "https://iplists.firehol.org/files/firehol_level4.netset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "firehol level 4 compilation"
},
"greensnow":{
"url_4": "https://blocklist.greensnow.co/greensnow.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "suspicious server IPs"
},
"hagezi":{
"url_4": "https://raw.githubusercontent.com/hagezi/dns-blocklists/refs/heads/main/ips/tif.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "out",
"descr": "Threat IP blocklist",
"flag": "tcp udp 80 443"
},
"ipblackhole":{
"url_4": "https://blackhole.s-e-r-v-e-r.pw/blackhole-today",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"url_4": "https://blackhole.monster/blackhole-today",
"rule": "feed 1",
"chain": "in",
"descr": "blackhole IP blocklist"
},
"ipexdbl":{
"url_4": "https://raw.githubusercontent.com/ZEROF/ipextractor/main/ipexdbl.txt",
"rule": "feed 1",
"chain": "in",
"descr": "IPEX dynamic blocklists"
},
"ipsum":{
"url_4": "https://raw.githubusercontent.com/stamparm/ipsum/master/levels/3.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "malicious IPs"
},
"ipthreat":{
"url_4": "https://lists.ipthreat.net/file/ipthreat-lists/threat/threat-30.txt.gz",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "hacker and botnet IPs",
"flag": "gz"
@@ -165,112 +164,103 @@
"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": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "real-time IP blocklist"
},
"nixspam":{
"url_4": "https://www.nixspam.net/download/nixspam-ip.dump.gz",
"rule_4": "/127\\./{next}/(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "iX spam protection",
"flag": "gz"
},
"pallebone":{
"url_4": "https://raw.githubusercontent.com/pallebone/StrictBlockPAllebone/master/BlockIP.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"chain": "in",
"descr": "curated IP blocklist"
},
"proxy":{
"url_4": "https://iplists.firehol.org/files/proxylists.ipset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "open proxies"
},
"threat":{
"url_4": "https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "emerging threats"
},
"threatview":{
"url_4": "https://threatview.io/Downloads/IP-High-Confidence-Feed.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "malicious IPs"
},
"tor":{
"url_4": "https://www.dan.me.uk/torlist/?exit",
"url_6": "https://www.dan.me.uk/torlist/?exit",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "tor exit nodes"
},
"turris":{
"url_4": "https://view.sentinel.turris.cz/greylist-data/greylist-latest.csv",
"url_6": "https://view.sentinel.turris.cz/greylist-data/greylist-latest.csv",
"rule_4": "BEGIN{FS=\",\"}/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "BEGIN{FS=\",\"}/^(([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}",
"rule": "feed 1 ,",
"chain": "in",
"descr": "turris sentinel blocklist"
},
"uceprotect1":{
"url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/dnsbl-1.uceprotect.net.gz",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "spam protection level 1",
"flag": "gz"
},
"uceprotect2":{
"url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/dnsbl-2.uceprotect.net.gz",
"rule_4": "BEGIN{IGNORECASE=1}/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "spam protection level 2",
"flag": "gz"
},
"uceprotect3":{
"url_4": "http://wget-mirrors.uceprotect.net/rbldnsd-all/dnsbl-3.uceprotect.net.gz",
"rule_4": "BEGIN{IGNORECASE=1}/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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}",
"rule": "feed 1",
"chain": "in",
"descr": "spam protection level 3",
"flag": "gz"
},
"urlhaus":{
"url_4": "https://urlhaus.abuse.ch/downloads/ids/",
"rule_4": "BEGIN{FS=\";\"}/content:\"127\\./{next}/(content:\"([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\")/{printf \"%s,\\n\",substr($10,11,length($10)-11)}",
"rule": "suricata 1",
"chain": "in",
"descr": "urlhaus IDS IPs"
},
"urlvir":{
"url_4": "https://iplists.firehol.org/files/urlvir.ipset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "malware related IPs"
},
"voip":{
"url_4": "https://voipbl.org/update/",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "VoIP fraud blocklist"
},
"vpn":{
"url_4": "https://raw.githubusercontent.com/X4BNet/lists_vpn/refs/heads/main/output/vpn/ipv4.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "vpn IPs"
},
"vpndc":{
"url_4": "https://raw.githubusercontent.com/X4BNet/lists_vpn/refs/heads/main/output/datacenter/ipv4.txt",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "vpn datacenter IPs"
},
"webclient":{
"url_4": "https://iplists.firehol.org/files/firehol_webclient.netset",
"rule_4": "/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(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": "feed 1",
"chain": "in",
"descr": "malware related IPs"
}

View File

@@ -1,6 +1,6 @@
#!/bin/sh /etc/rc.common
# banIP init script - ban incoming and outgoing IPs via named nftables Sets
# Copyright (c) 2018-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2018-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions

View File

@@ -1,14 +1,14 @@
# banIP mail template/include - ban incoming and outgoing IPs via named nftables Sets
# Copyright (c) 2018-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2018-2026 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 logread_cmd
if [ -f "${ban_logreadfile}" ]; then
if [ -f "${ban_logreadfile}" ] && [ -x "${ban_logreadcmd}" ] && [ "${ban_logreadcmd##*/}" = "tail" ]; then
logread_cmd="${ban_logreadcmd} -qn ${ban_loglimit} ${ban_logreadfile} 2>/dev/null | ${ban_grepcmd} -e \"banIP/\" 2>/dev/null"
elif printf "%s" "${ban_packages}" | "${ban_grepcmd}" -q '"logd'; then
elif [ -x "${ban_logreadcmd}" ] && [ "${ban_logreadcmd##*/}" = "logread" ]; then
logread_cmd="${ban_logreadcmd} -l ${ban_loglimit} -e "banIP/" 2>/dev/null"
fi