]>
Commit | Line | Data |
---|---|---|
e50b0a6f AI |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2018 Facebook | |
3 | ||
04b6ab73 AI |
4 | #define _GNU_SOURCE |
5 | ||
e50b0a6f AI |
6 | #include <stdio.h> |
7 | #include <stdlib.h> | |
8 | #include <unistd.h> | |
9 | ||
10 | #include <arpa/inet.h> | |
04b6ab73 | 11 | #include <netinet/in.h> |
e50b0a6f | 12 | #include <sys/types.h> |
04b6ab73 | 13 | #include <sys/select.h> |
e50b0a6f AI |
14 | #include <sys/socket.h> |
15 | ||
16 | #include <linux/filter.h> | |
17 | ||
18 | #include <bpf/bpf.h> | |
622adafb | 19 | #include <bpf/libbpf.h> |
e50b0a6f AI |
20 | |
21 | #include "cgroup_helpers.h" | |
aa5f0c96 | 22 | #include "bpf_util.h" |
e50b0a6f | 23 | |
04b6ab73 AI |
24 | #ifndef ENOTSUPP |
25 | # define ENOTSUPP 524 | |
26 | #endif | |
27 | ||
e50b0a6f | 28 | #define CG_PATH "/foo" |
afef88e6 DM |
29 | #define CONNECT4_PROG_PATH "./connect4_prog.bpf.o" |
30 | #define CONNECT6_PROG_PATH "./connect6_prog.bpf.o" | |
31 | #define SENDMSG4_PROG_PATH "./sendmsg4_prog.bpf.o" | |
32 | #define SENDMSG6_PROG_PATH "./sendmsg6_prog.bpf.o" | |
33 | #define RECVMSG4_PROG_PATH "./recvmsg4_prog.bpf.o" | |
34 | #define RECVMSG6_PROG_PATH "./recvmsg6_prog.bpf.o" | |
35 | #define BIND4_PROG_PATH "./bind4_prog.bpf.o" | |
36 | #define BIND6_PROG_PATH "./bind6_prog.bpf.o" | |
e50b0a6f AI |
37 | |
38 | #define SERV4_IP "192.168.1.254" | |
39 | #define SERV4_REWRITE_IP "127.0.0.1" | |
04b6ab73 | 40 | #define SRC4_IP "172.16.0.1" |
9be71aa6 | 41 | #define SRC4_REWRITE_IP "127.0.0.4" |
e50b0a6f AI |
42 | #define SERV4_PORT 4040 |
43 | #define SERV4_REWRITE_PORT 4444 | |
44 | ||
45 | #define SERV6_IP "face:b00c:1234:5678::abcd" | |
46 | #define SERV6_REWRITE_IP "::1" | |
04b6ab73 AI |
47 | #define SERV6_V4MAPPED_IP "::ffff:192.168.0.4" |
48 | #define SRC6_IP "::1" | |
9be71aa6 | 49 | #define SRC6_REWRITE_IP "::6" |
976b4f3a | 50 | #define WILDCARD6_IP "::" |
e50b0a6f AI |
51 | #define SERV6_PORT 6060 |
52 | #define SERV6_REWRITE_PORT 6666 | |
53 | ||
54 | #define INET_NTOP_BUF 40 | |
55 | ||
9be71aa6 AI |
56 | struct sock_addr_test; |
57 | ||
58 | typedef int (*load_fn)(const struct sock_addr_test *test); | |
e50b0a6f AI |
59 | typedef int (*info_fn)(int, struct sockaddr *, socklen_t *); |
60 | ||
9be71aa6 AI |
61 | char bpf_log_buf[BPF_LOG_BUF_SIZE]; |
62 | ||
63 | struct sock_addr_test { | |
64 | const char *descr; | |
65 | /* BPF prog properties */ | |
66 | load_fn loadfn; | |
67 | enum bpf_attach_type expected_attach_type; | |
68 | enum bpf_attach_type attach_type; | |
69 | /* Socket properties */ | |
70 | int domain; | |
71 | int type; | |
72 | /* IP:port pairs for BPF prog to override */ | |
73 | const char *requested_ip; | |
74 | unsigned short requested_port; | |
75 | const char *expected_ip; | |
76 | unsigned short expected_port; | |
77 | const char *expected_src_ip; | |
78 | /* Expected test result */ | |
79 | enum { | |
80 | LOAD_REJECT, | |
81 | ATTACH_REJECT, | |
1812291e | 82 | ATTACH_OKAY, |
04b6ab73 AI |
83 | SYSCALL_EPERM, |
84 | SYSCALL_ENOTSUPP, | |
9be71aa6 AI |
85 | SUCCESS, |
86 | } expected_result; | |
e50b0a6f AI |
87 | }; |
88 | ||
9be71aa6 AI |
89 | static int bind4_prog_load(const struct sock_addr_test *test); |
90 | static int bind6_prog_load(const struct sock_addr_test *test); | |
91 | static int connect4_prog_load(const struct sock_addr_test *test); | |
92 | static int connect6_prog_load(const struct sock_addr_test *test); | |
976b4f3a | 93 | static int sendmsg_allow_prog_load(const struct sock_addr_test *test); |
04b6ab73 | 94 | static int sendmsg_deny_prog_load(const struct sock_addr_test *test); |
1812291e DB |
95 | static int recvmsg_allow_prog_load(const struct sock_addr_test *test); |
96 | static int recvmsg_deny_prog_load(const struct sock_addr_test *test); | |
04b6ab73 | 97 | static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test); |
35749060 | 98 | static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test); |
04b6ab73 AI |
99 | static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test); |
100 | static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test); | |
35749060 | 101 | static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test); |
04b6ab73 AI |
102 | static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test); |
103 | static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test); | |
976b4f3a | 104 | static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test); |
9be71aa6 AI |
105 | |
106 | static struct sock_addr_test tests[] = { | |
107 | /* bind */ | |
108 | { | |
109 | "bind4: load prog with wrong expected attach type", | |
110 | bind4_prog_load, | |
111 | BPF_CGROUP_INET6_BIND, | |
112 | BPF_CGROUP_INET4_BIND, | |
113 | AF_INET, | |
114 | SOCK_STREAM, | |
115 | NULL, | |
116 | 0, | |
117 | NULL, | |
118 | 0, | |
119 | NULL, | |
120 | LOAD_REJECT, | |
121 | }, | |
122 | { | |
123 | "bind4: attach prog with wrong attach type", | |
124 | bind4_prog_load, | |
125 | BPF_CGROUP_INET4_BIND, | |
126 | BPF_CGROUP_INET6_BIND, | |
127 | AF_INET, | |
128 | SOCK_STREAM, | |
129 | NULL, | |
130 | 0, | |
131 | NULL, | |
132 | 0, | |
133 | NULL, | |
134 | ATTACH_REJECT, | |
135 | }, | |
136 | { | |
137 | "bind4: rewrite IP & TCP port in", | |
138 | bind4_prog_load, | |
139 | BPF_CGROUP_INET4_BIND, | |
140 | BPF_CGROUP_INET4_BIND, | |
141 | AF_INET, | |
142 | SOCK_STREAM, | |
143 | SERV4_IP, | |
144 | SERV4_PORT, | |
145 | SERV4_REWRITE_IP, | |
146 | SERV4_REWRITE_PORT, | |
147 | NULL, | |
148 | SUCCESS, | |
149 | }, | |
150 | { | |
151 | "bind4: rewrite IP & UDP port in", | |
152 | bind4_prog_load, | |
153 | BPF_CGROUP_INET4_BIND, | |
154 | BPF_CGROUP_INET4_BIND, | |
155 | AF_INET, | |
156 | SOCK_DGRAM, | |
157 | SERV4_IP, | |
158 | SERV4_PORT, | |
159 | SERV4_REWRITE_IP, | |
160 | SERV4_REWRITE_PORT, | |
161 | NULL, | |
162 | SUCCESS, | |
163 | }, | |
164 | { | |
165 | "bind6: load prog with wrong expected attach type", | |
166 | bind6_prog_load, | |
167 | BPF_CGROUP_INET4_BIND, | |
168 | BPF_CGROUP_INET6_BIND, | |
169 | AF_INET6, | |
170 | SOCK_STREAM, | |
171 | NULL, | |
172 | 0, | |
173 | NULL, | |
174 | 0, | |
175 | NULL, | |
176 | LOAD_REJECT, | |
177 | }, | |
178 | { | |
179 | "bind6: attach prog with wrong attach type", | |
180 | bind6_prog_load, | |
181 | BPF_CGROUP_INET6_BIND, | |
182 | BPF_CGROUP_INET4_BIND, | |
183 | AF_INET, | |
184 | SOCK_STREAM, | |
185 | NULL, | |
186 | 0, | |
187 | NULL, | |
188 | 0, | |
189 | NULL, | |
190 | ATTACH_REJECT, | |
191 | }, | |
192 | { | |
193 | "bind6: rewrite IP & TCP port in", | |
194 | bind6_prog_load, | |
195 | BPF_CGROUP_INET6_BIND, | |
196 | BPF_CGROUP_INET6_BIND, | |
197 | AF_INET6, | |
198 | SOCK_STREAM, | |
199 | SERV6_IP, | |
200 | SERV6_PORT, | |
201 | SERV6_REWRITE_IP, | |
202 | SERV6_REWRITE_PORT, | |
203 | NULL, | |
204 | SUCCESS, | |
205 | }, | |
206 | { | |
207 | "bind6: rewrite IP & UDP port in", | |
208 | bind6_prog_load, | |
209 | BPF_CGROUP_INET6_BIND, | |
210 | BPF_CGROUP_INET6_BIND, | |
211 | AF_INET6, | |
212 | SOCK_DGRAM, | |
213 | SERV6_IP, | |
214 | SERV6_PORT, | |
215 | SERV6_REWRITE_IP, | |
216 | SERV6_REWRITE_PORT, | |
217 | NULL, | |
218 | SUCCESS, | |
219 | }, | |
220 | ||
221 | /* connect */ | |
222 | { | |
223 | "connect4: load prog with wrong expected attach type", | |
224 | connect4_prog_load, | |
225 | BPF_CGROUP_INET6_CONNECT, | |
226 | BPF_CGROUP_INET4_CONNECT, | |
227 | AF_INET, | |
228 | SOCK_STREAM, | |
229 | NULL, | |
230 | 0, | |
231 | NULL, | |
232 | 0, | |
233 | NULL, | |
234 | LOAD_REJECT, | |
235 | }, | |
236 | { | |
237 | "connect4: attach prog with wrong attach type", | |
238 | connect4_prog_load, | |
239 | BPF_CGROUP_INET4_CONNECT, | |
240 | BPF_CGROUP_INET6_CONNECT, | |
241 | AF_INET, | |
242 | SOCK_STREAM, | |
243 | NULL, | |
244 | 0, | |
245 | NULL, | |
246 | 0, | |
247 | NULL, | |
248 | ATTACH_REJECT, | |
249 | }, | |
250 | { | |
251 | "connect4: rewrite IP & TCP port", | |
252 | connect4_prog_load, | |
253 | BPF_CGROUP_INET4_CONNECT, | |
254 | BPF_CGROUP_INET4_CONNECT, | |
255 | AF_INET, | |
256 | SOCK_STREAM, | |
257 | SERV4_IP, | |
258 | SERV4_PORT, | |
259 | SERV4_REWRITE_IP, | |
260 | SERV4_REWRITE_PORT, | |
261 | SRC4_REWRITE_IP, | |
262 | SUCCESS, | |
263 | }, | |
264 | { | |
265 | "connect4: rewrite IP & UDP port", | |
266 | connect4_prog_load, | |
267 | BPF_CGROUP_INET4_CONNECT, | |
268 | BPF_CGROUP_INET4_CONNECT, | |
269 | AF_INET, | |
270 | SOCK_DGRAM, | |
271 | SERV4_IP, | |
272 | SERV4_PORT, | |
273 | SERV4_REWRITE_IP, | |
274 | SERV4_REWRITE_PORT, | |
275 | SRC4_REWRITE_IP, | |
276 | SUCCESS, | |
277 | }, | |
278 | { | |
279 | "connect6: load prog with wrong expected attach type", | |
280 | connect6_prog_load, | |
281 | BPF_CGROUP_INET4_CONNECT, | |
282 | BPF_CGROUP_INET6_CONNECT, | |
283 | AF_INET6, | |
284 | SOCK_STREAM, | |
285 | NULL, | |
286 | 0, | |
287 | NULL, | |
288 | 0, | |
289 | NULL, | |
290 | LOAD_REJECT, | |
291 | }, | |
292 | { | |
293 | "connect6: attach prog with wrong attach type", | |
294 | connect6_prog_load, | |
295 | BPF_CGROUP_INET6_CONNECT, | |
296 | BPF_CGROUP_INET4_CONNECT, | |
297 | AF_INET, | |
298 | SOCK_STREAM, | |
299 | NULL, | |
300 | 0, | |
301 | NULL, | |
302 | 0, | |
303 | NULL, | |
304 | ATTACH_REJECT, | |
305 | }, | |
306 | { | |
307 | "connect6: rewrite IP & TCP port", | |
308 | connect6_prog_load, | |
309 | BPF_CGROUP_INET6_CONNECT, | |
310 | BPF_CGROUP_INET6_CONNECT, | |
311 | AF_INET6, | |
312 | SOCK_STREAM, | |
313 | SERV6_IP, | |
314 | SERV6_PORT, | |
315 | SERV6_REWRITE_IP, | |
316 | SERV6_REWRITE_PORT, | |
317 | SRC6_REWRITE_IP, | |
318 | SUCCESS, | |
319 | }, | |
320 | { | |
321 | "connect6: rewrite IP & UDP port", | |
322 | connect6_prog_load, | |
323 | BPF_CGROUP_INET6_CONNECT, | |
324 | BPF_CGROUP_INET6_CONNECT, | |
325 | AF_INET6, | |
326 | SOCK_DGRAM, | |
327 | SERV6_IP, | |
328 | SERV6_PORT, | |
329 | SERV6_REWRITE_IP, | |
330 | SERV6_REWRITE_PORT, | |
331 | SRC6_REWRITE_IP, | |
332 | SUCCESS, | |
333 | }, | |
04b6ab73 AI |
334 | |
335 | /* sendmsg */ | |
336 | { | |
337 | "sendmsg4: load prog with wrong expected attach type", | |
338 | sendmsg4_rw_asm_prog_load, | |
339 | BPF_CGROUP_UDP6_SENDMSG, | |
340 | BPF_CGROUP_UDP4_SENDMSG, | |
341 | AF_INET, | |
342 | SOCK_DGRAM, | |
343 | NULL, | |
344 | 0, | |
345 | NULL, | |
346 | 0, | |
347 | NULL, | |
348 | LOAD_REJECT, | |
349 | }, | |
350 | { | |
351 | "sendmsg4: attach prog with wrong attach type", | |
352 | sendmsg4_rw_asm_prog_load, | |
353 | BPF_CGROUP_UDP4_SENDMSG, | |
354 | BPF_CGROUP_UDP6_SENDMSG, | |
355 | AF_INET, | |
356 | SOCK_DGRAM, | |
357 | NULL, | |
358 | 0, | |
359 | NULL, | |
360 | 0, | |
361 | NULL, | |
362 | ATTACH_REJECT, | |
363 | }, | |
364 | { | |
365 | "sendmsg4: rewrite IP & port (asm)", | |
366 | sendmsg4_rw_asm_prog_load, | |
367 | BPF_CGROUP_UDP4_SENDMSG, | |
368 | BPF_CGROUP_UDP4_SENDMSG, | |
369 | AF_INET, | |
370 | SOCK_DGRAM, | |
371 | SERV4_IP, | |
372 | SERV4_PORT, | |
373 | SERV4_REWRITE_IP, | |
374 | SERV4_REWRITE_PORT, | |
375 | SRC4_REWRITE_IP, | |
376 | SUCCESS, | |
377 | }, | |
378 | { | |
379 | "sendmsg4: rewrite IP & port (C)", | |
380 | sendmsg4_rw_c_prog_load, | |
381 | BPF_CGROUP_UDP4_SENDMSG, | |
382 | BPF_CGROUP_UDP4_SENDMSG, | |
383 | AF_INET, | |
384 | SOCK_DGRAM, | |
385 | SERV4_IP, | |
386 | SERV4_PORT, | |
387 | SERV4_REWRITE_IP, | |
388 | SERV4_REWRITE_PORT, | |
389 | SRC4_REWRITE_IP, | |
390 | SUCCESS, | |
391 | }, | |
392 | { | |
393 | "sendmsg4: deny call", | |
394 | sendmsg_deny_prog_load, | |
395 | BPF_CGROUP_UDP4_SENDMSG, | |
396 | BPF_CGROUP_UDP4_SENDMSG, | |
397 | AF_INET, | |
398 | SOCK_DGRAM, | |
399 | SERV4_IP, | |
400 | SERV4_PORT, | |
401 | SERV4_REWRITE_IP, | |
402 | SERV4_REWRITE_PORT, | |
403 | SRC4_REWRITE_IP, | |
404 | SYSCALL_EPERM, | |
405 | }, | |
406 | { | |
407 | "sendmsg6: load prog with wrong expected attach type", | |
408 | sendmsg6_rw_asm_prog_load, | |
409 | BPF_CGROUP_UDP4_SENDMSG, | |
410 | BPF_CGROUP_UDP6_SENDMSG, | |
411 | AF_INET6, | |
412 | SOCK_DGRAM, | |
413 | NULL, | |
414 | 0, | |
415 | NULL, | |
416 | 0, | |
417 | NULL, | |
418 | LOAD_REJECT, | |
419 | }, | |
420 | { | |
421 | "sendmsg6: attach prog with wrong attach type", | |
422 | sendmsg6_rw_asm_prog_load, | |
423 | BPF_CGROUP_UDP6_SENDMSG, | |
424 | BPF_CGROUP_UDP4_SENDMSG, | |
425 | AF_INET6, | |
426 | SOCK_DGRAM, | |
427 | NULL, | |
428 | 0, | |
429 | NULL, | |
430 | 0, | |
431 | NULL, | |
432 | ATTACH_REJECT, | |
433 | }, | |
434 | { | |
435 | "sendmsg6: rewrite IP & port (asm)", | |
436 | sendmsg6_rw_asm_prog_load, | |
437 | BPF_CGROUP_UDP6_SENDMSG, | |
438 | BPF_CGROUP_UDP6_SENDMSG, | |
439 | AF_INET6, | |
440 | SOCK_DGRAM, | |
441 | SERV6_IP, | |
442 | SERV6_PORT, | |
443 | SERV6_REWRITE_IP, | |
444 | SERV6_REWRITE_PORT, | |
445 | SRC6_REWRITE_IP, | |
446 | SUCCESS, | |
447 | }, | |
448 | { | |
449 | "sendmsg6: rewrite IP & port (C)", | |
450 | sendmsg6_rw_c_prog_load, | |
451 | BPF_CGROUP_UDP6_SENDMSG, | |
452 | BPF_CGROUP_UDP6_SENDMSG, | |
453 | AF_INET6, | |
454 | SOCK_DGRAM, | |
455 | SERV6_IP, | |
456 | SERV6_PORT, | |
457 | SERV6_REWRITE_IP, | |
458 | SERV6_REWRITE_PORT, | |
459 | SRC6_REWRITE_IP, | |
460 | SUCCESS, | |
461 | }, | |
462 | { | |
463 | "sendmsg6: IPv4-mapped IPv6", | |
464 | sendmsg6_rw_v4mapped_prog_load, | |
465 | BPF_CGROUP_UDP6_SENDMSG, | |
466 | BPF_CGROUP_UDP6_SENDMSG, | |
467 | AF_INET6, | |
468 | SOCK_DGRAM, | |
469 | SERV6_IP, | |
470 | SERV6_PORT, | |
471 | SERV6_REWRITE_IP, | |
472 | SERV6_REWRITE_PORT, | |
473 | SRC6_REWRITE_IP, | |
474 | SYSCALL_ENOTSUPP, | |
475 | }, | |
976b4f3a AI |
476 | { |
477 | "sendmsg6: set dst IP = [::] (BSD'ism)", | |
478 | sendmsg6_rw_wildcard_prog_load, | |
479 | BPF_CGROUP_UDP6_SENDMSG, | |
480 | BPF_CGROUP_UDP6_SENDMSG, | |
481 | AF_INET6, | |
482 | SOCK_DGRAM, | |
483 | SERV6_IP, | |
484 | SERV6_PORT, | |
485 | SERV6_REWRITE_IP, | |
486 | SERV6_REWRITE_PORT, | |
487 | SRC6_REWRITE_IP, | |
488 | SUCCESS, | |
489 | }, | |
490 | { | |
491 | "sendmsg6: preserve dst IP = [::] (BSD'ism)", | |
492 | sendmsg_allow_prog_load, | |
493 | BPF_CGROUP_UDP6_SENDMSG, | |
494 | BPF_CGROUP_UDP6_SENDMSG, | |
495 | AF_INET6, | |
496 | SOCK_DGRAM, | |
497 | WILDCARD6_IP, | |
498 | SERV6_PORT, | |
499 | SERV6_REWRITE_IP, | |
500 | SERV6_PORT, | |
501 | SRC6_IP, | |
502 | SUCCESS, | |
503 | }, | |
04b6ab73 AI |
504 | { |
505 | "sendmsg6: deny call", | |
506 | sendmsg_deny_prog_load, | |
507 | BPF_CGROUP_UDP6_SENDMSG, | |
508 | BPF_CGROUP_UDP6_SENDMSG, | |
509 | AF_INET6, | |
510 | SOCK_DGRAM, | |
511 | SERV6_IP, | |
512 | SERV6_PORT, | |
513 | SERV6_REWRITE_IP, | |
514 | SERV6_REWRITE_PORT, | |
515 | SRC6_REWRITE_IP, | |
516 | SYSCALL_EPERM, | |
517 | }, | |
1812291e DB |
518 | |
519 | /* recvmsg */ | |
520 | { | |
521 | "recvmsg4: return code ok", | |
522 | recvmsg_allow_prog_load, | |
523 | BPF_CGROUP_UDP4_RECVMSG, | |
524 | BPF_CGROUP_UDP4_RECVMSG, | |
525 | AF_INET, | |
526 | SOCK_DGRAM, | |
527 | NULL, | |
528 | 0, | |
529 | NULL, | |
530 | 0, | |
531 | NULL, | |
532 | ATTACH_OKAY, | |
533 | }, | |
534 | { | |
535 | "recvmsg4: return code !ok", | |
536 | recvmsg_deny_prog_load, | |
537 | BPF_CGROUP_UDP4_RECVMSG, | |
538 | BPF_CGROUP_UDP4_RECVMSG, | |
539 | AF_INET, | |
540 | SOCK_DGRAM, | |
541 | NULL, | |
542 | 0, | |
543 | NULL, | |
544 | 0, | |
545 | NULL, | |
546 | LOAD_REJECT, | |
547 | }, | |
548 | { | |
549 | "recvmsg6: return code ok", | |
550 | recvmsg_allow_prog_load, | |
551 | BPF_CGROUP_UDP6_RECVMSG, | |
552 | BPF_CGROUP_UDP6_RECVMSG, | |
553 | AF_INET6, | |
554 | SOCK_DGRAM, | |
555 | NULL, | |
556 | 0, | |
557 | NULL, | |
558 | 0, | |
559 | NULL, | |
560 | ATTACH_OKAY, | |
561 | }, | |
562 | { | |
563 | "recvmsg6: return code !ok", | |
564 | recvmsg_deny_prog_load, | |
565 | BPF_CGROUP_UDP6_RECVMSG, | |
566 | BPF_CGROUP_UDP6_RECVMSG, | |
567 | AF_INET6, | |
568 | SOCK_DGRAM, | |
569 | NULL, | |
570 | 0, | |
571 | NULL, | |
572 | 0, | |
573 | NULL, | |
574 | LOAD_REJECT, | |
575 | }, | |
576 | { | |
35749060 SF |
577 | "recvmsg4: rewrite IP & port (C)", |
578 | recvmsg4_rw_c_prog_load, | |
1812291e DB |
579 | BPF_CGROUP_UDP4_RECVMSG, |
580 | BPF_CGROUP_UDP4_RECVMSG, | |
581 | AF_INET, | |
582 | SOCK_DGRAM, | |
583 | SERV4_REWRITE_IP, | |
584 | SERV4_REWRITE_PORT, | |
585 | SERV4_REWRITE_IP, | |
586 | SERV4_REWRITE_PORT, | |
587 | SERV4_IP, | |
588 | SUCCESS, | |
589 | }, | |
590 | { | |
35749060 SF |
591 | "recvmsg6: rewrite IP & port (C)", |
592 | recvmsg6_rw_c_prog_load, | |
1812291e DB |
593 | BPF_CGROUP_UDP6_RECVMSG, |
594 | BPF_CGROUP_UDP6_RECVMSG, | |
595 | AF_INET6, | |
596 | SOCK_DGRAM, | |
597 | SERV6_REWRITE_IP, | |
598 | SERV6_REWRITE_PORT, | |
599 | SERV6_REWRITE_IP, | |
600 | SERV6_REWRITE_PORT, | |
601 | SERV6_IP, | |
602 | SUCCESS, | |
603 | }, | |
9be71aa6 | 604 | }; |
e50b0a6f AI |
605 | |
606 | static int mk_sockaddr(int domain, const char *ip, unsigned short port, | |
607 | struct sockaddr *addr, socklen_t addr_len) | |
608 | { | |
609 | struct sockaddr_in6 *addr6; | |
610 | struct sockaddr_in *addr4; | |
611 | ||
612 | if (domain != AF_INET && domain != AF_INET6) { | |
613 | log_err("Unsupported address family"); | |
614 | return -1; | |
615 | } | |
616 | ||
617 | memset(addr, 0, addr_len); | |
618 | ||
619 | if (domain == AF_INET) { | |
620 | if (addr_len < sizeof(struct sockaddr_in)) | |
621 | return -1; | |
622 | addr4 = (struct sockaddr_in *)addr; | |
623 | addr4->sin_family = domain; | |
624 | addr4->sin_port = htons(port); | |
625 | if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) { | |
626 | log_err("Invalid IPv4: %s", ip); | |
627 | return -1; | |
628 | } | |
629 | } else if (domain == AF_INET6) { | |
630 | if (addr_len < sizeof(struct sockaddr_in6)) | |
631 | return -1; | |
632 | addr6 = (struct sockaddr_in6 *)addr; | |
633 | addr6->sin6_family = domain; | |
634 | addr6->sin6_port = htons(port); | |
635 | if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) { | |
636 | log_err("Invalid IPv6: %s", ip); | |
637 | return -1; | |
638 | } | |
639 | } | |
640 | ||
641 | return 0; | |
642 | } | |
643 | ||
9be71aa6 AI |
644 | static int load_insns(const struct sock_addr_test *test, |
645 | const struct bpf_insn *insns, size_t insns_cnt) | |
e50b0a6f | 646 | { |
d8e86407 | 647 | LIBBPF_OPTS(bpf_prog_load_opts, opts); |
e50b0a6f AI |
648 | int ret; |
649 | ||
d8e86407 AN |
650 | opts.expected_attach_type = test->expected_attach_type; |
651 | opts.log_buf = bpf_log_buf; | |
652 | opts.log_size = BPF_LOG_BUF_SIZE; | |
e50b0a6f | 653 | |
d8e86407 | 654 | ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, NULL, "GPL", insns, insns_cnt, &opts); |
9be71aa6 AI |
655 | if (ret < 0 && test->expected_result != LOAD_REJECT) { |
656 | log_err(">>> Loading program error.\n" | |
657 | ">>> Verifier output:\n%s\n-------\n", bpf_log_buf); | |
e50b0a6f AI |
658 | } |
659 | ||
660 | return ret; | |
661 | } | |
662 | ||
9be71aa6 | 663 | static int load_path(const struct sock_addr_test *test, const char *path) |
622adafb | 664 | { |
622adafb | 665 | struct bpf_object *obj; |
186d1a86 AN |
666 | struct bpf_program *prog; |
667 | int err; | |
622adafb | 668 | |
186d1a86 AN |
669 | obj = bpf_object__open_file(path, NULL); |
670 | err = libbpf_get_error(obj); | |
671 | if (err) { | |
672 | log_err(">>> Opening BPF object (%s) error.\n", path); | |
673 | return -1; | |
674 | } | |
675 | ||
676 | prog = bpf_object__next_program(obj, NULL); | |
677 | if (!prog) | |
678 | goto err_out; | |
622adafb | 679 | |
186d1a86 AN |
680 | bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR); |
681 | bpf_program__set_expected_attach_type(prog, test->expected_attach_type); | |
682 | bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32); | |
683 | ||
684 | err = bpf_object__load(obj); | |
685 | if (err) { | |
9be71aa6 AI |
686 | if (test->expected_result != LOAD_REJECT) |
687 | log_err(">>> Loading program (%s) error.\n", path); | |
186d1a86 | 688 | goto err_out; |
622adafb AI |
689 | } |
690 | ||
186d1a86 AN |
691 | return bpf_program__fd(prog); |
692 | err_out: | |
693 | bpf_object__close(obj); | |
694 | return -1; | |
a999696c SF |
695 | } |
696 | ||
697 | static int bind4_prog_load(const struct sock_addr_test *test) | |
698 | { | |
699 | return load_path(test, BIND4_PROG_PATH); | |
700 | } | |
701 | ||
702 | static int bind6_prog_load(const struct sock_addr_test *test) | |
703 | { | |
704 | return load_path(test, BIND6_PROG_PATH); | |
622adafb AI |
705 | } |
706 | ||
9be71aa6 | 707 | static int connect4_prog_load(const struct sock_addr_test *test) |
622adafb | 708 | { |
9be71aa6 | 709 | return load_path(test, CONNECT4_PROG_PATH); |
622adafb AI |
710 | } |
711 | ||
9be71aa6 | 712 | static int connect6_prog_load(const struct sock_addr_test *test) |
622adafb | 713 | { |
9be71aa6 | 714 | return load_path(test, CONNECT6_PROG_PATH); |
622adafb AI |
715 | } |
716 | ||
1812291e DB |
717 | static int xmsg_ret_only_prog_load(const struct sock_addr_test *test, |
718 | int32_t rc) | |
04b6ab73 AI |
719 | { |
720 | struct bpf_insn insns[] = { | |
976b4f3a AI |
721 | /* return rc */ |
722 | BPF_MOV64_IMM(BPF_REG_0, rc), | |
04b6ab73 AI |
723 | BPF_EXIT_INSN(), |
724 | }; | |
f98d6dd1 | 725 | return load_insns(test, insns, ARRAY_SIZE(insns)); |
04b6ab73 AI |
726 | } |
727 | ||
976b4f3a AI |
728 | static int sendmsg_allow_prog_load(const struct sock_addr_test *test) |
729 | { | |
1812291e | 730 | return xmsg_ret_only_prog_load(test, /*rc*/ 1); |
976b4f3a AI |
731 | } |
732 | ||
733 | static int sendmsg_deny_prog_load(const struct sock_addr_test *test) | |
734 | { | |
1812291e DB |
735 | return xmsg_ret_only_prog_load(test, /*rc*/ 0); |
736 | } | |
737 | ||
738 | static int recvmsg_allow_prog_load(const struct sock_addr_test *test) | |
739 | { | |
740 | return xmsg_ret_only_prog_load(test, /*rc*/ 1); | |
741 | } | |
742 | ||
743 | static int recvmsg_deny_prog_load(const struct sock_addr_test *test) | |
744 | { | |
745 | return xmsg_ret_only_prog_load(test, /*rc*/ 0); | |
976b4f3a AI |
746 | } |
747 | ||
04b6ab73 AI |
748 | static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test) |
749 | { | |
750 | struct sockaddr_in dst4_rw_addr; | |
751 | struct in_addr src4_rw_ip; | |
752 | ||
753 | if (inet_pton(AF_INET, SRC4_REWRITE_IP, (void *)&src4_rw_ip) != 1) { | |
754 | log_err("Invalid IPv4: %s", SRC4_REWRITE_IP); | |
755 | return -1; | |
756 | } | |
757 | ||
758 | if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT, | |
759 | (struct sockaddr *)&dst4_rw_addr, | |
760 | sizeof(dst4_rw_addr)) == -1) | |
761 | return -1; | |
762 | ||
763 | struct bpf_insn insns[] = { | |
764 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | |
765 | ||
766 | /* if (sk.family == AF_INET && */ | |
767 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, | |
768 | offsetof(struct bpf_sock_addr, family)), | |
769 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 8), | |
770 | ||
771 | /* sk.type == SOCK_DGRAM) { */ | |
772 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, | |
773 | offsetof(struct bpf_sock_addr, type)), | |
774 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 6), | |
775 | ||
776 | /* msg_src_ip4 = src4_rw_ip */ | |
777 | BPF_MOV32_IMM(BPF_REG_7, src4_rw_ip.s_addr), | |
778 | BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, | |
779 | offsetof(struct bpf_sock_addr, msg_src_ip4)), | |
780 | ||
781 | /* user_ip4 = dst4_rw_addr.sin_addr */ | |
782 | BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_addr.s_addr), | |
783 | BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, | |
784 | offsetof(struct bpf_sock_addr, user_ip4)), | |
785 | ||
786 | /* user_port = dst4_rw_addr.sin_port */ | |
787 | BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_port), | |
788 | BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, | |
789 | offsetof(struct bpf_sock_addr, user_port)), | |
790 | /* } */ | |
791 | ||
792 | /* return 1 */ | |
793 | BPF_MOV64_IMM(BPF_REG_0, 1), | |
794 | BPF_EXIT_INSN(), | |
795 | }; | |
796 | ||
f98d6dd1 | 797 | return load_insns(test, insns, ARRAY_SIZE(insns)); |
04b6ab73 AI |
798 | } |
799 | ||
35749060 | 800 | static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test) |
1812291e | 801 | { |
35749060 | 802 | return load_path(test, RECVMSG4_PROG_PATH); |
1812291e DB |
803 | } |
804 | ||
04b6ab73 AI |
805 | static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test) |
806 | { | |
807 | return load_path(test, SENDMSG4_PROG_PATH); | |
808 | } | |
809 | ||
810 | static int sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test *test, | |
811 | const char *rw_dst_ip) | |
812 | { | |
813 | struct sockaddr_in6 dst6_rw_addr; | |
814 | struct in6_addr src6_rw_ip; | |
815 | ||
816 | if (inet_pton(AF_INET6, SRC6_REWRITE_IP, (void *)&src6_rw_ip) != 1) { | |
817 | log_err("Invalid IPv6: %s", SRC6_REWRITE_IP); | |
818 | return -1; | |
819 | } | |
820 | ||
821 | if (mk_sockaddr(AF_INET6, rw_dst_ip, SERV6_REWRITE_PORT, | |
822 | (struct sockaddr *)&dst6_rw_addr, | |
823 | sizeof(dst6_rw_addr)) == -1) | |
824 | return -1; | |
825 | ||
826 | struct bpf_insn insns[] = { | |
827 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | |
828 | ||
829 | /* if (sk.family == AF_INET6) { */ | |
830 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, | |
831 | offsetof(struct bpf_sock_addr, family)), | |
832 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18), | |
833 | ||
834 | #define STORE_IPV6_WORD_N(DST, SRC, N) \ | |
835 | BPF_MOV32_IMM(BPF_REG_7, SRC[N]), \ | |
836 | BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, \ | |
837 | offsetof(struct bpf_sock_addr, DST[N])) | |
838 | ||
839 | #define STORE_IPV6(DST, SRC) \ | |
840 | STORE_IPV6_WORD_N(DST, SRC, 0), \ | |
841 | STORE_IPV6_WORD_N(DST, SRC, 1), \ | |
842 | STORE_IPV6_WORD_N(DST, SRC, 2), \ | |
843 | STORE_IPV6_WORD_N(DST, SRC, 3) | |
844 | ||
845 | STORE_IPV6(msg_src_ip6, src6_rw_ip.s6_addr32), | |
846 | STORE_IPV6(user_ip6, dst6_rw_addr.sin6_addr.s6_addr32), | |
847 | ||
848 | /* user_port = dst6_rw_addr.sin6_port */ | |
849 | BPF_MOV32_IMM(BPF_REG_7, dst6_rw_addr.sin6_port), | |
850 | BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, | |
851 | offsetof(struct bpf_sock_addr, user_port)), | |
852 | ||
853 | /* } */ | |
854 | ||
855 | /* return 1 */ | |
856 | BPF_MOV64_IMM(BPF_REG_0, 1), | |
857 | BPF_EXIT_INSN(), | |
858 | }; | |
859 | ||
f98d6dd1 | 860 | return load_insns(test, insns, ARRAY_SIZE(insns)); |
04b6ab73 AI |
861 | } |
862 | ||
863 | static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test) | |
864 | { | |
865 | return sendmsg6_rw_dst_asm_prog_load(test, SERV6_REWRITE_IP); | |
866 | } | |
867 | ||
35749060 | 868 | static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test) |
1812291e | 869 | { |
35749060 | 870 | return load_path(test, RECVMSG6_PROG_PATH); |
1812291e DB |
871 | } |
872 | ||
04b6ab73 AI |
873 | static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test) |
874 | { | |
875 | return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP); | |
876 | } | |
877 | ||
976b4f3a AI |
878 | static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test) |
879 | { | |
880 | return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP); | |
881 | } | |
882 | ||
04b6ab73 AI |
883 | static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test) |
884 | { | |
885 | return load_path(test, SENDMSG6_PROG_PATH); | |
886 | } | |
887 | ||
9be71aa6 AI |
888 | static int cmp_addr(const struct sockaddr_storage *addr1, |
889 | const struct sockaddr_storage *addr2, int cmp_port) | |
e50b0a6f | 890 | { |
9be71aa6 AI |
891 | const struct sockaddr_in *four1, *four2; |
892 | const struct sockaddr_in6 *six1, *six2; | |
893 | ||
894 | if (addr1->ss_family != addr2->ss_family) | |
895 | return -1; | |
896 | ||
897 | if (addr1->ss_family == AF_INET) { | |
898 | four1 = (const struct sockaddr_in *)addr1; | |
899 | four2 = (const struct sockaddr_in *)addr2; | |
900 | return !((four1->sin_port == four2->sin_port || !cmp_port) && | |
901 | four1->sin_addr.s_addr == four2->sin_addr.s_addr); | |
902 | } else if (addr1->ss_family == AF_INET6) { | |
903 | six1 = (const struct sockaddr_in6 *)addr1; | |
904 | six2 = (const struct sockaddr_in6 *)addr2; | |
905 | return !((six1->sin6_port == six2->sin6_port || !cmp_port) && | |
906 | !memcmp(&six1->sin6_addr, &six2->sin6_addr, | |
907 | sizeof(struct in6_addr))); | |
e50b0a6f | 908 | } |
9be71aa6 AI |
909 | |
910 | return -1; | |
911 | } | |
912 | ||
913 | static int cmp_sock_addr(info_fn fn, int sock1, | |
914 | const struct sockaddr_storage *addr2, int cmp_port) | |
915 | { | |
916 | struct sockaddr_storage addr1; | |
917 | socklen_t len1 = sizeof(addr1); | |
918 | ||
919 | memset(&addr1, 0, len1); | |
920 | if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0) | |
921 | return -1; | |
922 | ||
923 | return cmp_addr(&addr1, addr2, cmp_port); | |
924 | } | |
925 | ||
926 | static int cmp_local_ip(int sock1, const struct sockaddr_storage *addr2) | |
927 | { | |
928 | return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 0); | |
e50b0a6f AI |
929 | } |
930 | ||
9be71aa6 | 931 | static int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2) |
e50b0a6f | 932 | { |
9be71aa6 | 933 | return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 1); |
e50b0a6f AI |
934 | } |
935 | ||
9be71aa6 | 936 | static int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2) |
622adafb | 937 | { |
9be71aa6 | 938 | return cmp_sock_addr(getpeername, sock1, addr2, /*cmp_port*/ 1); |
622adafb AI |
939 | } |
940 | ||
e50b0a6f AI |
941 | static int start_server(int type, const struct sockaddr_storage *addr, |
942 | socklen_t addr_len) | |
943 | { | |
e50b0a6f AI |
944 | int fd; |
945 | ||
946 | fd = socket(addr->ss_family, type, 0); | |
947 | if (fd == -1) { | |
948 | log_err("Failed to create server socket"); | |
949 | goto out; | |
950 | } | |
951 | ||
952 | if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) { | |
953 | log_err("Failed to bind server socket"); | |
954 | goto close_out; | |
955 | } | |
956 | ||
957 | if (type == SOCK_STREAM) { | |
958 | if (listen(fd, 128) == -1) { | |
959 | log_err("Failed to listen on server socket"); | |
960 | goto close_out; | |
961 | } | |
962 | } | |
963 | ||
e50b0a6f AI |
964 | goto out; |
965 | close_out: | |
966 | close(fd); | |
967 | fd = -1; | |
968 | out: | |
969 | return fd; | |
970 | } | |
971 | ||
622adafb AI |
972 | static int connect_to_server(int type, const struct sockaddr_storage *addr, |
973 | socklen_t addr_len) | |
974 | { | |
975 | int domain; | |
9be71aa6 | 976 | int fd = -1; |
622adafb AI |
977 | |
978 | domain = addr->ss_family; | |
979 | ||
980 | if (domain != AF_INET && domain != AF_INET6) { | |
981 | log_err("Unsupported address family"); | |
9be71aa6 | 982 | goto err; |
622adafb AI |
983 | } |
984 | ||
985 | fd = socket(domain, type, 0); | |
986 | if (fd == -1) { | |
9be71aa6 AI |
987 | log_err("Failed to create client socket"); |
988 | goto err; | |
622adafb AI |
989 | } |
990 | ||
991 | if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) { | |
992 | log_err("Fail to connect to server"); | |
993 | goto err; | |
994 | } | |
995 | ||
9be71aa6 | 996 | goto out; |
622adafb AI |
997 | err: |
998 | close(fd); | |
9be71aa6 AI |
999 | fd = -1; |
1000 | out: | |
1001 | return fd; | |
622adafb AI |
1002 | } |
1003 | ||
04b6ab73 AI |
1004 | int init_pktinfo(int domain, struct cmsghdr *cmsg) |
1005 | { | |
1006 | struct in6_pktinfo *pktinfo6; | |
1007 | struct in_pktinfo *pktinfo4; | |
1008 | ||
1009 | if (domain == AF_INET) { | |
1010 | cmsg->cmsg_level = SOL_IP; | |
1011 | cmsg->cmsg_type = IP_PKTINFO; | |
1012 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); | |
1013 | pktinfo4 = (struct in_pktinfo *)CMSG_DATA(cmsg); | |
1014 | memset(pktinfo4, 0, sizeof(struct in_pktinfo)); | |
1015 | if (inet_pton(domain, SRC4_IP, | |
1016 | (void *)&pktinfo4->ipi_spec_dst) != 1) | |
1017 | return -1; | |
1018 | } else if (domain == AF_INET6) { | |
1019 | cmsg->cmsg_level = SOL_IPV6; | |
1020 | cmsg->cmsg_type = IPV6_PKTINFO; | |
1021 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); | |
1022 | pktinfo6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); | |
1023 | memset(pktinfo6, 0, sizeof(struct in6_pktinfo)); | |
1024 | if (inet_pton(domain, SRC6_IP, | |
1025 | (void *)&pktinfo6->ipi6_addr) != 1) | |
1026 | return -1; | |
1027 | } else { | |
1028 | return -1; | |
1029 | } | |
1030 | ||
1031 | return 0; | |
1032 | } | |
1033 | ||
a7f7547f AI |
1034 | static int sendmsg_to_server(int type, const struct sockaddr_storage *addr, |
1035 | socklen_t addr_len, int set_cmsg, int flags, | |
1036 | int *syscall_err) | |
04b6ab73 AI |
1037 | { |
1038 | union { | |
1039 | char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; | |
1040 | struct cmsghdr align; | |
1041 | } control6; | |
1042 | union { | |
1043 | char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; | |
1044 | struct cmsghdr align; | |
1045 | } control4; | |
1046 | struct msghdr hdr; | |
1047 | struct iovec iov; | |
1048 | char data = 'a'; | |
1049 | int domain; | |
1050 | int fd = -1; | |
1051 | ||
1052 | domain = addr->ss_family; | |
1053 | ||
1054 | if (domain != AF_INET && domain != AF_INET6) { | |
1055 | log_err("Unsupported address family"); | |
1056 | goto err; | |
1057 | } | |
1058 | ||
a7f7547f | 1059 | fd = socket(domain, type, 0); |
04b6ab73 AI |
1060 | if (fd == -1) { |
1061 | log_err("Failed to create client socket"); | |
1062 | goto err; | |
1063 | } | |
1064 | ||
1065 | memset(&iov, 0, sizeof(iov)); | |
1066 | iov.iov_base = &data; | |
1067 | iov.iov_len = sizeof(data); | |
1068 | ||
1069 | memset(&hdr, 0, sizeof(hdr)); | |
1070 | hdr.msg_name = (void *)addr; | |
1071 | hdr.msg_namelen = addr_len; | |
1072 | hdr.msg_iov = &iov; | |
1073 | hdr.msg_iovlen = 1; | |
1074 | ||
1075 | if (set_cmsg) { | |
1076 | if (domain == AF_INET) { | |
1077 | hdr.msg_control = &control4; | |
1078 | hdr.msg_controllen = sizeof(control4.buf); | |
1079 | } else if (domain == AF_INET6) { | |
1080 | hdr.msg_control = &control6; | |
1081 | hdr.msg_controllen = sizeof(control6.buf); | |
1082 | } | |
1083 | if (init_pktinfo(domain, CMSG_FIRSTHDR(&hdr))) { | |
1084 | log_err("Fail to init pktinfo"); | |
1085 | goto err; | |
1086 | } | |
1087 | } | |
1088 | ||
a7f7547f | 1089 | if (sendmsg(fd, &hdr, flags) != sizeof(data)) { |
04b6ab73 AI |
1090 | log_err("Fail to send message to server"); |
1091 | *syscall_err = errno; | |
1092 | goto err; | |
1093 | } | |
1094 | ||
1095 | goto out; | |
1096 | err: | |
1097 | close(fd); | |
1098 | fd = -1; | |
1099 | out: | |
1100 | return fd; | |
1101 | } | |
1102 | ||
a7f7547f AI |
1103 | static int fastconnect_to_server(const struct sockaddr_storage *addr, |
1104 | socklen_t addr_len) | |
1105 | { | |
1106 | int sendmsg_err; | |
1107 | ||
1108 | return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0, | |
1109 | MSG_FASTOPEN, &sendmsg_err); | |
1110 | } | |
1111 | ||
04b6ab73 AI |
1112 | static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr) |
1113 | { | |
1114 | struct timeval tv; | |
1115 | struct msghdr hdr; | |
1116 | struct iovec iov; | |
1117 | char data[64]; | |
1118 | fd_set rfds; | |
1119 | ||
1120 | FD_ZERO(&rfds); | |
1121 | FD_SET(sockfd, &rfds); | |
1122 | ||
1123 | tv.tv_sec = 2; | |
1124 | tv.tv_usec = 0; | |
1125 | ||
1126 | if (select(sockfd + 1, &rfds, NULL, NULL, &tv) <= 0 || | |
1127 | !FD_ISSET(sockfd, &rfds)) | |
1128 | return -1; | |
1129 | ||
1130 | memset(&iov, 0, sizeof(iov)); | |
1131 | iov.iov_base = data; | |
1132 | iov.iov_len = sizeof(data); | |
1133 | ||
1134 | memset(&hdr, 0, sizeof(hdr)); | |
1135 | hdr.msg_name = src_addr; | |
1136 | hdr.msg_namelen = sizeof(struct sockaddr_storage); | |
1137 | hdr.msg_iov = &iov; | |
1138 | hdr.msg_iovlen = 1; | |
1139 | ||
1140 | return recvmsg(sockfd, &hdr, 0); | |
1141 | } | |
1142 | ||
9be71aa6 AI |
1143 | static int init_addrs(const struct sock_addr_test *test, |
1144 | struct sockaddr_storage *requested_addr, | |
1145 | struct sockaddr_storage *expected_addr, | |
1146 | struct sockaddr_storage *expected_src_addr) | |
e50b0a6f | 1147 | { |
9be71aa6 AI |
1148 | socklen_t addr_len = sizeof(struct sockaddr_storage); |
1149 | ||
1150 | if (mk_sockaddr(test->domain, test->expected_ip, test->expected_port, | |
1151 | (struct sockaddr *)expected_addr, addr_len) == -1) | |
1152 | goto err; | |
1153 | ||
1154 | if (mk_sockaddr(test->domain, test->requested_ip, test->requested_port, | |
1155 | (struct sockaddr *)requested_addr, addr_len) == -1) | |
1156 | goto err; | |
1157 | ||
1158 | if (test->expected_src_ip && | |
1159 | mk_sockaddr(test->domain, test->expected_src_ip, 0, | |
1160 | (struct sockaddr *)expected_src_addr, addr_len) == -1) | |
1161 | goto err; | |
1162 | ||
1163 | return 0; | |
1164 | err: | |
1165 | return -1; | |
e50b0a6f AI |
1166 | } |
1167 | ||
9be71aa6 | 1168 | static int run_bind_test_case(const struct sock_addr_test *test) |
e50b0a6f | 1169 | { |
9be71aa6 AI |
1170 | socklen_t addr_len = sizeof(struct sockaddr_storage); |
1171 | struct sockaddr_storage requested_addr; | |
1172 | struct sockaddr_storage expected_addr; | |
1173 | int clientfd = -1; | |
e50b0a6f AI |
1174 | int servfd = -1; |
1175 | int err = 0; | |
1176 | ||
9be71aa6 AI |
1177 | if (init_addrs(test, &requested_addr, &expected_addr, NULL)) |
1178 | goto err; | |
e50b0a6f | 1179 | |
9be71aa6 | 1180 | servfd = start_server(test->type, &requested_addr, addr_len); |
e50b0a6f AI |
1181 | if (servfd == -1) |
1182 | goto err; | |
1183 | ||
9be71aa6 AI |
1184 | if (cmp_local_addr(servfd, &expected_addr)) |
1185 | goto err; | |
1186 | ||
1187 | /* Try to connect to server just in case */ | |
1188 | clientfd = connect_to_server(test->type, &expected_addr, addr_len); | |
1189 | if (clientfd == -1) | |
622adafb AI |
1190 | goto err; |
1191 | ||
e50b0a6f AI |
1192 | goto out; |
1193 | err: | |
1194 | err = -1; | |
1195 | out: | |
9be71aa6 | 1196 | close(clientfd); |
e50b0a6f AI |
1197 | close(servfd); |
1198 | return err; | |
1199 | } | |
1200 | ||
9be71aa6 | 1201 | static int run_connect_test_case(const struct sock_addr_test *test) |
e50b0a6f | 1202 | { |
9be71aa6 AI |
1203 | socklen_t addr_len = sizeof(struct sockaddr_storage); |
1204 | struct sockaddr_storage expected_src_addr; | |
1205 | struct sockaddr_storage requested_addr; | |
1206 | struct sockaddr_storage expected_addr; | |
1207 | int clientfd = -1; | |
1208 | int servfd = -1; | |
1209 | int err = 0; | |
e50b0a6f | 1210 | |
9be71aa6 AI |
1211 | if (init_addrs(test, &requested_addr, &expected_addr, |
1212 | &expected_src_addr)) | |
1213 | goto err; | |
e50b0a6f | 1214 | |
9be71aa6 AI |
1215 | /* Prepare server to connect to */ |
1216 | servfd = start_server(test->type, &expected_addr, addr_len); | |
1217 | if (servfd == -1) | |
1218 | goto err; | |
622adafb | 1219 | |
9be71aa6 AI |
1220 | clientfd = connect_to_server(test->type, &requested_addr, addr_len); |
1221 | if (clientfd == -1) | |
1222 | goto err; | |
622adafb | 1223 | |
9be71aa6 AI |
1224 | /* Make sure src and dst addrs were overridden properly */ |
1225 | if (cmp_peer_addr(clientfd, &expected_addr)) | |
1226 | goto err; | |
e50b0a6f | 1227 | |
9be71aa6 AI |
1228 | if (cmp_local_ip(clientfd, &expected_src_addr)) |
1229 | goto err; | |
1230 | ||
a7f7547f AI |
1231 | if (test->type == SOCK_STREAM) { |
1232 | /* Test TCP Fast Open scenario */ | |
1233 | clientfd = fastconnect_to_server(&requested_addr, addr_len); | |
1234 | if (clientfd == -1) | |
1235 | goto err; | |
1236 | ||
1237 | /* Make sure src and dst addrs were overridden properly */ | |
1238 | if (cmp_peer_addr(clientfd, &expected_addr)) | |
1239 | goto err; | |
1240 | ||
1241 | if (cmp_local_ip(clientfd, &expected_src_addr)) | |
1242 | goto err; | |
1243 | } | |
1244 | ||
9be71aa6 | 1245 | goto out; |
e50b0a6f | 1246 | err: |
9be71aa6 AI |
1247 | err = -1; |
1248 | out: | |
1249 | close(clientfd); | |
1250 | close(servfd); | |
1251 | return err; | |
e50b0a6f AI |
1252 | } |
1253 | ||
1812291e | 1254 | static int run_xmsg_test_case(const struct sock_addr_test *test, int max_cmsg) |
04b6ab73 AI |
1255 | { |
1256 | socklen_t addr_len = sizeof(struct sockaddr_storage); | |
04b6ab73 | 1257 | struct sockaddr_storage expected_addr; |
1812291e DB |
1258 | struct sockaddr_storage server_addr; |
1259 | struct sockaddr_storage sendmsg_addr; | |
1260 | struct sockaddr_storage recvmsg_addr; | |
04b6ab73 AI |
1261 | int clientfd = -1; |
1262 | int servfd = -1; | |
1263 | int set_cmsg; | |
1264 | int err = 0; | |
1265 | ||
1266 | if (test->type != SOCK_DGRAM) | |
1267 | goto err; | |
1268 | ||
1812291e | 1269 | if (init_addrs(test, &sendmsg_addr, &server_addr, &expected_addr)) |
04b6ab73 AI |
1270 | goto err; |
1271 | ||
1272 | /* Prepare server to sendmsg to */ | |
1812291e | 1273 | servfd = start_server(test->type, &server_addr, addr_len); |
04b6ab73 AI |
1274 | if (servfd == -1) |
1275 | goto err; | |
1276 | ||
1812291e | 1277 | for (set_cmsg = 0; set_cmsg <= max_cmsg; ++set_cmsg) { |
04b6ab73 AI |
1278 | if (clientfd >= 0) |
1279 | close(clientfd); | |
1280 | ||
1812291e | 1281 | clientfd = sendmsg_to_server(test->type, &sendmsg_addr, |
a7f7547f AI |
1282 | addr_len, set_cmsg, /*flags*/0, |
1283 | &err); | |
04b6ab73 AI |
1284 | if (err) |
1285 | goto out; | |
1286 | else if (clientfd == -1) | |
1287 | goto err; | |
1288 | ||
1289 | /* Try to receive message on server instead of using | |
1290 | * getpeername(2) on client socket, to check that client's | |
1291 | * destination address was rewritten properly, since | |
1292 | * getpeername(2) doesn't work with unconnected datagram | |
1293 | * sockets. | |
1294 | * | |
1295 | * Get source address from recvmsg(2) as well to make sure | |
1296 | * source was rewritten properly: getsockname(2) can't be used | |
1297 | * since socket is unconnected and source defined for one | |
1298 | * specific packet may differ from the one used by default and | |
1299 | * returned by getsockname(2). | |
1300 | */ | |
1812291e | 1301 | if (recvmsg_from_client(servfd, &recvmsg_addr) == -1) |
04b6ab73 AI |
1302 | goto err; |
1303 | ||
1812291e | 1304 | if (cmp_addr(&recvmsg_addr, &expected_addr, /*cmp_port*/0)) |
04b6ab73 AI |
1305 | goto err; |
1306 | } | |
1307 | ||
1308 | goto out; | |
1309 | err: | |
1310 | err = -1; | |
1311 | out: | |
1312 | close(clientfd); | |
1313 | close(servfd); | |
1314 | return err; | |
1315 | } | |
1316 | ||
9be71aa6 | 1317 | static int run_test_case(int cgfd, const struct sock_addr_test *test) |
e50b0a6f | 1318 | { |
9be71aa6 | 1319 | int progfd = -1; |
e50b0a6f AI |
1320 | int err = 0; |
1321 | ||
9be71aa6 AI |
1322 | printf("Test case: %s .. ", test->descr); |
1323 | ||
1324 | progfd = test->loadfn(test); | |
1325 | if (test->expected_result == LOAD_REJECT && progfd < 0) | |
1326 | goto out; | |
1327 | else if (test->expected_result == LOAD_REJECT || progfd < 0) | |
1328 | goto err; | |
1329 | ||
1330 | err = bpf_prog_attach(progfd, cgfd, test->attach_type, | |
1331 | BPF_F_ALLOW_OVERRIDE); | |
1332 | if (test->expected_result == ATTACH_REJECT && err) { | |
1333 | err = 0; /* error was expected, reset it */ | |
1334 | goto out; | |
1335 | } else if (test->expected_result == ATTACH_REJECT || err) { | |
e50b0a6f | 1336 | goto err; |
1812291e DB |
1337 | } else if (test->expected_result == ATTACH_OKAY) { |
1338 | err = 0; | |
1339 | goto out; | |
9be71aa6 | 1340 | } |
e50b0a6f | 1341 | |
9be71aa6 AI |
1342 | switch (test->attach_type) { |
1343 | case BPF_CGROUP_INET4_BIND: | |
1344 | case BPF_CGROUP_INET6_BIND: | |
1345 | err = run_bind_test_case(test); | |
1346 | break; | |
1347 | case BPF_CGROUP_INET4_CONNECT: | |
1348 | case BPF_CGROUP_INET6_CONNECT: | |
1349 | err = run_connect_test_case(test); | |
1350 | break; | |
04b6ab73 AI |
1351 | case BPF_CGROUP_UDP4_SENDMSG: |
1352 | case BPF_CGROUP_UDP6_SENDMSG: | |
1812291e DB |
1353 | err = run_xmsg_test_case(test, 1); |
1354 | break; | |
1355 | case BPF_CGROUP_UDP4_RECVMSG: | |
1356 | case BPF_CGROUP_UDP6_RECVMSG: | |
1357 | err = run_xmsg_test_case(test, 0); | |
04b6ab73 | 1358 | break; |
9be71aa6 | 1359 | default: |
e50b0a6f | 1360 | goto err; |
9be71aa6 | 1361 | } |
e50b0a6f | 1362 | |
04b6ab73 AI |
1363 | if (test->expected_result == SYSCALL_EPERM && err == EPERM) { |
1364 | err = 0; /* error was expected, reset it */ | |
1365 | goto out; | |
1366 | } | |
1367 | ||
1368 | if (test->expected_result == SYSCALL_ENOTSUPP && err == ENOTSUPP) { | |
1369 | err = 0; /* error was expected, reset it */ | |
1370 | goto out; | |
1371 | } | |
1372 | ||
9be71aa6 | 1373 | if (err || test->expected_result != SUCCESS) |
e50b0a6f AI |
1374 | goto err; |
1375 | ||
1376 | goto out; | |
1377 | err: | |
1378 | err = -1; | |
1379 | out: | |
9be71aa6 AI |
1380 | /* Detaching w/o checking return code: best effort attempt. */ |
1381 | if (progfd != -1) | |
1382 | bpf_prog_detach(cgfd, test->attach_type); | |
1383 | close(progfd); | |
1384 | printf("[%s]\n", err ? "FAIL" : "PASS"); | |
e50b0a6f AI |
1385 | return err; |
1386 | } | |
1387 | ||
9be71aa6 AI |
1388 | static int run_tests(int cgfd) |
1389 | { | |
1390 | int passes = 0; | |
1391 | int fails = 0; | |
1392 | int i; | |
1393 | ||
1394 | for (i = 0; i < ARRAY_SIZE(tests); ++i) { | |
1395 | if (run_test_case(cgfd, &tests[i])) | |
1396 | ++fails; | |
1397 | else | |
1398 | ++passes; | |
1399 | } | |
1400 | printf("Summary: %d PASSED, %d FAILED\n", passes, fails); | |
1401 | return fails ? -1 : 0; | |
1402 | } | |
1403 | ||
1404 | int main(int argc, char **argv) | |
e50b0a6f | 1405 | { |
e50b0a6f AI |
1406 | int cgfd = -1; |
1407 | int err = 0; | |
1408 | ||
9be71aa6 AI |
1409 | if (argc < 2) { |
1410 | fprintf(stderr, | |
1411 | "%s has to be run via %s.sh. Skip direct run.\n", | |
1412 | argv[0], argv[0]); | |
1413 | exit(err); | |
1414 | } | |
e50b0a6f | 1415 | |
4939b284 | 1416 | cgfd = cgroup_setup_and_join(CG_PATH); |
a8911d6d | 1417 | if (cgfd < 0) |
e50b0a6f AI |
1418 | goto err; |
1419 | ||
b858ba8c YS |
1420 | /* Use libbpf 1.0 API mode */ |
1421 | libbpf_set_strict_mode(LIBBPF_STRICT_ALL); | |
1422 | ||
9be71aa6 | 1423 | if (run_tests(cgfd)) |
e50b0a6f AI |
1424 | goto err; |
1425 | ||
1426 | goto out; | |
1427 | err: | |
1428 | err = -1; | |
1429 | out: | |
1430 | close(cgfd); | |
1431 | cleanup_cgroup_environment(); | |
e50b0a6f AI |
1432 | return err; |
1433 | } |