Files
XDP-Packet-Filter/xdp_packet_filter.c
2025-09-04 17:00:56 +07:00

296 lines
7.9 KiB
C

/**
* Packet Filter berbasis XDP
*
* Author : MOVZX
* Email : movzx@yahoo.com
* GitHub : https://github.com/MOVZX
*
* Version : 1.0
*
* File xdp_redm_packet_filter.c
*/
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/udp.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#define bpf_htons(x) __builtin_bswap16(x)
#define bpf_htonl(x) __builtin_bswap32(x)
/**
* Daftar Port yang tidak terdaftar di Server
* Kalau terdeteksi ya berarti ada aktivitas Port/Vulnerability Scanner
* yang sedang mengintip/menganalisa Server, gak boleh!
*/
#define DAFTAR_BLOKIR \
{ \
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, 8006 \
}
#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
* dalam daftar port yang terblokir.
*
* @param port: port tujuan yang akan diperiksa (tipe unsigned short).
*
* @return:
* 1 jika port tujuan terdaftar dalam daftar blokir (tipe int),
* 0 jika port tujuan tidak terdaftar dalam daftar blokir (tipe int).
*/
static inline int periksa_port_tujuan(unsigned short port)
{
unsigned short blocked_ports[] = DAFTAR_BLOKIR;
// Loop pemeriksaan port
for (int i = 0; i < sizeof(blocked_ports) / sizeof(blocked_ports[0]); i++)
{
if (bpf_htons(port) == blocked_ports[i])
return 1; // Blok
}
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
}
/**
* Fungsi untuk memeriksa apakah alamat IP sudah diblokir menggunakan Longest Prefix Match (LPM) trie.
* Fungsi ini mencoba mencocokkan alamat IP dengan prefiks /32 (exact match), /24, dan /20 secara berurutan.
*
* @param ip: Alamat IP yang akan diperiksa (tipe __u32).
*
* @return:
* 1 jika alamat IP sudah diblokir (tipe int),
* 0 jika alamat IP tidak diblokir (tipe int).
*/
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;
}
/**
* Fungsi untuk menambahkan alamat IP ke daftar IP yang diblokir dengan prefiks /32 (exact match).
*
* @param ip: Alamat IP yang akan ditambahkan ke daftar blokir (tipe __u32).
*/
/*
// TODO: Jangan langsung dimasukkan ke daftar blokir permanen, namun tambahkan ke daftar IP untuk direview
static inline void add_to_blocked_ips(__u32 ip)
{
struct {
__u32 prefixlen;
__u32 addr;
} key;
__u8 value = 1;
key.prefixlen = 32;
key.addr = ip;
bpf_map_update_elem(&blocked_ips, &key, &value, BPF_ANY);
}
*/
/**
* Program filtrasi paket XDP untuk memblokir paket berdasarkan port tujuan dan alamat IP pengirim.
*
* Fungsi ini memvalidasi dan memproses paket jaringan yang masuk pada level NIC, lalu memeriksa header Ethernet, IP,
* dan lapisan transport (TCP/UDP) serta menerapkan mekanisme filtrasi untuk memblokir lalu lintas yang ditujukan
* ke port tujuan tertentu yang telah ditentukan sebelumnya atau berasal dari alamat IP yang telah diblokir.
* Fungsi ini beroperasi sebagai berikut:
*
* - Validasi header Ethernet dan pastikan paket adalah tipe IPv4.
* - Validasi header IP dan periksa protokol (TCP, UDP, atau ICMP).
* - Jika paket berasal dari IP yang sudah diblokir, paket dihentikan.
* - Untuk TCP, validasi header TCP dan periksa apakah port tujuan ada dalam daftar blokir. Jika ya, paket dihentikan.
* - Untuk UDP, validasi header UDP dan periksa apakah port tujuan ada dalam daftar blokir. Jika ya, paket dihentikan.
* - Untuk ICMP, terapkan rate limiting dan blokir IP pengirim jika melebihi batas.
* - Jika paket melewati semua pemeriksaan dan tidak diblokir, maka paket diizinkan untuk melewati.
*
* Fungsi ini mencatat paket yang diblokir ketika flag/mode DEBUG diaktifkan.
*
* @param ctx: Pointer ke konteks XDP yang menyediakan akses ke data paket.
*
* @return:
* - XDP_DROP jika header tidak valid atau paket diblokir.
* - XDP_PASS jika paket diizinkan untuk melewati.
*/
SEC("packet_filter") int xdp_packet_filter(struct xdp_md *ctx)
{
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
// Validasi Ethernet Header
if (data + sizeof(struct ethhdr) > data_end)
return XDP_DROP;
struct ethhdr *eth = (struct ethhdr *)data;
// Lewati jika bukan IPv4
if (eth->h_proto != bpf_htons(ETH_P_IP))
return XDP_PASS;
// IP Header
struct iphdr *ip = (struct iphdr *)(eth + 1);
// Validasi IP Header
if ((void *)(ip + 1) > data_end || ip->ihl < 5)
return XDP_DROP;
__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 = 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;
}
// ICMP
else if (protocol == IPPROTO_ICMP)
{
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
// add_to_blocked_ips(ip_klien);
return XDP_DROP;
}
}
// Cek daftar blokir port
if (periksa_port_tujuan(dest_port))
{
#ifdef DEBUG
bpf_printk("[BLOKIR][%s]: %pI4 -> %pI4:%d", protocol == IPPROTO_TCP ? "TCP" : "UDP",
&ip_klien, &ip_tujuan, bpf_htons(dest_port));
#endif
// add_to_blocked_ips(ip_klien);
return XDP_DROP;
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";