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..5753f3df --- /dev/null +++ b/xdp-udpddos/xdp_udpddos.bpf.c @@ -0,0 +1,129 @@ +#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"; +