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