-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsource_xdp.c
executable file
·153 lines (131 loc) · 3.58 KB
/
source_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
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
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/if_arp.h>
#include <linux/tcp.h>
#include <linux/in.h>
BPF_HASH(block, int, uint16, 10);
BPF_HASH(drop_count, int, int, 1);
BPF_HASH(ip_b, int, __be32, 100);
BPF_HASH(mac_b, int, u_int8_t, 100);
BPF_HASH(capture, int, int, 1);
BPF_RINGBUF_OUTPUT(packet, 8);
struct pkt{
struct xdp_md *ctx;
struct ethhdr *eth;
struct arphdr *arph;
struct iphdr *iph;
struct icmphdr *icmph;
struct tcphdr *tcph;
struct udphdr *udph;
struct dnshdr *dnsh;
};
int zero = 0;
static inline void proceed_pkt(struct pkt* p){
int len = (int)p->ctx->data_end - p->ctx->data;
packet.ringbuf_output(p->ctx->data, len, 0);
}
static inline void increment_drop(){
int* val = drop_count.lookup(&zero);
if(val)
*val += 1;
}
static inline int process_eth(struct pkt *p){
int tmp = -1;
if(block.lookup(&tmp)){//block all traffic
increment_drop();
if(capture.lookup(&zero))
proceed_pkt(p);
return XDP_DROP;
}
struct ethhdr *eth = p->ctx->data;
if((void*)eth + sizeof(*eth) > p->ctx->data_end)
return XDP_DROP; //malformed packet
p->eth = eth;
if(block.lookup(htons(eth->h_proto)) || mac_b.lookup(eth->h_source)){//block network layer protocol
increment_drop();
if(capture.lookup(&zero))
proceed_pkt(p);
return XDP_DROP;
}
if(htons(eth->h_proto) == ETH_P_IP)
return process_ip(p);
if(htons(eth->h_proto) == ETH_P_ARP)
return process_arp(p);
}
static inline int process_ip(struct pkt *p){
struct iphdr *iph = p->ctx->data + sizeof(*(p->eth));
if((void*)iph + sizeof(*iph) <= p->ctx->data_end){
increment_drop();
if(capture.lookup(&zero))
proceed_pkt(p);
return XDP_DROP;
}
p->iph = iph;
if(ip_b.lookup(iph->saddr)){
increment_drop();
if(capture.lookup(&zero))
proceed_pkt(p);
return XDP_DROP;
}
if(p->iph->protocol == IPPROTO_TCP)
return process_tcp(p);
if(p->iph->protocol == IPPROTO_UDP)
return process_udp(p);
if(p->iph->protocol == IPPROTO_ICMP)
return process_icmp(p);
}
static inline int process_arp(struct pkt *p){
struct arphdr *arph = p->ctx->data + sizeof(*(p->eth));
if((void*)arph + sizeof(*arph) <= p->ctx->data_end){
increment_drop();
if(capture.lookup(&zero))
proceed_pkt(p);
return XDP_DROP;
}
p->arph = arph;
return XDP_PASS;
}
static inline int process_icmp(struct pkt *p){
struct icmphdr *icmph = (struct icmphdr*)(p->iph + sizeof(*(p->iph)));
if((void*)icmph + sizeof(*icmph) > p->ctx->data_end){
increment_drop();
if(capture.lookup(&zero))
proceed_pkt(p);
return XDP_DROP;
}
p->icmph = icmph;
return XDP_PASS;
}
static inline int process_tcp(struct pkt *p){
struct tcphdr *tcph = (struct tcphdr*)(p->iph + sizeof(*(p->iph)));
if((void*)tcph + sizeof(*tcph) > p->ctx->data_end)
return XDP_DROP;
p->tcph = tcph;
if((block.lookup(&(p->iph->protocol)) & p->tcph->dest) == p->tcph->dest){
increment_drop();
if(capture.lookup(&zero))
proceed_pkt(p);
return XDP_DROP;
}
return XDP_PASS;
}
static inline int process_udp(struct pkt *p){
struct udphdr *udph = (struct udphdr*)(p->iph + sizeof(*(p->iph)));
if((void*)udph + sizeof(*udph) > p->ctx->data_end)
return XDP_DROP;
p->udph = udph;
if((block.lookup(&(p->iph->protocol)) & p->udph->dest) == p->udph->dest){
increment_drop();
if(capture.lookup(&zero))
proceed_pkt(p);
return XDP_DROP;
}
return XDP_PASS;
}
int capture(struct xdp_md *ctx){
struct pkt p;
p.ctx = ctx;
return process_eth(&p);
}