|
#!/usr/bin/env bash |
|
set -euo pipefail |
|
|
|
exec 9>/run/block-scanners.lock |
|
flock -n 9 || { |
|
echo "[WARN] another block-scanners instance is already running" |
|
exit 0 |
|
} |
|
|
|
MODE="${1:-input-only}" # supported: input-only |
|
AUTO_INSTALL="${AUTO_INSTALL:-1}" |
|
|
|
IPSET_V4_IP="scanner_v4_ip" |
|
IPSET_V4_NET="scanner_v4_net" |
|
IPSET_V6_NET="scanner_v6_net" |
|
|
|
ALLOW_V4_IP="allow_v4_ip" |
|
ALLOW_V4_NET="allow_v4_net" |
|
ALLOW_V6_NET="allow_v6_net" |
|
|
|
CHAIN_V4="BLOCK_SCANNERS_V4" |
|
CHAIN_V6="BLOCK_SCANNERS_V6" |
|
|
|
CONFIG_DIR="/etc/block-scanners" |
|
TMPDIR="$(mktemp -d)" |
|
trap 'rm -rf "$TMPDIR"' EXIT |
|
|
|
log() { echo "[INFO] $*"; } |
|
warn() { echo "[WARN] $*" >&2; } |
|
err() { echo "[ERROR] $*" >&2; } |
|
|
|
has_cmd() { |
|
command -v "$1" >/dev/null 2>&1 |
|
} |
|
|
|
detect_pkg_manager() { |
|
if has_cmd apt-get; then |
|
echo "apt" |
|
elif has_cmd dnf; then |
|
echo "dnf" |
|
elif has_cmd yum; then |
|
echo "yum" |
|
else |
|
echo "unknown" |
|
fi |
|
} |
|
|
|
install_if_missing() { |
|
local missing=() |
|
|
|
has_cmd ipset || missing+=("ipset") |
|
has_cmd iptables || missing+=("iptables") |
|
has_cmd ip6tables || missing+=("iptables") |
|
has_cmd curl || missing+=("curl") |
|
has_cmd awk || missing+=("awk") |
|
has_cmd sed || missing+=("sed") |
|
has_cmd sort || missing+=("sort") |
|
has_cmd grep || missing+=("grep") |
|
|
|
if [[ ${#missing[@]} -eq 0 ]]; then |
|
log "All required commands already exist." |
|
return 0 |
|
fi |
|
|
|
if [[ "$AUTO_INSTALL" != "1" ]]; then |
|
err "Missing commands and AUTO_INSTALL=0: ${missing[*]}" |
|
exit 1 |
|
fi |
|
|
|
local pm |
|
pm="$(detect_pkg_manager)" |
|
|
|
case "$pm" in |
|
apt) |
|
export DEBIAN_FRONTEND=noninteractive |
|
log "Installing missing packages via apt-get..." |
|
apt-get update |
|
apt-get install -y ipset iptables curl gawk sed coreutils grep |
|
;; |
|
dnf) |
|
log "Installing missing packages via dnf..." |
|
dnf install -y ipset iptables curl gawk sed coreutils grep |
|
;; |
|
yum) |
|
log "Installing missing packages via yum..." |
|
yum install -y ipset iptables curl gawk sed coreutils grep |
|
;; |
|
*) |
|
err "Unsupported package manager. Please install manually: ipset iptables curl awk sed sort grep" |
|
exit 1 |
|
;; |
|
esac |
|
} |
|
|
|
require_cmds() { |
|
local required=(ipset iptables ip6tables curl awk sed sort grep) |
|
for c in "${required[@]}"; do |
|
has_cmd "$c" || { err "Missing command after install step: $c"; exit 1; } |
|
done |
|
} |
|
|
|
ensure_config_dir() { |
|
mkdir -p "$CONFIG_DIR" |
|
|
|
[[ -f "$CONFIG_DIR/allow_v4_ip.txt" ]] || cat > "$CONFIG_DIR/allow_v4_ip.txt" <<'EOT' |
|
# One IPv4 per line |
|
# 1.2.3.4 |
|
EOT |
|
|
|
[[ -f "$CONFIG_DIR/allow_v4_net.txt" ]] || cat > "$CONFIG_DIR/allow_v4_net.txt" <<'EOT' |
|
# One IPv4 CIDR per line |
|
# 10.10.10.0/24 |
|
EOT |
|
|
|
[[ -f "$CONFIG_DIR/allow_v6_net.txt" ]] || cat > "$CONFIG_DIR/allow_v6_net.txt" <<'EOT' |
|
# One IPv6 CIDR per line |
|
# 2001:db8::/64 |
|
EOT |
|
} |
|
|
|
valid_ipv4() { |
|
local ip="$1" |
|
local a b c d |
|
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || return 1 |
|
IFS='.' read -r a b c d <<< "$ip" |
|
for octet in "$a" "$b" "$c" "$d"; do |
|
[[ "$octet" =~ ^[0-9]+$ ]] || return 1 |
|
(( octet >= 0 && octet <= 255 )) || return 1 |
|
done |
|
return 0 |
|
} |
|
|
|
valid_ipv4_cidr() { |
|
local cidr="$1" |
|
local ip prefix |
|
[[ "$cidr" == */* ]] || return 1 |
|
ip="${cidr%/*}" |
|
prefix="${cidr#*/}" |
|
valid_ipv4 "$ip" || return 1 |
|
[[ "$prefix" =~ ^[0-9]+$ ]] || return 1 |
|
(( prefix >= 0 && prefix <= 32 )) || return 1 |
|
return 0 |
|
} |
|
|
|
valid_ipv6_cidr() { |
|
local cidr="$1" |
|
local ip prefix |
|
[[ "$cidr" == */* ]] || return 1 |
|
ip="${cidr%/*}" |
|
prefix="${cidr#*/}" |
|
|
|
[[ "$ip" == *:* ]] || return 1 |
|
[[ "$prefix" =~ ^[0-9]+$ ]] || return 1 |
|
(( prefix >= 0 && prefix <= 128 )) || return 1 |
|
|
|
if has_cmd python3; then |
|
python3 - "$cidr" <<'PY' >/dev/null 2>&1 |
|
import ipaddress, sys |
|
try: |
|
ipaddress.ip_network(sys.argv[1], strict=False) |
|
sys.exit(0) |
|
except Exception: |
|
sys.exit(1) |
|
PY |
|
return $? |
|
fi |
|
|
|
[[ "$ip" =~ ^[0-9A-Fa-f:]+$ ]] || return 1 |
|
return 0 |
|
} |
|
|
|
create_sets() { |
|
ipset create "$IPSET_V4_IP" hash:ip family inet maxelem 600000 -exist |
|
ipset create "$IPSET_V4_NET" hash:net family inet maxelem 220000 -exist |
|
ipset create "$IPSET_V6_NET" hash:net family inet6 maxelem 131072 -exist |
|
|
|
ipset create "$ALLOW_V4_IP" hash:ip family inet maxelem 4096 -exist |
|
ipset create "$ALLOW_V4_NET" hash:net family inet maxelem 4096 -exist |
|
ipset create "$ALLOW_V6_NET" hash:net family inet6 maxelem 4096 -exist |
|
} |
|
|
|
ensure_chains_input_only() { |
|
iptables -L "$CHAIN_V4" -n >/dev/null 2>&1 || iptables -N "$CHAIN_V4" |
|
ip6tables -L "$CHAIN_V6" -n >/dev/null 2>&1 || ip6tables -N "$CHAIN_V6" |
|
|
|
iptables -C INPUT -j "$CHAIN_V4" 2>/dev/null || iptables -I INPUT 1 -j "$CHAIN_V4" |
|
ip6tables -C INPUT -j "$CHAIN_V6" 2>/dev/null || ip6tables -I INPUT 1 -j "$CHAIN_V6" |
|
} |
|
|
|
rebuild_chain_rules_input_only() { |
|
ensure_chains_input_only |
|
|
|
iptables -F "$CHAIN_V4" |
|
ip6tables -F "$CHAIN_V6" |
|
|
|
iptables -A "$CHAIN_V4" -m set --match-set "$ALLOW_V4_IP" src -j ACCEPT |
|
iptables -A "$CHAIN_V4" -m set --match-set "$ALLOW_V4_NET" src -j ACCEPT |
|
iptables -A "$CHAIN_V4" -m set --match-set "$IPSET_V4_IP" src -j DROP |
|
iptables -A "$CHAIN_V4" -m set --match-set "$IPSET_V4_NET" src -j DROP |
|
iptables -A "$CHAIN_V4" -j RETURN |
|
|
|
ip6tables -A "$CHAIN_V6" -m set --match-set "$ALLOW_V6_NET" src -j ACCEPT |
|
ip6tables -A "$CHAIN_V6" -m set --match-set "$IPSET_V6_NET" src -j DROP |
|
ip6tables -A "$CHAIN_V6" -j RETURN |
|
} |
|
|
|
attach_rules() { |
|
case "$MODE" in |
|
input-only) |
|
rebuild_chain_rules_input_only |
|
;; |
|
*) |
|
err "Unsupported MODE: $MODE" |
|
exit 1 |
|
;; |
|
esac |
|
} |
|
|
|
fetch_lists() { |
|
cat > "$TMPDIR/censys_v4.txt" <<'EOT' |
|
66.132.159.0/24 |
|
162.142.125.0/24 |
|
167.94.138.0/24 |
|
167.94.145.0/24 |
|
167.94.146.0/24 |
|
167.248.133.0/24 |
|
199.45.154.0/24 |
|
199.45.155.0/24 |
|
206.168.34.0/24 |
|
206.168.35.0/24 |
|
EOT |
|
|
|
cat > "$TMPDIR/censys_v6.txt" <<'EOT' |
|
2602:80d:1000:b0cc:e::/80 |
|
2620:96:e000:b0cc:e::/80 |
|
2602:80d:1003::/112 |
|
2602:80d:1004::/112 |
|
EOT |
|
|
|
cat > "$TMPDIR/driftnet_v4.txt" <<'EOT' |
|
87.236.176.0/24 |
|
193.163.125.0/24 |
|
68.183.53.77/32 |
|
104.248.203.191/32 |
|
104.248.204.195/32 |
|
142.93.191.98/32 |
|
157.245.216.203/32 |
|
165.22.39.64/32 |
|
167.99.209.184/32 |
|
188.166.26.88/32 |
|
206.189.7.178/32 |
|
209.97.152.248/32 |
|
EOT |
|
|
|
cat > "$TMPDIR/driftnet_v6.txt" <<'EOT' |
|
2a06:4880::/32 |
|
2604:a880:800:10::c4b:f000/124 |
|
2604:a880:800:10::c51:a000/124 |
|
2604:a880:800:10::c52:d000/124 |
|
2604:a880:800:10::c55:5000/124 |
|
2604:a880:800:10::c56:b000/124 |
|
2a03:b0c0:2:d0::153e:a000/124 |
|
2a03:b0c0:2:d0::1576:8000/124 |
|
2a03:b0c0:2:d0::1577:7000/124 |
|
2a03:b0c0:2:d0::1579:e000/124 |
|
2a03:b0c0:2:d0::157c:a000/124 |
|
EOT |
|
|
|
curl -fsSL "https://scanner.modat.io/ipv4.txt" > "$TMPDIR/modat_v4.txt" |
|
|
|
curl -fsSL \ |
|
"https://raw.githubusercontent.com/gazpitchy92/ip-blocklist/refs/heads/main/list/blacklist.txt" \ |
|
> "$TMPDIR/gaz_list_v4.txt" |
|
|
|
curl -fsSL \ |
|
"https://raw.githubusercontent.com/gazpitchy92/ip-blocklist/refs/heads/main/range/blacklist.txt" \ |
|
> "$TMPDIR/gaz_range_v4.txt" |
|
} |
|
|
|
normalize() { |
|
sed 's/#.*$//' "$1" | tr -d '\r' | sed '/^$/d' | sort -u > "$2" |
|
} |
|
|
|
split_v4_ip_and_net() { |
|
local infile="$1" |
|
local out_ip="$2" |
|
local out_net="$3" |
|
|
|
: > "$out_ip" |
|
: > "$out_net" |
|
|
|
while read -r item; do |
|
[[ -z "$item" ]] && continue |
|
if valid_ipv4 "$item"; then |
|
echo "$item" >> "$out_ip" |
|
elif valid_ipv4_cidr "$item"; then |
|
echo "$item" >> "$out_net" |
|
fi |
|
done < "$infile" |
|
|
|
sort -u -o "$out_ip" "$out_ip" |
|
sort -u -o "$out_net" "$out_net" |
|
} |
|
|
|
filter_v6_net() { |
|
local infile="$1" |
|
local outfile="$2" |
|
|
|
: > "$outfile" |
|
while read -r item; do |
|
[[ -z "$item" ]] && continue |
|
if valid_ipv6_cidr "$item"; then |
|
echo "$item" >> "$outfile" |
|
fi |
|
done < "$infile" |
|
|
|
sort -u -o "$outfile" "$outfile" |
|
} |
|
|
|
write_ipset_restore_create_file() { |
|
local outfile="$1" |
|
local setname="$2" |
|
local settype="$3" |
|
local family="$4" |
|
local maxelem="$5" |
|
local infile="$6" |
|
|
|
{ |
|
echo "create ${setname} ${settype} family ${family} maxelem ${maxelem}" |
|
while read -r item; do |
|
[[ -z "$item" ]] && continue |
|
echo "add ${setname} ${item}" |
|
done < "$infile" |
|
} > "$outfile" |
|
} |
|
|
|
load_ipset_restore_file() { |
|
local restore_file="$1" |
|
ipset restore < "$restore_file" |
|
} |
|
|
|
build_sets() { |
|
normalize "$CONFIG_DIR/allow_v4_ip.txt" "$TMPDIR/all_allow_v4_ip.txt" |
|
normalize "$CONFIG_DIR/allow_v4_net.txt" "$TMPDIR/all_allow_v4_net.txt" |
|
normalize "$CONFIG_DIR/allow_v6_net.txt" "$TMPDIR/all_allow_v6_net.txt" |
|
|
|
cat \ |
|
"$TMPDIR/modat_v4.txt" \ |
|
"$TMPDIR/gaz_list_v4.txt" \ |
|
> "$TMPDIR/v4_ip_candidates_raw.txt" |
|
|
|
cat \ |
|
"$TMPDIR/censys_v4.txt" \ |
|
"$TMPDIR/gaz_range_v4.txt" \ |
|
"$TMPDIR/driftnet_v4.txt" \ |
|
> "$TMPDIR/v4_net_candidates_raw.txt" |
|
|
|
cat \ |
|
"$TMPDIR/censys_v6.txt" \ |
|
"$TMPDIR/driftnet_v6.txt" \ |
|
> "$TMPDIR/v6_net_candidates_raw.txt" |
|
|
|
normalize "$TMPDIR/v4_ip_candidates_raw.txt" "$TMPDIR/v4_ip_candidates.txt" |
|
normalize "$TMPDIR/v4_net_candidates_raw.txt" "$TMPDIR/v4_net_candidates.txt" |
|
normalize "$TMPDIR/v6_net_candidates_raw.txt" "$TMPDIR/v6_net_candidates.txt" |
|
|
|
split_v4_ip_and_net "$TMPDIR/v4_ip_candidates.txt" "$TMPDIR/v4_ip_final.txt" "$TMPDIR/v4_net_from_ipfeed.txt" |
|
split_v4_ip_and_net "$TMPDIR/v4_net_candidates.txt" "$TMPDIR/v4_ip_from_netfeed.txt" "$TMPDIR/v4_net_final.txt" |
|
filter_v6_net "$TMPDIR/v6_net_candidates.txt" "$TMPDIR/v6_net_final.txt" |
|
filter_v6_net "$TMPDIR/all_allow_v6_net.txt" "$TMPDIR/all_allow_v6_net_filtered.txt" |
|
|
|
cat "$TMPDIR/v4_ip_final.txt" "$TMPDIR/v4_ip_from_netfeed.txt" | sort -u > "$TMPDIR/all_v4_ip.txt" |
|
cat "$TMPDIR/v4_net_final.txt" "$TMPDIR/v4_net_from_ipfeed.txt" | sort -u > "$TMPDIR/all_v4_net.txt" |
|
|
|
: > "$TMPDIR/all_allow_v4_ip_filtered.txt" |
|
while read -r item; do |
|
[[ -z "$item" ]] && continue |
|
valid_ipv4 "$item" && echo "$item" >> "$TMPDIR/all_allow_v4_ip_filtered.txt" |
|
done < "$TMPDIR/all_allow_v4_ip.txt" |
|
sort -u -o "$TMPDIR/all_allow_v4_ip_filtered.txt" "$TMPDIR/all_allow_v4_ip_filtered.txt" |
|
|
|
: > "$TMPDIR/all_allow_v4_net_filtered.txt" |
|
while read -r item; do |
|
[[ -z "$item" ]] && continue |
|
valid_ipv4_cidr "$item" && echo "$item" >> "$TMPDIR/all_allow_v4_net_filtered.txt" |
|
done < "$TMPDIR/all_allow_v4_net.txt" |
|
sort -u -o "$TMPDIR/all_allow_v4_net_filtered.txt" "$TMPDIR/all_allow_v4_net_filtered.txt" |
|
|
|
ipset destroy "${IPSET_V4_IP}_new" 2>/dev/null || true |
|
ipset destroy "${IPSET_V4_NET}_new" 2>/dev/null || true |
|
ipset destroy "${IPSET_V6_NET}_new" 2>/dev/null || true |
|
ipset destroy "${ALLOW_V4_IP}_new" 2>/dev/null || true |
|
ipset destroy "${ALLOW_V4_NET}_new" 2>/dev/null || true |
|
ipset destroy "${ALLOW_V6_NET}_new" 2>/dev/null || true |
|
|
|
write_ipset_restore_create_file \ |
|
"$TMPDIR/restore_scanner_v4_ip.txt" \ |
|
"${IPSET_V4_IP}_new" \ |
|
"hash:ip" \ |
|
"inet" \ |
|
"600000" \ |
|
"$TMPDIR/all_v4_ip.txt" |
|
|
|
write_ipset_restore_create_file \ |
|
"$TMPDIR/restore_scanner_v4_net.txt" \ |
|
"${IPSET_V4_NET}_new" \ |
|
"hash:net" \ |
|
"inet" \ |
|
"220000" \ |
|
"$TMPDIR/all_v4_net.txt" |
|
|
|
write_ipset_restore_create_file \ |
|
"$TMPDIR/restore_scanner_v6_net.txt" \ |
|
"${IPSET_V6_NET}_new" \ |
|
"hash:net" \ |
|
"inet6" \ |
|
"131072" \ |
|
"$TMPDIR/v6_net_final.txt" |
|
|
|
write_ipset_restore_create_file \ |
|
"$TMPDIR/restore_allow_v4_ip.txt" \ |
|
"${ALLOW_V4_IP}_new" \ |
|
"hash:ip" \ |
|
"inet" \ |
|
"4096" \ |
|
"$TMPDIR/all_allow_v4_ip_filtered.txt" |
|
|
|
write_ipset_restore_create_file \ |
|
"$TMPDIR/restore_allow_v4_net.txt" \ |
|
"${ALLOW_V4_NET}_new" \ |
|
"hash:net" \ |
|
"inet" \ |
|
"4096" \ |
|
"$TMPDIR/all_allow_v4_net_filtered.txt" |
|
|
|
write_ipset_restore_create_file \ |
|
"$TMPDIR/restore_allow_v6_net.txt" \ |
|
"${ALLOW_V6_NET}_new" \ |
|
"hash:net" \ |
|
"inet6" \ |
|
"4096" \ |
|
"$TMPDIR/all_allow_v6_net_filtered.txt" |
|
|
|
load_ipset_restore_file "$TMPDIR/restore_scanner_v4_ip.txt" |
|
load_ipset_restore_file "$TMPDIR/restore_scanner_v4_net.txt" |
|
load_ipset_restore_file "$TMPDIR/restore_scanner_v6_net.txt" |
|
load_ipset_restore_file "$TMPDIR/restore_allow_v4_ip.txt" |
|
load_ipset_restore_file "$TMPDIR/restore_allow_v4_net.txt" |
|
load_ipset_restore_file "$TMPDIR/restore_allow_v6_net.txt" |
|
|
|
ipset swap "${IPSET_V4_IP}_new" "$IPSET_V4_IP" |
|
ipset swap "${IPSET_V4_NET}_new" "$IPSET_V4_NET" |
|
ipset swap "${IPSET_V6_NET}_new" "$IPSET_V6_NET" |
|
ipset swap "${ALLOW_V4_IP}_new" "$ALLOW_V4_IP" |
|
ipset swap "${ALLOW_V4_NET}_new" "$ALLOW_V4_NET" |
|
ipset swap "${ALLOW_V6_NET}_new" "$ALLOW_V6_NET" |
|
|
|
ipset destroy "${IPSET_V4_IP}_new" |
|
ipset destroy "${IPSET_V4_NET}_new" |
|
ipset destroy "${IPSET_V6_NET}_new" |
|
ipset destroy "${ALLOW_V4_IP}_new" |
|
ipset destroy "${ALLOW_V4_NET}_new" |
|
ipset destroy "${ALLOW_V6_NET}_new" |
|
} |
|
|
|
persist_sets() { |
|
ipset save > /etc/ipset.conf |
|
} |
|
|
|
count_lines() { |
|
local file="$1" |
|
[[ -f "$file" ]] || { echo "0"; return 0; } |
|
grep -c . "$file" || true |
|
} |
|
|
|
show_feed_counts() { |
|
echo "==== feed source counts ====" |
|
echo "modat_v4 : $(count_lines "$TMPDIR/modat_v4.txt")" |
|
echo "gaz_list_v4 : $(count_lines "$TMPDIR/gaz_list_v4.txt")" |
|
echo "gaz_range_v4 : $(count_lines "$TMPDIR/gaz_range_v4.txt")" |
|
echo "censys_v4 : $(count_lines "$TMPDIR/censys_v4.txt")" |
|
echo "censys_v6 : $(count_lines "$TMPDIR/censys_v6.txt")" |
|
echo "driftnet_v4 : $(count_lines "$TMPDIR/driftnet_v4.txt")" |
|
echo "driftnet_v6 : $(count_lines "$TMPDIR/driftnet_v6.txt")" |
|
echo "normalized v4 ip : $(count_lines "$TMPDIR/all_v4_ip.txt")" |
|
echo "normalized v4 net : $(count_lines "$TMPDIR/all_v4_net.txt")" |
|
echo "normalized v6 net : $(count_lines "$TMPDIR/v6_net_final.txt")" |
|
} |
|
|
|
show_ipset_counts() { |
|
echo "==== ipset counts ====" |
|
ipset list "$IPSET_V4_IP" | awk '/Number of entries:/ {print "scanner_v4_ip :", $4}' |
|
ipset list "$IPSET_V4_NET" | awk '/Number of entries:/ {print "scanner_v4_net :", $4}' |
|
ipset list "$IPSET_V6_NET" | awk '/Number of entries:/ {print "scanner_v6_net :", $4}' |
|
ipset list "$ALLOW_V4_IP" | awk '/Number of entries:/ {print "allow_v4_ip :", $4}' |
|
ipset list "$ALLOW_V4_NET" | awk '/Number of entries:/ {print "allow_v4_net :", $4}' |
|
ipset list "$ALLOW_V6_NET" | awk '/Number of entries:/ {print "allow_v6_net :", $4}' |
|
} |
|
|
|
show_rules() { |
|
echo "==== iptables INPUT rules ====" |
|
iptables -L INPUT -n --line-numbers | sed -n '1,30p' |
|
echo |
|
echo "==== iptables ${CHAIN_V4} rules ====" |
|
iptables -L "$CHAIN_V4" -n --line-numbers | sed -n '1,30p' |
|
echo |
|
echo "==== ip6tables INPUT rules ====" |
|
ip6tables -L INPUT -n --line-numbers | sed -n '1,30p' |
|
echo |
|
echo "==== ip6tables ${CHAIN_V6} rules ====" |
|
ip6tables -L "$CHAIN_V6" -n --line-numbers | sed -n '1,30p' |
|
} |
|
|
|
show_hits() { |
|
echo "==== iptables INPUT counters ====" |
|
iptables -L INPUT -n -v --line-numbers | sed -n '1,30p' |
|
echo |
|
echo "==== iptables ${CHAIN_V4} counters ====" |
|
iptables -L "$CHAIN_V4" -n -v --line-numbers | sed -n '1,30p' |
|
echo |
|
echo "==== ip6tables INPUT counters ====" |
|
ip6tables -L INPUT -n -v --line-numbers | sed -n '1,30p' |
|
echo |
|
echo "==== ip6tables ${CHAIN_V6} counters ====" |
|
ip6tables -L "$CHAIN_V6" -n -v --line-numbers | sed -n '1,30p' |
|
} |
|
|
|
show_status() { |
|
show_feed_counts |
|
echo |
|
show_ipset_counts |
|
echo |
|
show_rules |
|
} |
|
|
|
show_debug_help() { |
|
cat <<EOF |
|
|
|
Useful commands: |
|
/usr/local/sbin/block-scanners.sh input-only |
|
|
|
Rules: |
|
iptables -L INPUT -n --line-numbers |
|
iptables -L ${CHAIN_V4} -n --line-numbers |
|
ip6tables -L INPUT -n --line-numbers |
|
ip6tables -L ${CHAIN_V6} -n --line-numbers |
|
|
|
Hits: |
|
iptables -L INPUT -n -v --line-numbers |
|
iptables -L ${CHAIN_V4} -n -v --line-numbers |
|
ip6tables -L INPUT -n -v --line-numbers |
|
ip6tables -L ${CHAIN_V6} -n -v --line-numbers |
|
|
|
Set counts: |
|
ipset list ${IPSET_V4_IP} | grep "Number of entries" |
|
ipset list ${IPSET_V4_NET} | grep "Number of entries" |
|
ipset list ${IPSET_V6_NET} | grep "Number of entries" |
|
|
|
Allowlist files: |
|
${CONFIG_DIR}/allow_v4_ip.txt |
|
${CONFIG_DIR}/allow_v4_net.txt |
|
${CONFIG_DIR}/allow_v6_net.txt |
|
|
|
EOF |
|
} |
|
|
|
main() { |
|
[[ $EUID -eq 0 ]] || { err "Run as root"; exit 1; } |
|
|
|
install_if_missing |
|
require_cmds |
|
ensure_config_dir |
|
create_sets |
|
fetch_lists |
|
build_sets |
|
attach_rules |
|
persist_sets |
|
show_status |
|
echo |
|
show_debug_help |
|
} |
|
|
|
main "$@" |