Files
XDP-Packet-Filter/blokir.sh
MOVZX 53b40c0329 Various Changes
Signed-off-by: MOVZX <movzx@yahoo.com>
2025-08-29 17:36:45 +07:00

215 lines
5.7 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
#
# blokir.sh manage IPv4 prefixes in the “blocked_ips” LPM-trie map
#
# sudo ./blokir.sh # help
# sudo ./blokir.sh 1.2.3.4/24 … # add
# sudo ./blokir.sh unblock … # delete exact prefix(es)
# sudo ./blokir.sh reset # flush whole map
# sudo ./blokir.sh export [f] # print or save list
#
set -euo pipefail
###############################################################################
# 1. Locate the map automatically
###############################################################################
MAP_NAME=${MAP_NAME:-blocked_ips} # change if you used another name
detect_map_id() {
local id=""
if command -v jq >/dev/null; then
id=$(bpftool -j map show | jq -r --arg n "$MAP_NAME" \
'.[]|select(.name==$n)|.id' | head -n1)
fi
if [[ -z $id ]]; then # plain-text fallback
id=$(bpftool -p map show |
awk -v n="$MAP_NAME" '$4==n{split($1,a,":");print a[1];exit}')
fi
[[ -z $id ]] && {
echo "‼︎ map \"$MAP_NAME\" not found." >&2
exit 1
}
echo "$id"
}
MAP_ID=$(detect_map_id)
###############################################################################
# 2. Helpers
###############################################################################
usage() {
cat <<EOF
Usage:
$0 reset
$0 unblock <ip|cidr> [..]
$0 import [file]
$0 export [file]
$0 <ip|cidr> [..] (add)
$0 show
$0 (help)
EOF
}
# dotted IP + plen → key-bytes "xx xx …"
gen_key_bytes() {
local ip=$1 plen=$2
IFS=. read -r o1 o2 o3 o4 <<<"$ip"
printf '%02x %02x %02x %02x %02x %02x %02x %02x' \
$((plen & 255)) 0 0 0 "$o1" "$o2" "$o3" "$o4"
}
mask_ip() { # → network/0-host bits
local ip=$1 plen=$2
IFS=. read -r a b c d <<<"$ip"
local v=$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))
local m=$((plen == 0 ? 0 : (0xFFFFFFFF << (32 - plen)) & 0xFFFFFFFF))
v=$((v & m))
printf '%d.%d.%d.%d' $((v >> 24 & 255)) $((v >> 16 & 255)) $((v >> 8 & 255)) $((v & 255))
}
import_prefixes() {
local file="$1"
[[ -r "$file" ]] || {
echo "‼︎ Cannot read file: $file" >&2
exit 1
}
echo "📥 Importing from $file"
while IFS= read -r line || [[ -n "$line" ]]; do
[[ -z "$line" || "$line" =~ ^# ]] && continue # skip empty lines and comments
insert_prefix "$line"
done <"$file"
show_map
}
parse_cidr() { # validate → "ip plen"
local cidr="$1" ip plen
ip=${cidr%%/*}
plen=${cidr#*/}
[[ $ip == $plen ]] && plen=32
[[ $plen =~ ^[0-9]+$ && plen -le 32 ]] || return 1
if ! [[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then return 1; fi
IFS=. read -r a b c d <<<"$ip"
for o in $a $b $c $d; do ((o > 255)) && return 1; done
echo "$ip $plen"
}
###############################################################################
# 3. Map-byte helpers (used by add/del/export)
###############################################################################
list_keys() { # stdout: "xx xx …" (8-byte key)
if command -v jq >/dev/null; then
bpftool -j map dump id "$MAP_ID" |
jq -r '.[]|.key|join(" ")'
else
bpftool -p map dump id "$MAP_ID" |
awk '/^key:/{for(i=2;i<=NF;i++)printf $i" ";print ""}'
fi
}
bytes_to_prefix() { # arg: "xx xx …" → "IP/len"
read -ra b <<<"$1" # eight bytes
local plen=$((16#${b[0]#0x})) # byte-0 = prefix length
local o1=$((16#${b[4]#0x}))
local o2=$((16#${b[5]#0x}))
local o3=$((16#${b[6]#0x}))
local o4=$((16#${b[7]#0x}))
echo "$o1.$o2.$o3.$o4/$plen"
}
###############################################################################
# 4. Core operations
###############################################################################
insert_prefix() {
local parsed
parsed=$(parse_cidr "$1") || {
echo "‼︎ Bad CIDR: $1" >&2
return 1
}
set -- $parsed
local ip=$1 plen=$2
local net=$(mask_ip "$ip" "$plen")
local k=$(gen_key_bytes "$net" "$plen")
echo " $net/$plen"
bpftool map update id "$MAP_ID" key hex $k value hex 01
}
delete_prefix() {
local parsed
parsed=$(parse_cidr "$1") || {
echo "‼︎ Bad CIDR: $1" >&2
return 1
}
set -- $parsed
local ip=$1 plen=$2
local net=$(mask_ip "$ip" "$plen")
local k=$(gen_key_bytes "$net" "$plen")
echo " $net/$plen"
bpftool map delete id "$MAP_ID" key hex $k 2>/dev/null || echo " (not present)"
}
flush_map() {
echo "🗑 Flushing…"
list_keys | while read -r k; do bpftool map delete id "$MAP_ID" key hex $k 2>/dev/null || true; done
}
export_map() { # [outfile]
local out=${1:-}
local lines=""
while read -r k; do
[[ -z $k ]] && continue
lines+=$(bytes_to_prefix "$k")$'\n'
done < <(list_keys)
if [[ -n $out ]]; then
printf '%s' "$lines" >"$out"
echo "📤 List written to $out"
else printf '%s' "$lines"; fi
}
show_map() {
echo -e "\n📋 Current prefixes:"
export_map
echo -e "\n"
}
###############################################################################
# 5. CLI
###############################################################################
(($# == 0)) && {
usage
exit 0
}
case "$1" in
reset)
flush_map
show_map
;;
unblock)
shift
(($# == 0)) && {
usage
exit 1
}
for p in "$@"; do delete_prefix "$p"; done
show_map
;;
import)
shift
[[ $# -ne 1 ]] && {
usage
exit 1
}
import_prefixes "$1"
;;
export)
shift
export_map "${1:-}"
;;
show)
show_map
;;
-h | --help | help) usage ;;
*)
for p in "$@"; do insert_prefix "$p"; done
show_map
;;
esac