From 244f4e6e7dc92af3d1bf49e39a371fbd1fb4c079 Mon Sep 17 00:00:00 2001 From: Vincent Li Date: Tue, 26 Nov 2024 02:54:42 +0000 Subject: [PATCH] xdp-udpddos: Add XDP UDP DDoS for game protection UDP DDoS has pattern of flooding game server with random source IP and UDP with random payload. game server UDP traffic usually has certain payload pattern, so this XDP program can serve as example to stop UDP DDoS attack with UDP payload that does not match game UDP traffic payload pattern. Signed-off-by: Vincent Li --- Makefile | 2 +- xdp-udpddos/Makefile | 8 +++ xdp-udpddos/xdp_udpddos.bpf.c | 132 ++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 xdp-udpddos/Makefile create mode 100644 xdp-udpddos/xdp_udpddos.bpf.c diff --git a/Makefile b/Makefile index 26691eae..72fadf3d 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ include config.mk UTILS := xdp-filter xdp-loader xdp-dump ifneq ($(BPFTOOL),) -UTILS += xdp-bench xdp-monitor xdp-trafficgen xdp-synproxy xdp-dnsrrl xdp-udp xdp-dns xdp-sni xdp-geoip +UTILS += xdp-bench xdp-monitor xdp-trafficgen xdp-synproxy xdp-dnsrrl xdp-udp xdp-dns xdp-sni xdp-geoip xdp-udpddos endif SUBDIRS := lib $(UTILS) diff --git a/xdp-udpddos/Makefile b/xdp-udpddos/Makefile new file mode 100644 index 00000000..af7a0535 --- /dev/null +++ b/xdp-udpddos/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +XDP_TARGETS := xdp_udpddos.bpf +BPF_SKEL_TARGETS := $(XDP_TARGETS) + +LIB_DIR = ../lib + +include $(LIB_DIR)/common.mk diff --git a/xdp-udpddos/xdp_udpddos.bpf.c b/xdp-udpddos/xdp_udpddos.bpf.c new file mode 100644 index 00000000..3c972eab --- /dev/null +++ b/xdp-udpddos/xdp_udpddos.bpf.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause +/* Copyright (c) 2024, BPFire. All rights reserved. */ + +#include "vmlinux_local.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf/compiler.h" + +#define XML_HEADER "= PORT_START && port <= PORT_END; +} + +SEC("xdp") +int udp_rate_limit_and_validate(struct xdp_md *ctx) { + void *data = (void *)(long)ctx->data; + void *data_end = (void *)(long)ctx->data_end; + + // Parse Ethernet header + struct ethhdr *eth = data; + if ((void *)(eth + 1) > data_end) + return XDP_PASS; + + if (eth->h_proto != __constant_htons(ETH_P_IP)) + return XDP_PASS; // Not IPv4 + + // Parse IP header + struct iphdr *ip = (void *)(eth + 1); + if ((void *)(ip + 1) > data_end) + return XDP_PASS; + + if (ip->protocol != IPPROTO_UDP) + return XDP_PASS; // Not UDP + + // Parse UDP header + struct udphdr *udp = (void *)(ip + 1); + if ((void *)(udp + 1) > data_end) + return XDP_PASS; + + __u16 dest_port = __bpf_ntohs(udp->dest); + if (!is_port_in_range(dest_port)) + return XDP_PASS; // Port not in range + + // Get UDP payload + void *udp_payload = (void *)(udp + 1); + if (udp_payload + MATCH_BYTES_LEN > data_end) + return XDP_PASS; // Payload too small + + // Ensure payload is large enough for XML_HEADER_LEN + if (udp_payload + XML_HEADER_LEN > data_end) + return XDP_PASS; + // Check for XML header + if (__builtin_memcmp(udp_payload, XML_HEADER, XML_HEADER_LEN) == 0) { + // Rate limit logic for packets with XML header + __u32 count_key = 0; + __u32 reset_key = 1; + __u64 *packet_count = bpf_map_lookup_elem(&rate_limit_state, &count_key); + __u64 *last_reset_time = bpf_map_lookup_elem(&rate_limit_state, &reset_key); + __u64 now = bpf_ktime_get_ns(); + + // Initialize map entries if not present + if (!packet_count || !last_reset_time) { + __u64 initial_count = 1; + bpf_map_update_elem(&rate_limit_state, &count_key, &initial_count, BPF_ANY); + bpf_map_update_elem(&rate_limit_state, &reset_key, &now, BPF_ANY); + return XDP_PASS; + } + + // Reset packet count if interval elapsed + if ((now - *last_reset_time) >= RESET_INTERVAL_NS) { + *packet_count = 0; + *last_reset_time = now; + bpf_map_update_elem(&rate_limit_state, &count_key, packet_count, BPF_ANY); + bpf_map_update_elem(&rate_limit_state, &reset_key, last_reset_time, BPF_ANY); + } + + // Enforce rate limit + if (*packet_count >= RATE_LIMIT_THRESHOLD) { + bpf_printk("Rate limit exceeded for XML header on port %u\n", dest_port); + return XDP_PASS; // Drop packets exceeding the limit + } + + // Increment the packet count and update map + (*packet_count)++; + bpf_map_update_elem(&rate_limit_state, &count_key, packet_count, BPF_ANY); + + return XDP_PASS; + } + + // Check for 4-byte payload match + if (__builtin_memcmp(udp_payload, match_bytes, MATCH_BYTES_LEN) != 0) { + bpf_printk("Dropped packet with mismatched payload on port %u\n", dest_port); + return XDP_DROP; // Drop packets with mismatched payload + } + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; +