-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathfivem_xdp.c
100 lines (82 loc) · 3.02 KB
/
fivem_xdp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/udp.h>
#include <bpf/bpf_helpers.h>
#include <arpa/inet.h> // For htonl and htons
#define FIVEM_SERVER_IP 0x7F000001 // 127.0.0.1
#define FIVEM_SERVER_PORT 30120 // Replace with the port number of your FiveM server
#define RATE_LIMIT 13000 // Maximum number of packets allowed per second
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_PERCPU_ARRAY);
__uint(max_entries, 2); // 0: dropped, 1: passed
__type(key, __u32);
__type(value, __u64);
} packet_count_map SEC(".maps");
SEC("xdp_program")
int fivem_xdp(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
__u32 rate_limit_key = 0;
__u64 *rate_limit_value;
__u32 key_dropped = 0;
__u32 key_passed = 1;
__u64 *count_dropped, *count_passed;
count_dropped = bpf_map_lookup_elem(&packet_count_map, &key_dropped);
count_passed = bpf_map_lookup_elem(&packet_count_map, &key_passed);
if (!count_dropped || !count_passed) {
return XDP_ABORTED;
}
// Parse Ethernet header
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end) {
return XDP_ABORTED;
}
// Check that the packet is IPv4
if (eth->h_proto != htons(ETH_P_IP)) {
return XDP_PASS; // Allow non-IPv4 packets
}
// Parse IP header and validate its length
struct iphdr *ip = data + sizeof(struct ethhdr);
if ((void *)(ip + 1) > data_end || ip->ihl < 5) {
return XDP_ABORTED;
}
// Check if packet is UDP
if (ip->protocol != IPPROTO_UDP) {
return XDP_PASS; // Allow non-UDP packets
}
// Parse UDP header
struct udphdr *udp = data + sizeof(struct ethhdr) + (ip->ihl * 4);
if ((void *)(udp + 1) > data_end) {
return XDP_ABORTED;
}
// Check if packet is destined for the FiveM server IP and port
if (ip->daddr != htonl(FIVEM_SERVER_IP) || udp->dest != htons(FIVEM_SERVER_PORT)) {
return XDP_PASS; // Allow other UDP traffic
}
// Check the rate limit map
rate_limit_value = bpf_map_lookup_elem(&rate_limit_map, &rate_limit_key);
if (!rate_limit_value) {
return XDP_PASS; // Allow packets if map lookup fails
}
// Get the current timestamp
__u64 now = bpf_ktime_get_ns();
__u64 last = *rate_limit_value;
// Rate limiting logic
if (now - last < (1000000000 / RATE_LIMIT)) {
__sync_fetch_and_add(count_dropped, 1);
return XDP_DROP; // Drop packet if rate limit exceeded
}
// Update the rate limit map with the current timestamp
bpf_map_update_elem(&rate_limit_map, &rate_limit_key, &now, BPF_ANY);
__sync_fetch_and_add(count_passed, 1);
return XDP_PASS; // Pass the packet if within rate limit
}
char _license[] SEC("license") = "MIT";