forked from zhangmenghao/eBPF-IDS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxdp_prog_kern.c
295 lines (254 loc) · 7.7 KB
/
xdp_prog_kern.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/bpf.h>
#include <linux/in.h>
#include "bpf_helpers.h"
#include "bpf_endian.h"
// The parsing helper functions from the packet01 lesson have moved here
#include "common/parsing_helpers.h"
#include "common/rewrite_helpers.h"
/* Defines xdp_stats_map */
#include "common/xdp_stats_kern_user.h"
#include "common/xdp_stats_kern.h"
#include "common_kern_user.h"
#ifndef memcpy
#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n))
#endif
#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})
#define IDS_INSPECT_STRIDE 1
#define IDS_INSPECT_MAP_SIZE 16777216
#define IDS_INSPECT_DEPTH 200
#define TAIL_CALL_MAP_SIZE 1
struct bpf_map_def SEC("maps") ids_inspect_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(struct ids_inspect_map_key),
.value_size = sizeof(struct ids_inspect_map_value),
.max_entries = IDS_INSPECT_MAP_SIZE,
};
struct bpf_map_def SEC("maps") tail_call_map = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u32),
.max_entries = TAIL_CALL_MAP_SIZE,
};
struct meta_info {
__u8 unit;
__u8 tens;
__u16 raw;
} __attribute__((aligned(4)));
/*
static __always_inline int inspect_payload(struct hdr_cursor *nh,void *data_end, ids_inspect_state init_state)
{
// struct ids_inspect_unit *ids_unit = nh->pos;
ids_inspect_unit *ids_unit;
struct ids_inspect_map_key ids_map_key;
struct ids_inspect_map_value *ids_map_value;
int i;
ids_map_key.state = 0;
ids_map_key.padding = 0;
#pragma unroll
for (i = 0; i < IDS_INSPECT_DEPTH; i++) {
ids_unit = nh->pos;
if (ids_unit + 1 > data_end) {
// Reach the last byte of the packet
return 0;
}
// memcpy(ids_map_key.unit.unit, ids_unit, IDS_INSPECT_STRIDE);
// memcpy(&(ids_map_key.unit), ids_unit, IDS_INSPECT_STRIDE);
ids_map_key.unit = *ids_unit;
// bpf_printk("char: %u\n", ids_map_key.unit);
// bpf_printk("src: %u\n", ids_map_key.state);
ids_map_value = bpf_map_lookup_elem(&ids_inspect_map, &ids_map_key);
if (ids_map_value) {
// Go to the next state according to DFA
ids_map_key.state = ids_map_value->state;
// bpf_printk("dst: %u\n", ids_map_value->state);
if (ids_map_value->flag > 0) {
// An acceptable state, return the hit pattern number
return ids_map_value->flag;
}
}
// Prepare for next scanning
nh->pos += 1;
}
// The payload is not inspected completely
return -1;
}
*/
SEC("xdp_ids")
int xdp_ids_func(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct meta_info *meta;
struct hdr_cursor nh;
int eth_type, ip_type;
struct ethhdr *eth;
struct iphdr *iph;
struct ipv6hdr *ip6h;
struct udphdr *udph;
struct tcphdr *tcph;
/* Default action XDP_PASS, imply everything we couldn't parse, or that
* we don't want to deal with, we just pass up the stack and let the
* kernel deal with it.
*/
__u32 action = XDP_PASS; /* Default action */
/* Prepare space for metadata */
if (bpf_xdp_adjust_meta(ctx, -(int)sizeof(*meta)) < 0) {
action = XDP_ABORTED;
goto out;
}
/* Actually, I do not understand why we should reassign value to data.
* But without the reassignment below, the program can not be loaded...
*/
data = (void *)(long)ctx->data;
data_end = (void *)(long)ctx->data_end;
nh.pos = data;
/* Check the validity */
meta = (void *)(long)ctx->data_meta;
if (meta + 1 > data) {
action = XDP_ABORTED;
goto out;
}
/* Parse packet */
eth_type = parse_ethhdr(&nh, data_end, ð);
if (eth_type == bpf_htons(ETH_P_IP)) {
ip_type = parse_iphdr(&nh, data_end, &iph);
} else if (eth_type == bpf_htons(ETH_P_IPV6)) {
ip_type = parse_ip6hdr(&nh, data_end, &ip6h);
} else {
goto out;
}
if (ip_type == IPPROTO_TCP) {
if (parse_tcphdr(&nh, data_end, &tcph) < 0) {
action = XDP_ABORTED;
goto out;
}
} else if (ip_type == IPPROTO_UDP) {
if (parse_udphdr(&nh, data_end, &udph) < 0) {
action = XDP_ABORTED;
goto out;
}
} else {
goto out;
}
/* Only packet with valid TCP/UDP header will reach here */
meta->raw = 0;
__u16 temp;
temp = nh.pos - data;
/* When adjusting the position of nh pointer, we cannot use
the field in the meta directly. So we use unit and tens field
to encode the nh pointer difference.*/
meta->unit = temp % 10;
meta->tens = temp / 10;
/* Debug info */
// bpf_printk("meta: %u\n", meta->raw);
// bpf_printk("Current packet pointer: %u\n", nh.pos);
bpf_tail_call(ctx, &tail_call_map, 0);
bpf_printk("Tail call fails in xdp_ids!\n");
out:
return xdp_stats_record_action(ctx, action);
}
SEC("xdp_dpi")
int xdp_dpi_func(struct xdp_md *ctx)
{
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
void *data_meta = (void *)(long)ctx->data_meta;
struct meta_info *meta = data_meta;
struct hdr_cursor nh;
// int ids_state = 0;
/* Default action XDP_PASS, imply everything we couldn't parse, or that
* we don't want to deal with, we just pass up the stack and let the
* kernel deal with it.
*/
__u32 action = XDP_PASS; /* Default action */
/* Compute current packet pointer */
nh.pos = data;
if (meta + 1 > data) {
return XDP_ABORTED;
}
if (nh.pos + meta->unit > data_end) {
action = XDP_ABORTED;
goto out;
}
nh.pos += meta->unit;
// ids_inspect_state init_state = meta->raw;
if ((nh.pos + meta->tens * 10) > data_end) {
action = XDP_ABORTED;
goto out;
}
nh.pos += meta->tens * 10;
/* Debug info */
// bpf_printk("Tail call success!\n");
// bpf_printk("meta: %u\n", meta->raw);
// bpf_printk("Current packet pointer: %u\n", nh.pos);
// ids_state = inspect_payload(&nh, data_end, init_state);
ids_inspect_unit *ids_unit;
struct ids_inspect_map_key ids_map_key;
struct ids_inspect_map_value *ids_map_value;
int i;
ids_map_key.state = meta->raw;
ids_map_key.padding = 0;
#pragma unroll
for (i = 0; i < IDS_INSPECT_DEPTH; i++) {
ids_unit = nh.pos;
if (ids_unit + 1 > data_end) {
/* Reach the last byte of the packet */
return 0;
}
// memcpy(ids_map_key.unit.unit, ids_unit, IDS_INSPECT_STRIDE);
// memcpy(&(ids_map_key.unit), ids_unit, IDS_INSPECT_STRIDE);
ids_map_key.unit = *ids_unit;
// bpf_printk("char: %u\n", ids_map_key.unit);
// bpf_printk("src: %u\n", ids_map_key.state);
ids_map_value = bpf_map_lookup_elem(&ids_inspect_map, &ids_map_key);
if (ids_map_value) {
/* Go to the next state according to DFA */
ids_map_key.state = ids_map_value->state;
// bpf_printk("dst: %u\n", ids_map_value->state);
if (ids_map_value->flag > 0) {
/* An acceptable state, return the hit pattern number */
action = XDP_DROP;
bpf_printk("The %dth pattern is triggered\n", ids_map_value->flag);
goto out;
}
}
/* Prepare for next scanning */
nh.pos += 1;
}
// bpf_printk("ids_state: %d\n", ids_state);
// if (ids_state > 0) {
// action = XDP_DROP;
// bpf_printk("The %dth pattern is triggered\n", ids_state);
// goto out;
// } else if (ids_state < 0) {
meta->raw = ids_map_key.state;
__u16 temp;
temp = nh.pos - data;
meta->unit = temp % 10;
meta->tens = temp / 10;
bpf_tail_call(ctx, &tail_call_map, 0);
bpf_printk("Tail call fails in xdp_dpi!\n");
// } else {
/* The packet is inspected completely */
// goto out;
// }
out:
return xdp_stats_record_action(ctx, action);
}
SEC("xdp_pass")
int xdp_pass_func(struct xdp_md *ctx)
{
return xdp_stats_record_action(ctx, XDP_PASS);
}
SEC("xdp_drop")
int xdp_drop_func(struct xdp_md *ctx)
{
return xdp_stats_record_action(ctx, XDP_DROP);
}
char _license[] SEC("license") = "GPL";