@@ -1,5 +0,0 @@
|
||||
#!/bin/env bash
|
||||
|
||||
ETH=enp11s0
|
||||
|
||||
/usr/sbin/ip link set dev $ETH xdp obj xdp_packet_filter.o sec packet_filter
|
||||
4
blocked_ips.conf
Normal file
4
blocked_ips.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
57.141.2.0/24
|
||||
139.59.224.0/20
|
||||
178.156.172.0/24
|
||||
141.148.153.0/24
|
||||
214
blokir.sh
Executable file
214
blokir.sh
Executable file
@@ -0,0 +1,214 @@
|
||||
#!/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
|
||||
2
build.sh
2
build.sh
@@ -1,5 +1,3 @@
|
||||
#!/bin/env bash
|
||||
|
||||
rm xdp_packet_filter.o
|
||||
|
||||
clang -O2 -g -Wall -target bpf -c xdp_packet_filter.c -o xdp_packet_filter.o
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/env bash
|
||||
|
||||
ETH=enp11s0
|
||||
|
||||
/usr/sbin/ip link set dev $ETH xdp off
|
||||
@@ -32,10 +32,34 @@
|
||||
20, 21, 22, 23, 25, 53, 67, 68, 69, 110, 111, 135, \
|
||||
137, 138, 139, 143, 389, 445, 465, 546, 873, 993, 995, \
|
||||
1080, 1433, 1435, 1900, 2049, 3306, 3389, 5353, 5432, \
|
||||
5900, 5901, 5902, 6667 \
|
||||
5900, 5901, 5902, 6667, 8006 \
|
||||
}
|
||||
|
||||
#define DEBUG
|
||||
#define LOCAL_ADDRESS 0x00000000
|
||||
#define LOCAL_BROADCAST 0xFFFFFFFF
|
||||
|
||||
#define INTERVAL 1000000000 // 1 detik dalam nano detik
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
struct
|
||||
{
|
||||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
} rate_limit_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
|
||||
__uint(max_entries, 1024);
|
||||
__type(key, struct {
|
||||
__u32 prefixlen;
|
||||
__u32 addr;
|
||||
});
|
||||
__type(value, __u8);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
} blocked_ips SEC(".maps");
|
||||
|
||||
/**
|
||||
* Fungsi untuk memeriksa apakah port tujuan terdaftar
|
||||
@@ -61,6 +85,64 @@ static inline int periksa_port_tujuan(unsigned short port)
|
||||
return 0; // Aman
|
||||
}
|
||||
|
||||
/**
|
||||
* Fungsi untuk memeriksa apakah sudah lewat dari interval rate limit.
|
||||
*
|
||||
* @param ip_klien: Alamat IP pengirim yang akan diperiksa.
|
||||
*
|
||||
* @return:
|
||||
* 1 jika sudah melewati interval (tipe int),
|
||||
* 0 jika belum melewati interval (tipe int).
|
||||
*/
|
||||
static inline int cek_rate_limit(__u32 ip_klien)
|
||||
{
|
||||
__u64 current_time = bpf_ktime_get_ns();
|
||||
__u64 *val = bpf_map_lookup_elem(&rate_limit_map, &ip_klien);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (current_time - *val < INTERVAL)
|
||||
return 0; // Belum melewati interval, drop paket
|
||||
}
|
||||
|
||||
__u64 new_val = current_time;
|
||||
|
||||
bpf_map_update_elem(&rate_limit_map, &ip_klien, &new_val, BPF_ANY);
|
||||
|
||||
return 1; // Sudah melewati interval, izinkan paket
|
||||
}
|
||||
|
||||
static inline int is_ip_blocked(__u32 ip)
|
||||
{
|
||||
struct {
|
||||
__u32 prefixlen;
|
||||
__u32 addr;
|
||||
} key;
|
||||
|
||||
// Try /32 match first
|
||||
key.prefixlen = 32;
|
||||
key.addr = ip;
|
||||
|
||||
if (bpf_map_lookup_elem(&blocked_ips, &key))
|
||||
return 1;
|
||||
|
||||
// Try /24 match
|
||||
key.prefixlen = 24;
|
||||
key.addr = ip & bpf_htonl(0xFFFFFF00);
|
||||
|
||||
if (bpf_map_lookup_elem(&blocked_ips, &key))
|
||||
return 1;
|
||||
|
||||
// Try /20 match
|
||||
key.prefixlen = 20;
|
||||
key.addr = ip & bpf_htonl(0xFFFFF000);
|
||||
|
||||
if (bpf_map_lookup_elem(&blocked_ips, &key))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Program filtrasi paket XDP untuk memblokir paket berdasarkan port tujuan.
|
||||
*
|
||||
@@ -108,26 +190,53 @@ SEC("packet_filter") int xdp_packet_filter(struct xdp_md *ctx)
|
||||
__u32 ip_klien = ip->saddr;
|
||||
__u32 ip_tujuan = ip->daddr;
|
||||
|
||||
if (bpf_htonl(LOCAL_ADDRESS) == ip_klien || bpf_htonl(LOCAL_BROADCAST) == ip_tujuan)
|
||||
return XDP_PASS;
|
||||
|
||||
// Header transport (TCP/UDP)
|
||||
__u8 protocol = ip->protocol;
|
||||
void *trans_hdr = (void *)(ip + 1);
|
||||
__u16 dest_port;
|
||||
__u16 dest_port = 0;
|
||||
|
||||
if (is_ip_blocked(ip_klien)) {
|
||||
#ifdef DEBUG
|
||||
bpf_printk("[DROP][IP]: %pI4 -> %pI4", &ip_klien, &ip_tujuan);
|
||||
#endif
|
||||
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
// TCP
|
||||
if (protocol == IPPROTO_TCP)
|
||||
{
|
||||
if (trans_hdr + sizeof(struct tcphdr) > data_end)
|
||||
return XDP_DROP;
|
||||
|
||||
dest_port = ((struct tcphdr *)trans_hdr)->dest;
|
||||
}
|
||||
|
||||
// UDP
|
||||
else if (protocol == IPPROTO_UDP)
|
||||
{
|
||||
if (trans_hdr + sizeof(struct udphdr) > data_end)
|
||||
return XDP_DROP;
|
||||
|
||||
dest_port = ((struct udphdr *)trans_hdr)->dest;
|
||||
}
|
||||
else
|
||||
|
||||
// ICMP
|
||||
else if (protocol == IPPROTO_ICMP)
|
||||
{
|
||||
return XDP_PASS;
|
||||
if (trans_hdr + sizeof(struct icmphdr) > data_end)
|
||||
return XDP_DROP;
|
||||
|
||||
if (!cek_rate_limit(ip_klien))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
bpf_printk("[DROP][ICMP]: %pI4 -> %pI4", &ip_klien, &ip_tujuan);
|
||||
#endif
|
||||
return XDP_DROP;
|
||||
}
|
||||
}
|
||||
|
||||
// Cek daftar blokir port
|
||||
@@ -144,4 +253,4 @@ SEC("packet_filter") int xdp_packet_filter(struct xdp_md *ctx)
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
5
xload
Executable file
5
xload
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/env bash
|
||||
|
||||
/usr/sbin/ip link set dev "$1" xdp obj /root/xdp_packet_filter.o sec packet_filter
|
||||
|
||||
/usr/sbin/xdp-loader status
|
||||
3
xlog
Executable file
3
xlog
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/env bash
|
||||
|
||||
cat /sys/kernel/debug/tracing/trace_pipe
|
||||
6
xreload
Executable file
6
xreload
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/env bash
|
||||
|
||||
/usr/sbin/ip link set dev "$1" xdp off
|
||||
/usr/sbin/ip link set dev "$1" xdp obj /root/xdp_packet_filter.o sec packet_filter
|
||||
|
||||
/usr/sbin/xdp-loader status
|
||||
Reference in New Issue
Block a user