-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfilter_xdp.c
128 lines (103 loc) · 5.43 KB
/
filter_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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
UDP filter XDP program
Drops IPv4 UDP packets sent to port 40000 that don't pass the packet filter.
USAGE:
clang -Ilibbpf/src -g -O2 -target bpf -c filter_xdp.c -o filter_xdp.o
sudo cat /sys/kernel/debug/tracing/trace_pipe
*/
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/bpf.h>
#include <linux/string.h>
#include <bpf/bpf_helpers.h>
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define bpf_ntohs(x) __builtin_bswap16(x)
#define bpf_htons(x) __builtin_bswap16(x)
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define bpf_ntohs(x) (x)
#define bpf_htons(x) (x)
#else
# error "Endianness detection needs to be set up for your compiler?!"
#endif
#define DEBUG 1
#if DEBUG
#define debug_printf bpf_printk
#else // #if DEBUG
#define debug_printf(...) do { } while (0)
#endif // #if DEBUG
SEC("filter_xdp") int filter_xdp_filter( struct xdp_md *ctx )
{
void * data = (void*) (long) ctx->data;
void * data_end = (void*) (long) ctx->data_end;
struct ethhdr * eth = data;
if ( (void*)eth + sizeof(struct ethhdr) < data_end )
{
if ( eth->h_proto == __constant_htons(ETH_P_IP) ) // IPV4
{
struct iphdr * ip = data + sizeof(struct ethhdr);
if ( (void*)ip + sizeof(struct iphdr) < data_end )
{
if ( ip->protocol == IPPROTO_UDP ) // UDP
{
struct udphdr * udp = (void*) ip + sizeof(struct iphdr);
if ( (void*)udp + sizeof(struct udphdr) <= data_end )
{
if ( udp->dest == __constant_htons(40000) )
{
// Drop packets that are too small to be valid
__u8 * packet_data = (void*) udp + sizeof(struct udphdr);
if ( (void*)packet_data + 16 > data_end )
{
debug_printf( "packet is too small" );
return XDP_DROP;
}
// Drop packets that are too large to be valid
int packet_bytes = data_end - (void*)udp - sizeof(struct udphdr);
if ( packet_bytes > 1400 )
{
debug_printf( "packet is too large" );
return XDP_DROP;
}
// Drop UDP packet if it is a fragment
if ( ( ip->frag_off & ~0x2000 ) != 0 )
{
debug_printf( "dropped udp fragment" );
return XDP_DROP;
}
// Basic packet filter
if ( packet_data[1] < 0x2A || packet_data[1] > 0x2D ||
packet_data[2] < 0xC8 || packet_data[2] > 0xE7 ||
packet_data[3] < 0x05 || packet_data[3] > 0x44 ||
packet_data[5] < 0x4E || packet_data[5] > 0x51 ||
packet_data[6] < 0x60 || packet_data[6] > 0xDF ||
packet_data[7] < 0x64 || packet_data[7] > 0xE3 ||
packet_data[8] != 0x07 && packet_data[8] != 0x4F ||
packet_data[9] != 0x25 && packet_data[9] != 0x53 ||
packet_data[10] < 0x7C || packet_data[10] > 0x83 ||
packet_data[11] < 0xAF || packet_data[11] > 0xB6 ||
packet_data[12] < 0x21 || packet_data[12] > 0x60 ||
packet_data[13] != 0x61 && packet_data[13] != 0x05 && packet_data[13] != 0x2B && packet_data[13] != 0x0D ||
packet_data[14] < 0xD2 || packet_data[14] > 0xF1 ||
packet_data[15] < 0x11 || packet_data[15] > 0x90 )
{
debug_printf( "basic packet filter dropped packet" );
return XDP_DROP;
}
debug_printf( "basic packet filter passed" );
return XDP_PASS;
}
}
}
}
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";