1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io */
3 #include <stddef.h>
4 #include <string.h>
5 #include <linux/bpf.h>
6 #include <linux/if_ether.h>
7 #include <linux/if_packet.h>
8 #include <linux/ip.h>
9 #include <linux/ipv6.h>
10 #include <linux/in.h>
11 #include <linux/udp.h>
12 #include <linux/tcp.h>
13 #include <linux/pkt_cls.h>
14 #include <sys/socket.h>
15 #include <bpf/bpf_helpers.h>
16 #include <bpf/bpf_endian.h>
17 #include "bpf_misc.h"
18 
19 /* Sockmap sample program connects a client and a backend together
20  * using cgroups.
21  *
22  *    client:X <---> frontend:80 client:X <---> backend:80
23  *
24  * For simplicity we hard code values here and bind 1:1. The hard
25  * coded values are part of the setup in sockmap.sh script that
26  * is associated with this BPF program.
27  *
28  * The bpf_printk is verbose and prints information as connections
29  * are established and verdicts are decided.
30  */
31 
32 struct {
33 	__uint(type, TEST_MAP_TYPE);
34 	__uint(max_entries, 20);
35 	__uint(key_size, sizeof(int));
36 	__uint(value_size, sizeof(int));
37 } sock_map SEC(".maps");
38 
39 struct {
40 	__uint(type, TEST_MAP_TYPE);
41 	__uint(max_entries, 20);
42 	__uint(key_size, sizeof(int));
43 	__uint(value_size, sizeof(int));
44 } sock_map_txmsg SEC(".maps");
45 
46 struct {
47 	__uint(type, TEST_MAP_TYPE);
48 	__uint(max_entries, 20);
49 	__uint(key_size, sizeof(int));
50 	__uint(value_size, sizeof(int));
51 } sock_map_redir SEC(".maps");
52 
53 struct {
54 	__uint(type, BPF_MAP_TYPE_ARRAY);
55 	__uint(max_entries, 1);
56 	__type(key, int);
57 	__type(value, int);
58 } sock_apply_bytes SEC(".maps");
59 
60 struct {
61 	__uint(type, BPF_MAP_TYPE_ARRAY);
62 	__uint(max_entries, 1);
63 	__type(key, int);
64 	__type(value, int);
65 } sock_cork_bytes SEC(".maps");
66 
67 struct {
68 	__uint(type, BPF_MAP_TYPE_ARRAY);
69 	__uint(max_entries, 6);
70 	__type(key, int);
71 	__type(value, int);
72 } sock_bytes SEC(".maps");
73 
74 struct {
75 	__uint(type, BPF_MAP_TYPE_ARRAY);
76 	__uint(max_entries, 1);
77 	__type(key, int);
78 	__type(value, int);
79 } sock_redir_flags SEC(".maps");
80 
81 struct {
82 	__uint(type, BPF_MAP_TYPE_ARRAY);
83 	__uint(max_entries, 3);
84 	__type(key, int);
85 	__type(value, int);
86 } sock_skb_opts SEC(".maps");
87 
88 struct {
89 	__uint(type, TEST_MAP_TYPE);
90 	__uint(max_entries, 20);
91 	__uint(key_size, sizeof(int));
92 	__uint(value_size, sizeof(int));
93 } tls_sock_map SEC(".maps");
94 
95 SEC("sk_skb1")
96 int bpf_prog1(struct __sk_buff *skb)
97 {
98 	int *f, two = 2;
99 
100 	f = bpf_map_lookup_elem(&sock_skb_opts, &two);
101 	if (f && *f) {
102 		return *f;
103 	}
104 	return skb->len;
105 }
106 
107 SEC("sk_skb2")
108 int bpf_prog2(struct __sk_buff *skb)
109 {
110 	__u32 lport = skb->local_port;
111 	__u32 rport = skb->remote_port;
112 	int len, *f, ret, zero = 0;
113 	__u64 flags = 0;
114 
115 	__sink(rport);
116 	if (lport == 10000)
117 		ret = 10;
118 	else
119 		ret = 1;
120 
121 	len = (__u32)skb->data_end - (__u32)skb->data;
122 	__sink(len);
123 
124 	f = bpf_map_lookup_elem(&sock_skb_opts, &zero);
125 	if (f && *f) {
126 		ret = 3;
127 		flags = *f;
128 	}
129 
130 #ifdef SOCKMAP
131 	return bpf_sk_redirect_map(skb, &sock_map, ret, flags);
132 #else
133 	return bpf_sk_redirect_hash(skb, &sock_map, &ret, flags);
134 #endif
135 
136 }
137 
138 static inline void bpf_write_pass(struct __sk_buff *skb, int offset)
139 {
140 	int err = bpf_skb_pull_data(skb, 6 + offset);
141 	void *data_end;
142 	char *c;
143 
144 	if (err)
145 		return;
146 
147 	c = (char *)(long)skb->data;
148 	data_end = (void *)(long)skb->data_end;
149 
150 	if (c + 5 + offset < data_end)
151 		memcpy(c + offset, "PASS", 4);
152 }
153 
154 SEC("sk_skb3")
155 int bpf_prog3(struct __sk_buff *skb)
156 {
157 	int err, *f, ret = SK_PASS;
158 	const int one = 1;
159 
160 	f = bpf_map_lookup_elem(&sock_skb_opts, &one);
161 	if (f && *f) {
162 		__u64 flags = 0;
163 
164 		ret = 0;
165 		flags = *f;
166 
167 		err = bpf_skb_adjust_room(skb, -13, 0, 0);
168 		if (err)
169 			return SK_DROP;
170 		err = bpf_skb_adjust_room(skb, 4, 0, 0);
171 		if (err)
172 			return SK_DROP;
173 		bpf_write_pass(skb, 0);
174 #ifdef SOCKMAP
175 		return bpf_sk_redirect_map(skb, &tls_sock_map, ret, flags);
176 #else
177 		return bpf_sk_redirect_hash(skb, &tls_sock_map, &ret, flags);
178 #endif
179 	}
180 	f = bpf_map_lookup_elem(&sock_skb_opts, &one);
181 	if (f && *f)
182 		ret = SK_DROP;
183 	err = bpf_skb_adjust_room(skb, 4, 0, 0);
184 	if (err)
185 		return SK_DROP;
186 	bpf_write_pass(skb, 13);
187 	return ret;
188 }
189 
190 SEC("sockops")
191 int bpf_sockmap(struct bpf_sock_ops *skops)
192 {
193 	__u32 lport, rport;
194 	int op, ret;
195 
196 	op = (int) skops->op;
197 
198 	switch (op) {
199 	case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
200 		lport = skops->local_port;
201 		rport = skops->remote_port;
202 
203 		if (lport == 10000) {
204 			ret = 1;
205 #ifdef SOCKMAP
206 			bpf_sock_map_update(skops, &sock_map, &ret,
207 						  BPF_NOEXIST);
208 #else
209 			bpf_sock_hash_update(skops, &sock_map, &ret,
210 						   BPF_NOEXIST);
211 #endif
212 		}
213 		break;
214 	case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
215 		lport = skops->local_port;
216 		rport = skops->remote_port;
217 
218 		if (bpf_ntohl(rport) == 10001) {
219 			ret = 10;
220 #ifdef SOCKMAP
221 			bpf_sock_map_update(skops, &sock_map, &ret,
222 						  BPF_NOEXIST);
223 #else
224 			bpf_sock_hash_update(skops, &sock_map, &ret,
225 						   BPF_NOEXIST);
226 #endif
227 		}
228 		break;
229 	default:
230 		break;
231 	}
232 
233 	return 0;
234 }
235 
236 SEC("sk_msg1")
237 int bpf_prog4(struct sk_msg_md *msg)
238 {
239 	int *bytes, zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5;
240 	int *start, *end, *start_push, *end_push, *start_pop, *pop, err = 0;
241 
242 	bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
243 	if (bytes)
244 		bpf_msg_apply_bytes(msg, *bytes);
245 	bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
246 	if (bytes)
247 		bpf_msg_cork_bytes(msg, *bytes);
248 	start = bpf_map_lookup_elem(&sock_bytes, &zero);
249 	end = bpf_map_lookup_elem(&sock_bytes, &one);
250 	if (start && end)
251 		bpf_msg_pull_data(msg, *start, *end, 0);
252 	start_push = bpf_map_lookup_elem(&sock_bytes, &two);
253 	end_push = bpf_map_lookup_elem(&sock_bytes, &three);
254 	if (start_push && end_push) {
255 		err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
256 		if (err)
257 			return SK_DROP;
258 	}
259 	start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
260 	pop = bpf_map_lookup_elem(&sock_bytes, &five);
261 	if (start_pop && pop)
262 		bpf_msg_pop_data(msg, *start_pop, *pop, 0);
263 	return SK_PASS;
264 }
265 
266 SEC("sk_msg2")
267 int bpf_prog6(struct sk_msg_md *msg)
268 {
269 	int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, key = 0;
270 	int *bytes, *start, *end, *start_push, *end_push, *start_pop, *pop, *f;
271 	int err = 0;
272 	__u64 flags = 0;
273 
274 	bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
275 	if (bytes)
276 		bpf_msg_apply_bytes(msg, *bytes);
277 	bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
278 	if (bytes)
279 		bpf_msg_cork_bytes(msg, *bytes);
280 
281 	start = bpf_map_lookup_elem(&sock_bytes, &zero);
282 	end = bpf_map_lookup_elem(&sock_bytes, &one);
283 	if (start && end)
284 		bpf_msg_pull_data(msg, *start, *end, 0);
285 
286 	start_push = bpf_map_lookup_elem(&sock_bytes, &two);
287 	end_push = bpf_map_lookup_elem(&sock_bytes, &three);
288 	if (start_push && end_push) {
289 		err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
290 		if (err)
291 			return SK_DROP;
292 	}
293 
294 	start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
295 	pop = bpf_map_lookup_elem(&sock_bytes, &five);
296 	if (start_pop && pop)
297 		bpf_msg_pop_data(msg, *start_pop, *pop, 0);
298 
299 	f = bpf_map_lookup_elem(&sock_redir_flags, &zero);
300 	if (f && *f) {
301 		key = 2;
302 		flags = *f;
303 	}
304 #ifdef SOCKMAP
305 	return bpf_msg_redirect_map(msg, &sock_map_redir, key, flags);
306 #else
307 	return bpf_msg_redirect_hash(msg, &sock_map_redir, &key, flags);
308 #endif
309 }
310 
311 SEC("sk_msg3")
312 int bpf_prog8(struct sk_msg_md *msg)
313 {
314 	void *data_end = (void *)(long) msg->data_end;
315 	void *data = (void *)(long) msg->data;
316 	int ret = 0, *bytes, zero = 0;
317 
318 	bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
319 	if (bytes) {
320 		ret = bpf_msg_apply_bytes(msg, *bytes);
321 		if (ret)
322 			return SK_DROP;
323 	} else {
324 		return SK_DROP;
325 	}
326 
327 	__sink(data_end);
328 	__sink(data);
329 
330 	return SK_PASS;
331 }
332 SEC("sk_msg4")
333 int bpf_prog9(struct sk_msg_md *msg)
334 {
335 	void *data_end = (void *)(long) msg->data_end;
336 	void *data = (void *)(long) msg->data;
337 	int ret = 0, *bytes, zero = 0;
338 
339 	bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
340 	if (bytes) {
341 		if (((__u64)data_end - (__u64)data) >= *bytes)
342 			return SK_PASS;
343 		ret = bpf_msg_cork_bytes(msg, *bytes);
344 		if (ret)
345 			return SK_DROP;
346 	}
347 	return SK_PASS;
348 }
349 
350 SEC("sk_msg5")
351 int bpf_prog10(struct sk_msg_md *msg)
352 {
353 	int *bytes, *start, *end, *start_push, *end_push, *start_pop, *pop;
354 	int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, err = 0;
355 
356 	bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
357 	if (bytes)
358 		bpf_msg_apply_bytes(msg, *bytes);
359 	bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
360 	if (bytes)
361 		bpf_msg_cork_bytes(msg, *bytes);
362 	start = bpf_map_lookup_elem(&sock_bytes, &zero);
363 	end = bpf_map_lookup_elem(&sock_bytes, &one);
364 	if (start && end)
365 		bpf_msg_pull_data(msg, *start, *end, 0);
366 	start_push = bpf_map_lookup_elem(&sock_bytes, &two);
367 	end_push = bpf_map_lookup_elem(&sock_bytes, &three);
368 	if (start_push && end_push) {
369 		err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
370 		if (err)
371 			return SK_PASS;
372 	}
373 	start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
374 	pop = bpf_map_lookup_elem(&sock_bytes, &five);
375 	if (start_pop && pop)
376 		bpf_msg_pop_data(msg, *start_pop, *pop, 0);
377 	return SK_DROP;
378 }
379 
380 char _license[] SEC("license") = "GPL";
381