การใช้ eBPF/XDP สำหรับทำ DDos Mitigation แบบละเอียด
Network

การใช้ eBPF/XDP สำหรับทำ DDos Mitigation แบบละเอียด

eBPF/XDP คือเทคโนโลยีด่านหน้าของ Linux ที่ช่วยป้องกัน DDoS ได้อย่างมีประสิทธิภาพสูงสุด ทำงานที่ระดับ Network Driver ทิ้งแพ็กเก็ตตั้งแต่ต้นทาง รองรับหลายสิบล้าน PPS ต่อ Core ปรับแต่ง Logic ได้ยืดหยุ่น ปลอดภัย และเหมาะกับการใช้งานจริง

4 นาทีในการอ่าน
โดย DriteStudio
แชร์บทความ:

การประยุกต์ใช้ eBPF/XDP สำหรับการป้องกันการโจมตีแบบ DDoS

การโจมตีแบบ Distributed Denial of Service (DDoS) เป็นหนึ่งในภัยคุกคามที่สำคัญที่สุดในโลกอินเทอร์เน็ตยุคปัจจุบัน ลักษณะของการโจมตีคือมีการส่ง ปริมาณข้อมูล (Traffic) จำนวนมหาศาล ไปยังเซิร์ฟเวอร์เป้าหมาย ทำให้ระบบไม่สามารถให้บริการผู้ใช้งานตามปกติได้

แนวทางการป้องกันแบบเดิม เช่น iptables หรือ Firewall แม้จะสามารถใช้งานได้ แต่มีข้อจำกัดเมื่อเผชิญกับการโจมตีที่มี Packet หลายสิบล้านต่อวินาที เนื่องจากต้องประมวลผลในระดับที่ลึกเกินไปของ Kernel Network Stack ส่งผลให้ CPU ทำงานหนักจนเกิดคอขวด


eBPF/XDP คืออะไร

eBPF (extended Berkeley Packet Filter)

  • เป็นเทคโนโลยีที่ช่วยให้เขียนโปรแกรมขนาดเล็กลงไปทำงานภายใน Kernel ได้โดยตรง
  • ไม่จำเป็นต้องแก้ไข Source Code ของ Kernel หรือโหลด Kernel Module
  • มี Verifier ตรวจสอบความปลอดภัยก่อนใช้งาน ทำให้มั่นใจว่าโค้ดไม่ทำให้ Kernel ล่ม

XDP (eXpress Data Path)

  • เป็น Hook Point ที่อยู่ระดับ Network Driver

  • ทำให้สามารถตรวจสอบและตัดสินใจทิ้งแพ็กเก็ตได้ตั้งแต่ต้นทาง

  • คำสั่งที่สามารถใช้ได้ เช่น

    • XDP_DROP — ทิ้งทันที
    • XDP_PASS — ปล่อยเข้าสู่ Kernel ต่อ
    • XDP_TX — ส่งออกกลับพอร์ตเดิม
    • XDP_REDIRECT — ส่งไปยังอินเทอร์เฟซอื่น

ทำไม eBPF/XDP ถึงเหมาะกับการป้องกัน DDoS

  1. ประสิทธิภาพสูง (Extreme Performance)

    • ทำงานในระดับ Driver ทำให้สามารถรองรับ Packet หลายสิบล้าน PPS ต่อ Core
  2. ความยืดหยุ่น (Programmability)

    • สามารถเขียน Logic ที่ซับซ้อนได้เอง เช่น การตรวจสอบ TCP Flag, UDP Payload หรือ Signature ของเกม
  3. ความปลอดภัย (Safety)

    • eBPF มีระบบตรวจสอบก่อนรันใน Kernel ป้องกันโค้ดที่อาจทำให้ระบบเสียหาย

ภาพรวมสถาปัตยกรรม

NIC → Driver → [XDP/eBPF Hook] → Kernel Stack → iptables/nftables → Application

ตัวอย่างการใช้งานจริง

1. โปรแกรมนับสถิติ Packet ต่อวินาที

// xdp_counter.c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>

enum { STATS_TOTAL = 0, STATS_TCP, STATS_UDP, STATS_OTHER, STATS_MAX };

struct {
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
    __uint(max_entries, STATS_MAX);
    __type(key, __u32);
    __type(value, __u64);
} pkt_stats SEC(".maps");

SEC("xdp")
int xdp_packet_counter(struct xdp_md *ctx) {
    void *data_end = (void *)(long)ctx->data_end;
    void *data     = (void *)(long)ctx->data;
    struct ethhdr *eth = data;

    if ((void *)(eth + 1) > data_end) return XDP_PASS;

    __u32 key = STATS_TOTAL;
    __u64 *v = bpf_map_lookup_elem(&pkt_stats, &key);
    if (v) (*v)++;

    if (eth->h_proto != bpf_htons(ETH_P_IP)) {
        key = STATS_OTHER;
    } else {
        struct iphdr *ip = (void *)(eth + 1);
        if ((void *)(ip + 1) > data_end) return XDP_PASS;

        switch (ip->protocol) {
            case IPPROTO_TCP: key = STATS_TCP; break;
            case IPPROTO_UDP: key = STATS_UDP; break;
            default: key = STATS_OTHER; break;
        }
    }
    v = bpf_map_lookup_elem(&pkt_stats, &key);
    if (v) (*v)++;
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

2. Rate Limiting แบบ Token Bucket

// xdp_token_bucket.c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>

#define FILL_RATE  200u
#define BURST_SIZE 400u
#define NSEC_PER_SEC 1000000000ULL

struct ip_state { __u64 last_ns; __u32 tokens; };

struct {
    __uint(type, BPF_MAP_TYPE_LRU_HASH);
    __uint(max_entries, 65536);
    __type(key, __u32);
    __type(value, struct ip_state);
} rl_map SEC(".maps");

static __always_inline void refill(struct ip_state *st, __u64 now) {
    __u64 delta_ns = now - st->last_ns;
    if (delta_ns >= NSEC_PER_SEC) {
        __u64 secs = delta_ns / NSEC_PER_SEC;
        __u64 add = secs * FILL_RATE;
        __u64 t = st->tokens + add;
        st->tokens = t > BURST_SIZE ? BURST_SIZE : t;
        st->last_ns = now;
    }
}

SEC("xdp")
int xdp_ratelimit_tb(struct xdp_md *ctx) {
    void *data_end = (void *)(long)ctx->data_end;
    void *data     = (void *)(long)ctx->data;
    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end) return XDP_PASS;
    if (eth->h_proto != bpf_htons(ETH_P_IP)) return XDP_PASS;

    struct iphdr *ip = (void *)(eth + 1);
    if ((void *)(ip + 1) > data_end) return XDP_PASS;

    __u32 src = ip->saddr;
    __u64 now = bpf_ktime_get_ns();
    struct ip_state *st = bpf_map_lookup_elem(&rl_map, &src);

    if (!st) {
        struct ip_state init = { .last_ns = now, .tokens = BURST_SIZE - 1 };
        bpf_map_update_elem(&rl_map, &src, &init, BPF_ANY);
        return XDP_PASS;
    }

    refill(st, now);
    if (st->tokens == 0) return XDP_DROP;
    st->tokens--;
    bpf_map_update_elem(&rl_map, &src, st, BPF_ANY);
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

3. การกรองการโจมตี Amplification Attack

// xdp_amp_filter.c
if (ip->protocol == IPPROTO_UDP) {
    struct udphdr *udp = (void *)ip + sizeof(*ip);
    if ((void *)(udp + 1) <= data_end) {
        __u16 sport = bpf_ntohs(udp->source);
        if (sport==53 || sport==123 || sport==1900 || sport==11211) {
            return XDP_DROP;
        }
    }
}

คำสั่งติดตั้งและใช้งาน

เตรียมสภาพแวดล้อม

sudo apt update && sudo apt install -y clang llvm libbpf-dev libbpf-tools bpftool git make
sudo mount bpffs /sys/fs/bpf -t bpf

คอมไพล์โปรแกรม XDP

clang -O2 -g -target bpf -c xdp_counter.c -o xdp_counter.o
clang -O2 -g -target bpf -c xdp_token_bucket.c -o xdp_token_bucket.o

ติดตั้งโปรแกรม XDP บนอินเทอร์เฟซ (เช่น eth0)

# โหมด Native (เร็วที่สุด ถ้าการ์ดรองรับ)
sudo ip link set dev eth0 xdp obj xdp_counter.o sec xdp

# โหมด Generic (ใช้ได้ทุกการ์ด)
sudo ip link set dev eth0 xdpgeneric obj xdp_counter.o sec xdp

# ถอนโปรแกรมออก
sudo ip link set dev eth0 xdp off

ใช้ xdp-tools (แนะนำ)

sudo xdp-loader load -m native -s xdp xdp_counter.o -d eth0
sudo xdp-loader status
sudo xdp-loader unload -d eth0 --all

สรุป

การใช้งาน eBPF/XDP เพื่อป้องกันการโจมตีแบบ DDoS เป็นแนวทางที่มีประสิทธิภาพสูงสุดในปัจจุบัน โดยสามารถ ตัดสินใจที่ระดับ Driver ทำให้ลดภาระ CPU และเพิ่มความทนทานของระบบต่อปริมาณ Packet มหาศาล

นอกจากนี้ eBPF ยังช่วยให้สามารถเขียน Logic เฉพาะเพื่อรับมือกับการโจมตีรูปแบบต่าง ๆ ได้ ทำให้ระบบมีความยืดหยุ่นและพร้อมรับกับภัยคุกคามที่เปลี่ยนแปลงตลอดเวลา


หมวดหมู่:#Network

ลิขสิทธิ์ © 2025 DriteStudio สงวนสิทธิ์ทั้งหมด

😒 😶 😂
Chat with us.