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_skb/stream_parser")
bpf_prog1(struct __sk_buff * skb)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_skb/stream_verdict")
bpf_prog2(struct __sk_buff * skb)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 
bpf_write_pass(struct __sk_buff * skb,int offset)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_skb/stream_verdict")
bpf_prog3(struct __sk_buff * skb)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 	err = bpf_skb_adjust_room(skb, 4, 0, 0);
181 	if (err)
182 		return SK_DROP;
183 	bpf_write_pass(skb, 13);
184 	return ret;
185 }
186 
187 SEC("sockops")
bpf_sockmap(struct bpf_sock_ops * skops)188 int bpf_sockmap(struct bpf_sock_ops *skops)
189 {
190 	__u32 lport, rport;
191 	int op, ret;
192 
193 	op = (int) skops->op;
194 
195 	switch (op) {
196 	case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
197 		lport = skops->local_port;
198 		rport = skops->remote_port;
199 
200 		if (lport == 10000) {
201 			ret = 1;
202 #ifdef SOCKMAP
203 			bpf_sock_map_update(skops, &sock_map, &ret,
204 						  BPF_NOEXIST);
205 #else
206 			bpf_sock_hash_update(skops, &sock_map, &ret,
207 						   BPF_NOEXIST);
208 #endif
209 		}
210 		break;
211 	case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
212 		lport = skops->local_port;
213 		rport = skops->remote_port;
214 
215 		if (bpf_ntohl(rport) == 10001) {
216 			ret = 10;
217 #ifdef SOCKMAP
218 			bpf_sock_map_update(skops, &sock_map, &ret,
219 						  BPF_NOEXIST);
220 #else
221 			bpf_sock_hash_update(skops, &sock_map, &ret,
222 						   BPF_NOEXIST);
223 #endif
224 		}
225 		break;
226 	default:
227 		break;
228 	}
229 
230 	return 0;
231 }
232 
233 SEC("sk_msg")
bpf_prog4(struct sk_msg_md * msg)234 int bpf_prog4(struct sk_msg_md *msg)
235 {
236 	int *bytes, zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5;
237 	int *start, *end, *start_push, *end_push, *start_pop, *pop, err = 0;
238 
239 	bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
240 	if (bytes)
241 		bpf_msg_apply_bytes(msg, *bytes);
242 	bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
243 	if (bytes)
244 		bpf_msg_cork_bytes(msg, *bytes);
245 	start = bpf_map_lookup_elem(&sock_bytes, &zero);
246 	end = bpf_map_lookup_elem(&sock_bytes, &one);
247 	if (start && end)
248 		bpf_msg_pull_data(msg, *start, *end, 0);
249 	start_push = bpf_map_lookup_elem(&sock_bytes, &two);
250 	end_push = bpf_map_lookup_elem(&sock_bytes, &three);
251 	if (start_push && end_push) {
252 		err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
253 		if (err)
254 			return SK_DROP;
255 	}
256 	start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
257 	pop = bpf_map_lookup_elem(&sock_bytes, &five);
258 	if (start_pop && pop)
259 		bpf_msg_pop_data(msg, *start_pop, *pop, 0);
260 	return SK_PASS;
261 }
262 
263 SEC("sk_msg")
bpf_prog6(struct sk_msg_md * msg)264 int bpf_prog6(struct sk_msg_md *msg)
265 {
266 	int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, key = 0;
267 	int *bytes, *start, *end, *start_push, *end_push, *start_pop, *pop, *f;
268 	int err = 0;
269 	__u64 flags = 0;
270 
271 	bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
272 	if (bytes)
273 		bpf_msg_apply_bytes(msg, *bytes);
274 	bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
275 	if (bytes)
276 		bpf_msg_cork_bytes(msg, *bytes);
277 
278 	start = bpf_map_lookup_elem(&sock_bytes, &zero);
279 	end = bpf_map_lookup_elem(&sock_bytes, &one);
280 	if (start && end)
281 		bpf_msg_pull_data(msg, *start, *end, 0);
282 
283 	start_push = bpf_map_lookup_elem(&sock_bytes, &two);
284 	end_push = bpf_map_lookup_elem(&sock_bytes, &three);
285 	if (start_push && end_push) {
286 		err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
287 		if (err)
288 			return SK_DROP;
289 	}
290 
291 	start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
292 	pop = bpf_map_lookup_elem(&sock_bytes, &five);
293 	if (start_pop && pop)
294 		bpf_msg_pop_data(msg, *start_pop, *pop, 0);
295 
296 	f = bpf_map_lookup_elem(&sock_redir_flags, &zero);
297 	if (f && *f) {
298 		key = 2;
299 		flags = *f;
300 	}
301 #ifdef SOCKMAP
302 	return bpf_msg_redirect_map(msg, &sock_map_redir, key, flags);
303 #else
304 	return bpf_msg_redirect_hash(msg, &sock_map_redir, &key, flags);
305 #endif
306 }
307 
308 SEC("sk_msg")
bpf_prog8(struct sk_msg_md * msg)309 int bpf_prog8(struct sk_msg_md *msg)
310 {
311 	void *data_end = (void *)(long) msg->data_end;
312 	void *data = (void *)(long) msg->data;
313 	int ret = 0, *bytes, zero = 0;
314 
315 	bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
316 	if (bytes) {
317 		ret = bpf_msg_apply_bytes(msg, *bytes);
318 		if (ret)
319 			return SK_DROP;
320 	} else {
321 		return SK_DROP;
322 	}
323 
324 	__sink(data_end);
325 	__sink(data);
326 
327 	return SK_PASS;
328 }
329 
330 SEC("sk_msg")
bpf_prog9(struct sk_msg_md * msg)331 int bpf_prog9(struct sk_msg_md *msg)
332 {
333 	void *data_end = (void *)(long) msg->data_end;
334 	void *data = (void *)(long) msg->data;
335 	int ret = 0, *bytes, zero = 0;
336 
337 	bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
338 	if (bytes) {
339 		if (((__u64)data_end - (__u64)data) >= *bytes)
340 			return SK_PASS;
341 		ret = bpf_msg_cork_bytes(msg, *bytes);
342 		if (ret)
343 			return SK_DROP;
344 	}
345 	return SK_PASS;
346 }
347 
348 SEC("sk_msg")
bpf_prog10(struct sk_msg_md * msg)349 int bpf_prog10(struct sk_msg_md *msg)
350 {
351 	int *bytes, *start, *end, *start_push, *end_push, *start_pop, *pop;
352 	int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, err = 0;
353 
354 	bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
355 	if (bytes)
356 		bpf_msg_apply_bytes(msg, *bytes);
357 	bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero);
358 	if (bytes)
359 		bpf_msg_cork_bytes(msg, *bytes);
360 	start = bpf_map_lookup_elem(&sock_bytes, &zero);
361 	end = bpf_map_lookup_elem(&sock_bytes, &one);
362 	if (start && end)
363 		bpf_msg_pull_data(msg, *start, *end, 0);
364 	start_push = bpf_map_lookup_elem(&sock_bytes, &two);
365 	end_push = bpf_map_lookup_elem(&sock_bytes, &three);
366 	if (start_push && end_push) {
367 		err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
368 		if (err)
369 			return SK_PASS;
370 	}
371 	start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
372 	pop = bpf_map_lookup_elem(&sock_bytes, &five);
373 	if (start_pop && pop)
374 		bpf_msg_pop_data(msg, *start_pop, *pop, 0);
375 	return SK_DROP;
376 }
377 
378 char _license[] SEC("license") = "GPL";
379