xref: /openbmc/linux/tools/testing/selftests/bpf/test_sock_addr.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1e50b0a6fSAndrey Ignatov // SPDX-License-Identifier: GPL-2.0
2e50b0a6fSAndrey Ignatov // Copyright (c) 2018 Facebook
3e50b0a6fSAndrey Ignatov 
404b6ab73SAndrey Ignatov #define _GNU_SOURCE
504b6ab73SAndrey Ignatov 
6e50b0a6fSAndrey Ignatov #include <stdio.h>
7e50b0a6fSAndrey Ignatov #include <stdlib.h>
8e50b0a6fSAndrey Ignatov #include <unistd.h>
9e50b0a6fSAndrey Ignatov 
10e50b0a6fSAndrey Ignatov #include <arpa/inet.h>
1104b6ab73SAndrey Ignatov #include <netinet/in.h>
12e50b0a6fSAndrey Ignatov #include <sys/types.h>
1304b6ab73SAndrey Ignatov #include <sys/select.h>
14e50b0a6fSAndrey Ignatov #include <sys/socket.h>
15e50b0a6fSAndrey Ignatov 
16e50b0a6fSAndrey Ignatov #include <linux/filter.h>
17e50b0a6fSAndrey Ignatov 
18e50b0a6fSAndrey Ignatov #include <bpf/bpf.h>
19622adafbSAndrey Ignatov #include <bpf/libbpf.h>
20e50b0a6fSAndrey Ignatov 
21e50b0a6fSAndrey Ignatov #include "cgroup_helpers.h"
22aa5f0c96SMartin KaFai Lau #include "bpf_util.h"
23e50b0a6fSAndrey Ignatov 
2404b6ab73SAndrey Ignatov #ifndef ENOTSUPP
2504b6ab73SAndrey Ignatov # define ENOTSUPP 524
2604b6ab73SAndrey Ignatov #endif
2704b6ab73SAndrey Ignatov 
28e50b0a6fSAndrey Ignatov #define CG_PATH	"/foo"
29*afef88e6SDaniel Müller #define CONNECT4_PROG_PATH	"./connect4_prog.bpf.o"
30*afef88e6SDaniel Müller #define CONNECT6_PROG_PATH	"./connect6_prog.bpf.o"
31*afef88e6SDaniel Müller #define SENDMSG4_PROG_PATH	"./sendmsg4_prog.bpf.o"
32*afef88e6SDaniel Müller #define SENDMSG6_PROG_PATH	"./sendmsg6_prog.bpf.o"
33*afef88e6SDaniel Müller #define RECVMSG4_PROG_PATH	"./recvmsg4_prog.bpf.o"
34*afef88e6SDaniel Müller #define RECVMSG6_PROG_PATH	"./recvmsg6_prog.bpf.o"
35*afef88e6SDaniel Müller #define BIND4_PROG_PATH		"./bind4_prog.bpf.o"
36*afef88e6SDaniel Müller #define BIND6_PROG_PATH		"./bind6_prog.bpf.o"
37e50b0a6fSAndrey Ignatov 
38e50b0a6fSAndrey Ignatov #define SERV4_IP		"192.168.1.254"
39e50b0a6fSAndrey Ignatov #define SERV4_REWRITE_IP	"127.0.0.1"
4004b6ab73SAndrey Ignatov #define SRC4_IP			"172.16.0.1"
419be71aa6SAndrey Ignatov #define SRC4_REWRITE_IP		"127.0.0.4"
42e50b0a6fSAndrey Ignatov #define SERV4_PORT		4040
43e50b0a6fSAndrey Ignatov #define SERV4_REWRITE_PORT	4444
44e50b0a6fSAndrey Ignatov 
45e50b0a6fSAndrey Ignatov #define SERV6_IP		"face:b00c:1234:5678::abcd"
46e50b0a6fSAndrey Ignatov #define SERV6_REWRITE_IP	"::1"
4704b6ab73SAndrey Ignatov #define SERV6_V4MAPPED_IP	"::ffff:192.168.0.4"
4804b6ab73SAndrey Ignatov #define SRC6_IP			"::1"
499be71aa6SAndrey Ignatov #define SRC6_REWRITE_IP		"::6"
50976b4f3aSAndrey Ignatov #define WILDCARD6_IP		"::"
51e50b0a6fSAndrey Ignatov #define SERV6_PORT		6060
52e50b0a6fSAndrey Ignatov #define SERV6_REWRITE_PORT	6666
53e50b0a6fSAndrey Ignatov 
54e50b0a6fSAndrey Ignatov #define INET_NTOP_BUF	40
55e50b0a6fSAndrey Ignatov 
569be71aa6SAndrey Ignatov struct sock_addr_test;
579be71aa6SAndrey Ignatov 
589be71aa6SAndrey Ignatov typedef int (*load_fn)(const struct sock_addr_test *test);
59e50b0a6fSAndrey Ignatov typedef int (*info_fn)(int, struct sockaddr *, socklen_t *);
60e50b0a6fSAndrey Ignatov 
619be71aa6SAndrey Ignatov char bpf_log_buf[BPF_LOG_BUF_SIZE];
629be71aa6SAndrey Ignatov 
639be71aa6SAndrey Ignatov struct sock_addr_test {
649be71aa6SAndrey Ignatov 	const char *descr;
659be71aa6SAndrey Ignatov 	/* BPF prog properties */
66e50b0a6fSAndrey Ignatov 	load_fn loadfn;
679be71aa6SAndrey Ignatov 	enum bpf_attach_type expected_attach_type;
689be71aa6SAndrey Ignatov 	enum bpf_attach_type attach_type;
699be71aa6SAndrey Ignatov 	/* Socket properties */
709be71aa6SAndrey Ignatov 	int domain;
719be71aa6SAndrey Ignatov 	int type;
729be71aa6SAndrey Ignatov 	/* IP:port pairs for BPF prog to override */
739be71aa6SAndrey Ignatov 	const char *requested_ip;
749be71aa6SAndrey Ignatov 	unsigned short requested_port;
759be71aa6SAndrey Ignatov 	const char *expected_ip;
769be71aa6SAndrey Ignatov 	unsigned short expected_port;
779be71aa6SAndrey Ignatov 	const char *expected_src_ip;
789be71aa6SAndrey Ignatov 	/* Expected test result */
799be71aa6SAndrey Ignatov 	enum {
809be71aa6SAndrey Ignatov 		LOAD_REJECT,
819be71aa6SAndrey Ignatov 		ATTACH_REJECT,
821812291eSDaniel Borkmann 		ATTACH_OKAY,
8304b6ab73SAndrey Ignatov 		SYSCALL_EPERM,
8404b6ab73SAndrey Ignatov 		SYSCALL_ENOTSUPP,
859be71aa6SAndrey Ignatov 		SUCCESS,
869be71aa6SAndrey Ignatov 	} expected_result;
87e50b0a6fSAndrey Ignatov };
88e50b0a6fSAndrey Ignatov 
899be71aa6SAndrey Ignatov static int bind4_prog_load(const struct sock_addr_test *test);
909be71aa6SAndrey Ignatov static int bind6_prog_load(const struct sock_addr_test *test);
919be71aa6SAndrey Ignatov static int connect4_prog_load(const struct sock_addr_test *test);
929be71aa6SAndrey Ignatov static int connect6_prog_load(const struct sock_addr_test *test);
93976b4f3aSAndrey Ignatov static int sendmsg_allow_prog_load(const struct sock_addr_test *test);
9404b6ab73SAndrey Ignatov static int sendmsg_deny_prog_load(const struct sock_addr_test *test);
951812291eSDaniel Borkmann static int recvmsg_allow_prog_load(const struct sock_addr_test *test);
961812291eSDaniel Borkmann static int recvmsg_deny_prog_load(const struct sock_addr_test *test);
9704b6ab73SAndrey Ignatov static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test);
9835749060SStanislav Fomichev static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test);
9904b6ab73SAndrey Ignatov static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test);
10004b6ab73SAndrey Ignatov static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test);
10135749060SStanislav Fomichev static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test);
10204b6ab73SAndrey Ignatov static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test);
10304b6ab73SAndrey Ignatov static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test);
104976b4f3aSAndrey Ignatov static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test);
1059be71aa6SAndrey Ignatov 
1069be71aa6SAndrey Ignatov static struct sock_addr_test tests[] = {
1079be71aa6SAndrey Ignatov 	/* bind */
1089be71aa6SAndrey Ignatov 	{
1099be71aa6SAndrey Ignatov 		"bind4: load prog with wrong expected attach type",
1109be71aa6SAndrey Ignatov 		bind4_prog_load,
1119be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_BIND,
1129be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_BIND,
1139be71aa6SAndrey Ignatov 		AF_INET,
1149be71aa6SAndrey Ignatov 		SOCK_STREAM,
1159be71aa6SAndrey Ignatov 		NULL,
1169be71aa6SAndrey Ignatov 		0,
1179be71aa6SAndrey Ignatov 		NULL,
1189be71aa6SAndrey Ignatov 		0,
1199be71aa6SAndrey Ignatov 		NULL,
1209be71aa6SAndrey Ignatov 		LOAD_REJECT,
1219be71aa6SAndrey Ignatov 	},
1229be71aa6SAndrey Ignatov 	{
1239be71aa6SAndrey Ignatov 		"bind4: attach prog with wrong attach type",
1249be71aa6SAndrey Ignatov 		bind4_prog_load,
1259be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_BIND,
1269be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_BIND,
1279be71aa6SAndrey Ignatov 		AF_INET,
1289be71aa6SAndrey Ignatov 		SOCK_STREAM,
1299be71aa6SAndrey Ignatov 		NULL,
1309be71aa6SAndrey Ignatov 		0,
1319be71aa6SAndrey Ignatov 		NULL,
1329be71aa6SAndrey Ignatov 		0,
1339be71aa6SAndrey Ignatov 		NULL,
1349be71aa6SAndrey Ignatov 		ATTACH_REJECT,
1359be71aa6SAndrey Ignatov 	},
1369be71aa6SAndrey Ignatov 	{
1379be71aa6SAndrey Ignatov 		"bind4: rewrite IP & TCP port in",
1389be71aa6SAndrey Ignatov 		bind4_prog_load,
1399be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_BIND,
1409be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_BIND,
1419be71aa6SAndrey Ignatov 		AF_INET,
1429be71aa6SAndrey Ignatov 		SOCK_STREAM,
1439be71aa6SAndrey Ignatov 		SERV4_IP,
1449be71aa6SAndrey Ignatov 		SERV4_PORT,
1459be71aa6SAndrey Ignatov 		SERV4_REWRITE_IP,
1469be71aa6SAndrey Ignatov 		SERV4_REWRITE_PORT,
1479be71aa6SAndrey Ignatov 		NULL,
1489be71aa6SAndrey Ignatov 		SUCCESS,
1499be71aa6SAndrey Ignatov 	},
1509be71aa6SAndrey Ignatov 	{
1519be71aa6SAndrey Ignatov 		"bind4: rewrite IP & UDP port in",
1529be71aa6SAndrey Ignatov 		bind4_prog_load,
1539be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_BIND,
1549be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_BIND,
1559be71aa6SAndrey Ignatov 		AF_INET,
1569be71aa6SAndrey Ignatov 		SOCK_DGRAM,
1579be71aa6SAndrey Ignatov 		SERV4_IP,
1589be71aa6SAndrey Ignatov 		SERV4_PORT,
1599be71aa6SAndrey Ignatov 		SERV4_REWRITE_IP,
1609be71aa6SAndrey Ignatov 		SERV4_REWRITE_PORT,
1619be71aa6SAndrey Ignatov 		NULL,
1629be71aa6SAndrey Ignatov 		SUCCESS,
1639be71aa6SAndrey Ignatov 	},
1649be71aa6SAndrey Ignatov 	{
1659be71aa6SAndrey Ignatov 		"bind6: load prog with wrong expected attach type",
1669be71aa6SAndrey Ignatov 		bind6_prog_load,
1679be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_BIND,
1689be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_BIND,
1699be71aa6SAndrey Ignatov 		AF_INET6,
1709be71aa6SAndrey Ignatov 		SOCK_STREAM,
1719be71aa6SAndrey Ignatov 		NULL,
1729be71aa6SAndrey Ignatov 		0,
1739be71aa6SAndrey Ignatov 		NULL,
1749be71aa6SAndrey Ignatov 		0,
1759be71aa6SAndrey Ignatov 		NULL,
1769be71aa6SAndrey Ignatov 		LOAD_REJECT,
1779be71aa6SAndrey Ignatov 	},
1789be71aa6SAndrey Ignatov 	{
1799be71aa6SAndrey Ignatov 		"bind6: attach prog with wrong attach type",
1809be71aa6SAndrey Ignatov 		bind6_prog_load,
1819be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_BIND,
1829be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_BIND,
1839be71aa6SAndrey Ignatov 		AF_INET,
1849be71aa6SAndrey Ignatov 		SOCK_STREAM,
1859be71aa6SAndrey Ignatov 		NULL,
1869be71aa6SAndrey Ignatov 		0,
1879be71aa6SAndrey Ignatov 		NULL,
1889be71aa6SAndrey Ignatov 		0,
1899be71aa6SAndrey Ignatov 		NULL,
1909be71aa6SAndrey Ignatov 		ATTACH_REJECT,
1919be71aa6SAndrey Ignatov 	},
1929be71aa6SAndrey Ignatov 	{
1939be71aa6SAndrey Ignatov 		"bind6: rewrite IP & TCP port in",
1949be71aa6SAndrey Ignatov 		bind6_prog_load,
1959be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_BIND,
1969be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_BIND,
1979be71aa6SAndrey Ignatov 		AF_INET6,
1989be71aa6SAndrey Ignatov 		SOCK_STREAM,
1999be71aa6SAndrey Ignatov 		SERV6_IP,
2009be71aa6SAndrey Ignatov 		SERV6_PORT,
2019be71aa6SAndrey Ignatov 		SERV6_REWRITE_IP,
2029be71aa6SAndrey Ignatov 		SERV6_REWRITE_PORT,
2039be71aa6SAndrey Ignatov 		NULL,
2049be71aa6SAndrey Ignatov 		SUCCESS,
2059be71aa6SAndrey Ignatov 	},
2069be71aa6SAndrey Ignatov 	{
2079be71aa6SAndrey Ignatov 		"bind6: rewrite IP & UDP port in",
2089be71aa6SAndrey Ignatov 		bind6_prog_load,
2099be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_BIND,
2109be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_BIND,
2119be71aa6SAndrey Ignatov 		AF_INET6,
2129be71aa6SAndrey Ignatov 		SOCK_DGRAM,
2139be71aa6SAndrey Ignatov 		SERV6_IP,
2149be71aa6SAndrey Ignatov 		SERV6_PORT,
2159be71aa6SAndrey Ignatov 		SERV6_REWRITE_IP,
2169be71aa6SAndrey Ignatov 		SERV6_REWRITE_PORT,
2179be71aa6SAndrey Ignatov 		NULL,
2189be71aa6SAndrey Ignatov 		SUCCESS,
2199be71aa6SAndrey Ignatov 	},
2209be71aa6SAndrey Ignatov 
2219be71aa6SAndrey Ignatov 	/* connect */
2229be71aa6SAndrey Ignatov 	{
2239be71aa6SAndrey Ignatov 		"connect4: load prog with wrong expected attach type",
2249be71aa6SAndrey Ignatov 		connect4_prog_load,
2259be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_CONNECT,
2269be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_CONNECT,
2279be71aa6SAndrey Ignatov 		AF_INET,
2289be71aa6SAndrey Ignatov 		SOCK_STREAM,
2299be71aa6SAndrey Ignatov 		NULL,
2309be71aa6SAndrey Ignatov 		0,
2319be71aa6SAndrey Ignatov 		NULL,
2329be71aa6SAndrey Ignatov 		0,
2339be71aa6SAndrey Ignatov 		NULL,
2349be71aa6SAndrey Ignatov 		LOAD_REJECT,
2359be71aa6SAndrey Ignatov 	},
2369be71aa6SAndrey Ignatov 	{
2379be71aa6SAndrey Ignatov 		"connect4: attach prog with wrong attach type",
2389be71aa6SAndrey Ignatov 		connect4_prog_load,
2399be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_CONNECT,
2409be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_CONNECT,
2419be71aa6SAndrey Ignatov 		AF_INET,
2429be71aa6SAndrey Ignatov 		SOCK_STREAM,
2439be71aa6SAndrey Ignatov 		NULL,
2449be71aa6SAndrey Ignatov 		0,
2459be71aa6SAndrey Ignatov 		NULL,
2469be71aa6SAndrey Ignatov 		0,
2479be71aa6SAndrey Ignatov 		NULL,
2489be71aa6SAndrey Ignatov 		ATTACH_REJECT,
2499be71aa6SAndrey Ignatov 	},
2509be71aa6SAndrey Ignatov 	{
2519be71aa6SAndrey Ignatov 		"connect4: rewrite IP & TCP port",
2529be71aa6SAndrey Ignatov 		connect4_prog_load,
2539be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_CONNECT,
2549be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_CONNECT,
2559be71aa6SAndrey Ignatov 		AF_INET,
2569be71aa6SAndrey Ignatov 		SOCK_STREAM,
2579be71aa6SAndrey Ignatov 		SERV4_IP,
2589be71aa6SAndrey Ignatov 		SERV4_PORT,
2599be71aa6SAndrey Ignatov 		SERV4_REWRITE_IP,
2609be71aa6SAndrey Ignatov 		SERV4_REWRITE_PORT,
2619be71aa6SAndrey Ignatov 		SRC4_REWRITE_IP,
2629be71aa6SAndrey Ignatov 		SUCCESS,
2639be71aa6SAndrey Ignatov 	},
2649be71aa6SAndrey Ignatov 	{
2659be71aa6SAndrey Ignatov 		"connect4: rewrite IP & UDP port",
2669be71aa6SAndrey Ignatov 		connect4_prog_load,
2679be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_CONNECT,
2689be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_CONNECT,
2699be71aa6SAndrey Ignatov 		AF_INET,
2709be71aa6SAndrey Ignatov 		SOCK_DGRAM,
2719be71aa6SAndrey Ignatov 		SERV4_IP,
2729be71aa6SAndrey Ignatov 		SERV4_PORT,
2739be71aa6SAndrey Ignatov 		SERV4_REWRITE_IP,
2749be71aa6SAndrey Ignatov 		SERV4_REWRITE_PORT,
2759be71aa6SAndrey Ignatov 		SRC4_REWRITE_IP,
2769be71aa6SAndrey Ignatov 		SUCCESS,
2779be71aa6SAndrey Ignatov 	},
2789be71aa6SAndrey Ignatov 	{
2799be71aa6SAndrey Ignatov 		"connect6: load prog with wrong expected attach type",
2809be71aa6SAndrey Ignatov 		connect6_prog_load,
2819be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_CONNECT,
2829be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_CONNECT,
2839be71aa6SAndrey Ignatov 		AF_INET6,
2849be71aa6SAndrey Ignatov 		SOCK_STREAM,
2859be71aa6SAndrey Ignatov 		NULL,
2869be71aa6SAndrey Ignatov 		0,
2879be71aa6SAndrey Ignatov 		NULL,
2889be71aa6SAndrey Ignatov 		0,
2899be71aa6SAndrey Ignatov 		NULL,
2909be71aa6SAndrey Ignatov 		LOAD_REJECT,
2919be71aa6SAndrey Ignatov 	},
2929be71aa6SAndrey Ignatov 	{
2939be71aa6SAndrey Ignatov 		"connect6: attach prog with wrong attach type",
2949be71aa6SAndrey Ignatov 		connect6_prog_load,
2959be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_CONNECT,
2969be71aa6SAndrey Ignatov 		BPF_CGROUP_INET4_CONNECT,
2979be71aa6SAndrey Ignatov 		AF_INET,
2989be71aa6SAndrey Ignatov 		SOCK_STREAM,
2999be71aa6SAndrey Ignatov 		NULL,
3009be71aa6SAndrey Ignatov 		0,
3019be71aa6SAndrey Ignatov 		NULL,
3029be71aa6SAndrey Ignatov 		0,
3039be71aa6SAndrey Ignatov 		NULL,
3049be71aa6SAndrey Ignatov 		ATTACH_REJECT,
3059be71aa6SAndrey Ignatov 	},
3069be71aa6SAndrey Ignatov 	{
3079be71aa6SAndrey Ignatov 		"connect6: rewrite IP & TCP port",
3089be71aa6SAndrey Ignatov 		connect6_prog_load,
3099be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_CONNECT,
3109be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_CONNECT,
3119be71aa6SAndrey Ignatov 		AF_INET6,
3129be71aa6SAndrey Ignatov 		SOCK_STREAM,
3139be71aa6SAndrey Ignatov 		SERV6_IP,
3149be71aa6SAndrey Ignatov 		SERV6_PORT,
3159be71aa6SAndrey Ignatov 		SERV6_REWRITE_IP,
3169be71aa6SAndrey Ignatov 		SERV6_REWRITE_PORT,
3179be71aa6SAndrey Ignatov 		SRC6_REWRITE_IP,
3189be71aa6SAndrey Ignatov 		SUCCESS,
3199be71aa6SAndrey Ignatov 	},
3209be71aa6SAndrey Ignatov 	{
3219be71aa6SAndrey Ignatov 		"connect6: rewrite IP & UDP port",
3229be71aa6SAndrey Ignatov 		connect6_prog_load,
3239be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_CONNECT,
3249be71aa6SAndrey Ignatov 		BPF_CGROUP_INET6_CONNECT,
3259be71aa6SAndrey Ignatov 		AF_INET6,
3269be71aa6SAndrey Ignatov 		SOCK_DGRAM,
3279be71aa6SAndrey Ignatov 		SERV6_IP,
3289be71aa6SAndrey Ignatov 		SERV6_PORT,
3299be71aa6SAndrey Ignatov 		SERV6_REWRITE_IP,
3309be71aa6SAndrey Ignatov 		SERV6_REWRITE_PORT,
3319be71aa6SAndrey Ignatov 		SRC6_REWRITE_IP,
3329be71aa6SAndrey Ignatov 		SUCCESS,
3339be71aa6SAndrey Ignatov 	},
33404b6ab73SAndrey Ignatov 
33504b6ab73SAndrey Ignatov 	/* sendmsg */
33604b6ab73SAndrey Ignatov 	{
33704b6ab73SAndrey Ignatov 		"sendmsg4: load prog with wrong expected attach type",
33804b6ab73SAndrey Ignatov 		sendmsg4_rw_asm_prog_load,
33904b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
34004b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
34104b6ab73SAndrey Ignatov 		AF_INET,
34204b6ab73SAndrey Ignatov 		SOCK_DGRAM,
34304b6ab73SAndrey Ignatov 		NULL,
34404b6ab73SAndrey Ignatov 		0,
34504b6ab73SAndrey Ignatov 		NULL,
34604b6ab73SAndrey Ignatov 		0,
34704b6ab73SAndrey Ignatov 		NULL,
34804b6ab73SAndrey Ignatov 		LOAD_REJECT,
34904b6ab73SAndrey Ignatov 	},
35004b6ab73SAndrey Ignatov 	{
35104b6ab73SAndrey Ignatov 		"sendmsg4: attach prog with wrong attach type",
35204b6ab73SAndrey Ignatov 		sendmsg4_rw_asm_prog_load,
35304b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
35404b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
35504b6ab73SAndrey Ignatov 		AF_INET,
35604b6ab73SAndrey Ignatov 		SOCK_DGRAM,
35704b6ab73SAndrey Ignatov 		NULL,
35804b6ab73SAndrey Ignatov 		0,
35904b6ab73SAndrey Ignatov 		NULL,
36004b6ab73SAndrey Ignatov 		0,
36104b6ab73SAndrey Ignatov 		NULL,
36204b6ab73SAndrey Ignatov 		ATTACH_REJECT,
36304b6ab73SAndrey Ignatov 	},
36404b6ab73SAndrey Ignatov 	{
36504b6ab73SAndrey Ignatov 		"sendmsg4: rewrite IP & port (asm)",
36604b6ab73SAndrey Ignatov 		sendmsg4_rw_asm_prog_load,
36704b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
36804b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
36904b6ab73SAndrey Ignatov 		AF_INET,
37004b6ab73SAndrey Ignatov 		SOCK_DGRAM,
37104b6ab73SAndrey Ignatov 		SERV4_IP,
37204b6ab73SAndrey Ignatov 		SERV4_PORT,
37304b6ab73SAndrey Ignatov 		SERV4_REWRITE_IP,
37404b6ab73SAndrey Ignatov 		SERV4_REWRITE_PORT,
37504b6ab73SAndrey Ignatov 		SRC4_REWRITE_IP,
37604b6ab73SAndrey Ignatov 		SUCCESS,
37704b6ab73SAndrey Ignatov 	},
37804b6ab73SAndrey Ignatov 	{
37904b6ab73SAndrey Ignatov 		"sendmsg4: rewrite IP & port (C)",
38004b6ab73SAndrey Ignatov 		sendmsg4_rw_c_prog_load,
38104b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
38204b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
38304b6ab73SAndrey Ignatov 		AF_INET,
38404b6ab73SAndrey Ignatov 		SOCK_DGRAM,
38504b6ab73SAndrey Ignatov 		SERV4_IP,
38604b6ab73SAndrey Ignatov 		SERV4_PORT,
38704b6ab73SAndrey Ignatov 		SERV4_REWRITE_IP,
38804b6ab73SAndrey Ignatov 		SERV4_REWRITE_PORT,
38904b6ab73SAndrey Ignatov 		SRC4_REWRITE_IP,
39004b6ab73SAndrey Ignatov 		SUCCESS,
39104b6ab73SAndrey Ignatov 	},
39204b6ab73SAndrey Ignatov 	{
39304b6ab73SAndrey Ignatov 		"sendmsg4: deny call",
39404b6ab73SAndrey Ignatov 		sendmsg_deny_prog_load,
39504b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
39604b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
39704b6ab73SAndrey Ignatov 		AF_INET,
39804b6ab73SAndrey Ignatov 		SOCK_DGRAM,
39904b6ab73SAndrey Ignatov 		SERV4_IP,
40004b6ab73SAndrey Ignatov 		SERV4_PORT,
40104b6ab73SAndrey Ignatov 		SERV4_REWRITE_IP,
40204b6ab73SAndrey Ignatov 		SERV4_REWRITE_PORT,
40304b6ab73SAndrey Ignatov 		SRC4_REWRITE_IP,
40404b6ab73SAndrey Ignatov 		SYSCALL_EPERM,
40504b6ab73SAndrey Ignatov 	},
40604b6ab73SAndrey Ignatov 	{
40704b6ab73SAndrey Ignatov 		"sendmsg6: load prog with wrong expected attach type",
40804b6ab73SAndrey Ignatov 		sendmsg6_rw_asm_prog_load,
40904b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
41004b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
41104b6ab73SAndrey Ignatov 		AF_INET6,
41204b6ab73SAndrey Ignatov 		SOCK_DGRAM,
41304b6ab73SAndrey Ignatov 		NULL,
41404b6ab73SAndrey Ignatov 		0,
41504b6ab73SAndrey Ignatov 		NULL,
41604b6ab73SAndrey Ignatov 		0,
41704b6ab73SAndrey Ignatov 		NULL,
41804b6ab73SAndrey Ignatov 		LOAD_REJECT,
41904b6ab73SAndrey Ignatov 	},
42004b6ab73SAndrey Ignatov 	{
42104b6ab73SAndrey Ignatov 		"sendmsg6: attach prog with wrong attach type",
42204b6ab73SAndrey Ignatov 		sendmsg6_rw_asm_prog_load,
42304b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
42404b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP4_SENDMSG,
42504b6ab73SAndrey Ignatov 		AF_INET6,
42604b6ab73SAndrey Ignatov 		SOCK_DGRAM,
42704b6ab73SAndrey Ignatov 		NULL,
42804b6ab73SAndrey Ignatov 		0,
42904b6ab73SAndrey Ignatov 		NULL,
43004b6ab73SAndrey Ignatov 		0,
43104b6ab73SAndrey Ignatov 		NULL,
43204b6ab73SAndrey Ignatov 		ATTACH_REJECT,
43304b6ab73SAndrey Ignatov 	},
43404b6ab73SAndrey Ignatov 	{
43504b6ab73SAndrey Ignatov 		"sendmsg6: rewrite IP & port (asm)",
43604b6ab73SAndrey Ignatov 		sendmsg6_rw_asm_prog_load,
43704b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
43804b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
43904b6ab73SAndrey Ignatov 		AF_INET6,
44004b6ab73SAndrey Ignatov 		SOCK_DGRAM,
44104b6ab73SAndrey Ignatov 		SERV6_IP,
44204b6ab73SAndrey Ignatov 		SERV6_PORT,
44304b6ab73SAndrey Ignatov 		SERV6_REWRITE_IP,
44404b6ab73SAndrey Ignatov 		SERV6_REWRITE_PORT,
44504b6ab73SAndrey Ignatov 		SRC6_REWRITE_IP,
44604b6ab73SAndrey Ignatov 		SUCCESS,
44704b6ab73SAndrey Ignatov 	},
44804b6ab73SAndrey Ignatov 	{
44904b6ab73SAndrey Ignatov 		"sendmsg6: rewrite IP & port (C)",
45004b6ab73SAndrey Ignatov 		sendmsg6_rw_c_prog_load,
45104b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
45204b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
45304b6ab73SAndrey Ignatov 		AF_INET6,
45404b6ab73SAndrey Ignatov 		SOCK_DGRAM,
45504b6ab73SAndrey Ignatov 		SERV6_IP,
45604b6ab73SAndrey Ignatov 		SERV6_PORT,
45704b6ab73SAndrey Ignatov 		SERV6_REWRITE_IP,
45804b6ab73SAndrey Ignatov 		SERV6_REWRITE_PORT,
45904b6ab73SAndrey Ignatov 		SRC6_REWRITE_IP,
46004b6ab73SAndrey Ignatov 		SUCCESS,
46104b6ab73SAndrey Ignatov 	},
46204b6ab73SAndrey Ignatov 	{
46304b6ab73SAndrey Ignatov 		"sendmsg6: IPv4-mapped IPv6",
46404b6ab73SAndrey Ignatov 		sendmsg6_rw_v4mapped_prog_load,
46504b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
46604b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
46704b6ab73SAndrey Ignatov 		AF_INET6,
46804b6ab73SAndrey Ignatov 		SOCK_DGRAM,
46904b6ab73SAndrey Ignatov 		SERV6_IP,
47004b6ab73SAndrey Ignatov 		SERV6_PORT,
47104b6ab73SAndrey Ignatov 		SERV6_REWRITE_IP,
47204b6ab73SAndrey Ignatov 		SERV6_REWRITE_PORT,
47304b6ab73SAndrey Ignatov 		SRC6_REWRITE_IP,
47404b6ab73SAndrey Ignatov 		SYSCALL_ENOTSUPP,
47504b6ab73SAndrey Ignatov 	},
47604b6ab73SAndrey Ignatov 	{
477976b4f3aSAndrey Ignatov 		"sendmsg6: set dst IP = [::] (BSD'ism)",
478976b4f3aSAndrey Ignatov 		sendmsg6_rw_wildcard_prog_load,
479976b4f3aSAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
480976b4f3aSAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
481976b4f3aSAndrey Ignatov 		AF_INET6,
482976b4f3aSAndrey Ignatov 		SOCK_DGRAM,
483976b4f3aSAndrey Ignatov 		SERV6_IP,
484976b4f3aSAndrey Ignatov 		SERV6_PORT,
485976b4f3aSAndrey Ignatov 		SERV6_REWRITE_IP,
486976b4f3aSAndrey Ignatov 		SERV6_REWRITE_PORT,
487976b4f3aSAndrey Ignatov 		SRC6_REWRITE_IP,
488976b4f3aSAndrey Ignatov 		SUCCESS,
489976b4f3aSAndrey Ignatov 	},
490976b4f3aSAndrey Ignatov 	{
491976b4f3aSAndrey Ignatov 		"sendmsg6: preserve dst IP = [::] (BSD'ism)",
492976b4f3aSAndrey Ignatov 		sendmsg_allow_prog_load,
493976b4f3aSAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
494976b4f3aSAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
495976b4f3aSAndrey Ignatov 		AF_INET6,
496976b4f3aSAndrey Ignatov 		SOCK_DGRAM,
497976b4f3aSAndrey Ignatov 		WILDCARD6_IP,
498976b4f3aSAndrey Ignatov 		SERV6_PORT,
499976b4f3aSAndrey Ignatov 		SERV6_REWRITE_IP,
500976b4f3aSAndrey Ignatov 		SERV6_PORT,
501976b4f3aSAndrey Ignatov 		SRC6_IP,
502976b4f3aSAndrey Ignatov 		SUCCESS,
503976b4f3aSAndrey Ignatov 	},
504976b4f3aSAndrey Ignatov 	{
50504b6ab73SAndrey Ignatov 		"sendmsg6: deny call",
50604b6ab73SAndrey Ignatov 		sendmsg_deny_prog_load,
50704b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
50804b6ab73SAndrey Ignatov 		BPF_CGROUP_UDP6_SENDMSG,
50904b6ab73SAndrey Ignatov 		AF_INET6,
51004b6ab73SAndrey Ignatov 		SOCK_DGRAM,
51104b6ab73SAndrey Ignatov 		SERV6_IP,
51204b6ab73SAndrey Ignatov 		SERV6_PORT,
51304b6ab73SAndrey Ignatov 		SERV6_REWRITE_IP,
51404b6ab73SAndrey Ignatov 		SERV6_REWRITE_PORT,
51504b6ab73SAndrey Ignatov 		SRC6_REWRITE_IP,
51604b6ab73SAndrey Ignatov 		SYSCALL_EPERM,
51704b6ab73SAndrey Ignatov 	},
5181812291eSDaniel Borkmann 
5191812291eSDaniel Borkmann 	/* recvmsg */
5201812291eSDaniel Borkmann 	{
5211812291eSDaniel Borkmann 		"recvmsg4: return code ok",
5221812291eSDaniel Borkmann 		recvmsg_allow_prog_load,
5231812291eSDaniel Borkmann 		BPF_CGROUP_UDP4_RECVMSG,
5241812291eSDaniel Borkmann 		BPF_CGROUP_UDP4_RECVMSG,
5251812291eSDaniel Borkmann 		AF_INET,
5261812291eSDaniel Borkmann 		SOCK_DGRAM,
5271812291eSDaniel Borkmann 		NULL,
5281812291eSDaniel Borkmann 		0,
5291812291eSDaniel Borkmann 		NULL,
5301812291eSDaniel Borkmann 		0,
5311812291eSDaniel Borkmann 		NULL,
5321812291eSDaniel Borkmann 		ATTACH_OKAY,
5331812291eSDaniel Borkmann 	},
5341812291eSDaniel Borkmann 	{
5351812291eSDaniel Borkmann 		"recvmsg4: return code !ok",
5361812291eSDaniel Borkmann 		recvmsg_deny_prog_load,
5371812291eSDaniel Borkmann 		BPF_CGROUP_UDP4_RECVMSG,
5381812291eSDaniel Borkmann 		BPF_CGROUP_UDP4_RECVMSG,
5391812291eSDaniel Borkmann 		AF_INET,
5401812291eSDaniel Borkmann 		SOCK_DGRAM,
5411812291eSDaniel Borkmann 		NULL,
5421812291eSDaniel Borkmann 		0,
5431812291eSDaniel Borkmann 		NULL,
5441812291eSDaniel Borkmann 		0,
5451812291eSDaniel Borkmann 		NULL,
5461812291eSDaniel Borkmann 		LOAD_REJECT,
5471812291eSDaniel Borkmann 	},
5481812291eSDaniel Borkmann 	{
5491812291eSDaniel Borkmann 		"recvmsg6: return code ok",
5501812291eSDaniel Borkmann 		recvmsg_allow_prog_load,
5511812291eSDaniel Borkmann 		BPF_CGROUP_UDP6_RECVMSG,
5521812291eSDaniel Borkmann 		BPF_CGROUP_UDP6_RECVMSG,
5531812291eSDaniel Borkmann 		AF_INET6,
5541812291eSDaniel Borkmann 		SOCK_DGRAM,
5551812291eSDaniel Borkmann 		NULL,
5561812291eSDaniel Borkmann 		0,
5571812291eSDaniel Borkmann 		NULL,
5581812291eSDaniel Borkmann 		0,
5591812291eSDaniel Borkmann 		NULL,
5601812291eSDaniel Borkmann 		ATTACH_OKAY,
5611812291eSDaniel Borkmann 	},
5621812291eSDaniel Borkmann 	{
5631812291eSDaniel Borkmann 		"recvmsg6: return code !ok",
5641812291eSDaniel Borkmann 		recvmsg_deny_prog_load,
5651812291eSDaniel Borkmann 		BPF_CGROUP_UDP6_RECVMSG,
5661812291eSDaniel Borkmann 		BPF_CGROUP_UDP6_RECVMSG,
5671812291eSDaniel Borkmann 		AF_INET6,
5681812291eSDaniel Borkmann 		SOCK_DGRAM,
5691812291eSDaniel Borkmann 		NULL,
5701812291eSDaniel Borkmann 		0,
5711812291eSDaniel Borkmann 		NULL,
5721812291eSDaniel Borkmann 		0,
5731812291eSDaniel Borkmann 		NULL,
5741812291eSDaniel Borkmann 		LOAD_REJECT,
5751812291eSDaniel Borkmann 	},
5761812291eSDaniel Borkmann 	{
57735749060SStanislav Fomichev 		"recvmsg4: rewrite IP & port (C)",
57835749060SStanislav Fomichev 		recvmsg4_rw_c_prog_load,
5791812291eSDaniel Borkmann 		BPF_CGROUP_UDP4_RECVMSG,
5801812291eSDaniel Borkmann 		BPF_CGROUP_UDP4_RECVMSG,
5811812291eSDaniel Borkmann 		AF_INET,
5821812291eSDaniel Borkmann 		SOCK_DGRAM,
5831812291eSDaniel Borkmann 		SERV4_REWRITE_IP,
5841812291eSDaniel Borkmann 		SERV4_REWRITE_PORT,
5851812291eSDaniel Borkmann 		SERV4_REWRITE_IP,
5861812291eSDaniel Borkmann 		SERV4_REWRITE_PORT,
5871812291eSDaniel Borkmann 		SERV4_IP,
5881812291eSDaniel Borkmann 		SUCCESS,
5891812291eSDaniel Borkmann 	},
5901812291eSDaniel Borkmann 	{
59135749060SStanislav Fomichev 		"recvmsg6: rewrite IP & port (C)",
59235749060SStanislav Fomichev 		recvmsg6_rw_c_prog_load,
5931812291eSDaniel Borkmann 		BPF_CGROUP_UDP6_RECVMSG,
5941812291eSDaniel Borkmann 		BPF_CGROUP_UDP6_RECVMSG,
5951812291eSDaniel Borkmann 		AF_INET6,
5961812291eSDaniel Borkmann 		SOCK_DGRAM,
5971812291eSDaniel Borkmann 		SERV6_REWRITE_IP,
5981812291eSDaniel Borkmann 		SERV6_REWRITE_PORT,
5991812291eSDaniel Borkmann 		SERV6_REWRITE_IP,
6001812291eSDaniel Borkmann 		SERV6_REWRITE_PORT,
6011812291eSDaniel Borkmann 		SERV6_IP,
6021812291eSDaniel Borkmann 		SUCCESS,
6031812291eSDaniel Borkmann 	},
6049be71aa6SAndrey Ignatov };
605e50b0a6fSAndrey Ignatov 
mk_sockaddr(int domain,const char * ip,unsigned short port,struct sockaddr * addr,socklen_t addr_len)606e50b0a6fSAndrey Ignatov static int mk_sockaddr(int domain, const char *ip, unsigned short port,
607e50b0a6fSAndrey Ignatov 		       struct sockaddr *addr, socklen_t addr_len)
608e50b0a6fSAndrey Ignatov {
609e50b0a6fSAndrey Ignatov 	struct sockaddr_in6 *addr6;
610e50b0a6fSAndrey Ignatov 	struct sockaddr_in *addr4;
611e50b0a6fSAndrey Ignatov 
612e50b0a6fSAndrey Ignatov 	if (domain != AF_INET && domain != AF_INET6) {
613e50b0a6fSAndrey Ignatov 		log_err("Unsupported address family");
614e50b0a6fSAndrey Ignatov 		return -1;
615e50b0a6fSAndrey Ignatov 	}
616e50b0a6fSAndrey Ignatov 
617e50b0a6fSAndrey Ignatov 	memset(addr, 0, addr_len);
618e50b0a6fSAndrey Ignatov 
619e50b0a6fSAndrey Ignatov 	if (domain == AF_INET) {
620e50b0a6fSAndrey Ignatov 		if (addr_len < sizeof(struct sockaddr_in))
621e50b0a6fSAndrey Ignatov 			return -1;
622e50b0a6fSAndrey Ignatov 		addr4 = (struct sockaddr_in *)addr;
623e50b0a6fSAndrey Ignatov 		addr4->sin_family = domain;
624e50b0a6fSAndrey Ignatov 		addr4->sin_port = htons(port);
625e50b0a6fSAndrey Ignatov 		if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) {
626e50b0a6fSAndrey Ignatov 			log_err("Invalid IPv4: %s", ip);
627e50b0a6fSAndrey Ignatov 			return -1;
628e50b0a6fSAndrey Ignatov 		}
629e50b0a6fSAndrey Ignatov 	} else if (domain == AF_INET6) {
630e50b0a6fSAndrey Ignatov 		if (addr_len < sizeof(struct sockaddr_in6))
631e50b0a6fSAndrey Ignatov 			return -1;
632e50b0a6fSAndrey Ignatov 		addr6 = (struct sockaddr_in6 *)addr;
633e50b0a6fSAndrey Ignatov 		addr6->sin6_family = domain;
634e50b0a6fSAndrey Ignatov 		addr6->sin6_port = htons(port);
635e50b0a6fSAndrey Ignatov 		if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) {
636e50b0a6fSAndrey Ignatov 			log_err("Invalid IPv6: %s", ip);
637e50b0a6fSAndrey Ignatov 			return -1;
638e50b0a6fSAndrey Ignatov 		}
639e50b0a6fSAndrey Ignatov 	}
640e50b0a6fSAndrey Ignatov 
641e50b0a6fSAndrey Ignatov 	return 0;
642e50b0a6fSAndrey Ignatov }
643e50b0a6fSAndrey Ignatov 
load_insns(const struct sock_addr_test * test,const struct bpf_insn * insns,size_t insns_cnt)6449be71aa6SAndrey Ignatov static int load_insns(const struct sock_addr_test *test,
6459be71aa6SAndrey Ignatov 		      const struct bpf_insn *insns, size_t insns_cnt)
646e50b0a6fSAndrey Ignatov {
647d8e86407SAndrii Nakryiko 	LIBBPF_OPTS(bpf_prog_load_opts, opts);
648e50b0a6fSAndrey Ignatov 	int ret;
649e50b0a6fSAndrey Ignatov 
650d8e86407SAndrii Nakryiko 	opts.expected_attach_type = test->expected_attach_type;
651d8e86407SAndrii Nakryiko 	opts.log_buf = bpf_log_buf;
652d8e86407SAndrii Nakryiko 	opts.log_size = BPF_LOG_BUF_SIZE;
653e50b0a6fSAndrey Ignatov 
654d8e86407SAndrii Nakryiko 	ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, NULL, "GPL", insns, insns_cnt, &opts);
6559be71aa6SAndrey Ignatov 	if (ret < 0 && test->expected_result != LOAD_REJECT) {
6569be71aa6SAndrey Ignatov 		log_err(">>> Loading program error.\n"
6579be71aa6SAndrey Ignatov 			">>> Verifier output:\n%s\n-------\n", bpf_log_buf);
658e50b0a6fSAndrey Ignatov 	}
659e50b0a6fSAndrey Ignatov 
660e50b0a6fSAndrey Ignatov 	return ret;
661e50b0a6fSAndrey Ignatov }
662e50b0a6fSAndrey Ignatov 
load_path(const struct sock_addr_test * test,const char * path)6639be71aa6SAndrey Ignatov static int load_path(const struct sock_addr_test *test, const char *path)
664622adafbSAndrey Ignatov {
665622adafbSAndrey Ignatov 	struct bpf_object *obj;
666186d1a86SAndrii Nakryiko 	struct bpf_program *prog;
667186d1a86SAndrii Nakryiko 	int err;
668622adafbSAndrey Ignatov 
669186d1a86SAndrii Nakryiko 	obj = bpf_object__open_file(path, NULL);
670186d1a86SAndrii Nakryiko 	err = libbpf_get_error(obj);
671186d1a86SAndrii Nakryiko 	if (err) {
672186d1a86SAndrii Nakryiko 		log_err(">>> Opening BPF object (%s) error.\n", path);
673622adafbSAndrey Ignatov 		return -1;
674622adafbSAndrey Ignatov 	}
675622adafbSAndrey Ignatov 
676186d1a86SAndrii Nakryiko 	prog = bpf_object__next_program(obj, NULL);
677186d1a86SAndrii Nakryiko 	if (!prog)
678186d1a86SAndrii Nakryiko 		goto err_out;
679186d1a86SAndrii Nakryiko 
680186d1a86SAndrii Nakryiko 	bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR);
681186d1a86SAndrii Nakryiko 	bpf_program__set_expected_attach_type(prog, test->expected_attach_type);
682186d1a86SAndrii Nakryiko 	bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32);
683186d1a86SAndrii Nakryiko 
684186d1a86SAndrii Nakryiko 	err = bpf_object__load(obj);
685186d1a86SAndrii Nakryiko 	if (err) {
686186d1a86SAndrii Nakryiko 		if (test->expected_result != LOAD_REJECT)
687186d1a86SAndrii Nakryiko 			log_err(">>> Loading program (%s) error.\n", path);
688186d1a86SAndrii Nakryiko 		goto err_out;
689186d1a86SAndrii Nakryiko 	}
690186d1a86SAndrii Nakryiko 
691186d1a86SAndrii Nakryiko 	return bpf_program__fd(prog);
692186d1a86SAndrii Nakryiko err_out:
693186d1a86SAndrii Nakryiko 	bpf_object__close(obj);
694186d1a86SAndrii Nakryiko 	return -1;
695622adafbSAndrey Ignatov }
696622adafbSAndrey Ignatov 
bind4_prog_load(const struct sock_addr_test * test)697a999696cSStanislav Fomichev static int bind4_prog_load(const struct sock_addr_test *test)
698a999696cSStanislav Fomichev {
699a999696cSStanislav Fomichev 	return load_path(test, BIND4_PROG_PATH);
700a999696cSStanislav Fomichev }
701a999696cSStanislav Fomichev 
bind6_prog_load(const struct sock_addr_test * test)702a999696cSStanislav Fomichev static int bind6_prog_load(const struct sock_addr_test *test)
703a999696cSStanislav Fomichev {
704a999696cSStanislav Fomichev 	return load_path(test, BIND6_PROG_PATH);
705a999696cSStanislav Fomichev }
706a999696cSStanislav Fomichev 
connect4_prog_load(const struct sock_addr_test * test)7079be71aa6SAndrey Ignatov static int connect4_prog_load(const struct sock_addr_test *test)
708622adafbSAndrey Ignatov {
7099be71aa6SAndrey Ignatov 	return load_path(test, CONNECT4_PROG_PATH);
710622adafbSAndrey Ignatov }
711622adafbSAndrey Ignatov 
connect6_prog_load(const struct sock_addr_test * test)7129be71aa6SAndrey Ignatov static int connect6_prog_load(const struct sock_addr_test *test)
713622adafbSAndrey Ignatov {
7149be71aa6SAndrey Ignatov 	return load_path(test, CONNECT6_PROG_PATH);
715622adafbSAndrey Ignatov }
716622adafbSAndrey Ignatov 
xmsg_ret_only_prog_load(const struct sock_addr_test * test,int32_t rc)7171812291eSDaniel Borkmann static int xmsg_ret_only_prog_load(const struct sock_addr_test *test,
718976b4f3aSAndrey Ignatov 				   int32_t rc)
71904b6ab73SAndrey Ignatov {
72004b6ab73SAndrey Ignatov 	struct bpf_insn insns[] = {
721976b4f3aSAndrey Ignatov 		/* return rc */
722976b4f3aSAndrey Ignatov 		BPF_MOV64_IMM(BPF_REG_0, rc),
72304b6ab73SAndrey Ignatov 		BPF_EXIT_INSN(),
72404b6ab73SAndrey Ignatov 	};
725f98d6dd1SGuo Zhengkui 	return load_insns(test, insns, ARRAY_SIZE(insns));
72604b6ab73SAndrey Ignatov }
72704b6ab73SAndrey Ignatov 
sendmsg_allow_prog_load(const struct sock_addr_test * test)728976b4f3aSAndrey Ignatov static int sendmsg_allow_prog_load(const struct sock_addr_test *test)
729976b4f3aSAndrey Ignatov {
7301812291eSDaniel Borkmann 	return xmsg_ret_only_prog_load(test, /*rc*/ 1);
731976b4f3aSAndrey Ignatov }
732976b4f3aSAndrey Ignatov 
sendmsg_deny_prog_load(const struct sock_addr_test * test)733976b4f3aSAndrey Ignatov static int sendmsg_deny_prog_load(const struct sock_addr_test *test)
734976b4f3aSAndrey Ignatov {
7351812291eSDaniel Borkmann 	return xmsg_ret_only_prog_load(test, /*rc*/ 0);
7361812291eSDaniel Borkmann }
7371812291eSDaniel Borkmann 
recvmsg_allow_prog_load(const struct sock_addr_test * test)7381812291eSDaniel Borkmann static int recvmsg_allow_prog_load(const struct sock_addr_test *test)
7391812291eSDaniel Borkmann {
7401812291eSDaniel Borkmann 	return xmsg_ret_only_prog_load(test, /*rc*/ 1);
7411812291eSDaniel Borkmann }
7421812291eSDaniel Borkmann 
recvmsg_deny_prog_load(const struct sock_addr_test * test)7431812291eSDaniel Borkmann static int recvmsg_deny_prog_load(const struct sock_addr_test *test)
7441812291eSDaniel Borkmann {
7451812291eSDaniel Borkmann 	return xmsg_ret_only_prog_load(test, /*rc*/ 0);
746976b4f3aSAndrey Ignatov }
747976b4f3aSAndrey Ignatov 
sendmsg4_rw_asm_prog_load(const struct sock_addr_test * test)74804b6ab73SAndrey Ignatov static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test)
74904b6ab73SAndrey Ignatov {
75004b6ab73SAndrey Ignatov 	struct sockaddr_in dst4_rw_addr;
75104b6ab73SAndrey Ignatov 	struct in_addr src4_rw_ip;
75204b6ab73SAndrey Ignatov 
75304b6ab73SAndrey Ignatov 	if (inet_pton(AF_INET, SRC4_REWRITE_IP, (void *)&src4_rw_ip) != 1) {
75404b6ab73SAndrey Ignatov 		log_err("Invalid IPv4: %s", SRC4_REWRITE_IP);
75504b6ab73SAndrey Ignatov 		return -1;
75604b6ab73SAndrey Ignatov 	}
75704b6ab73SAndrey Ignatov 
75804b6ab73SAndrey Ignatov 	if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT,
75904b6ab73SAndrey Ignatov 			(struct sockaddr *)&dst4_rw_addr,
76004b6ab73SAndrey Ignatov 			sizeof(dst4_rw_addr)) == -1)
76104b6ab73SAndrey Ignatov 		return -1;
76204b6ab73SAndrey Ignatov 
76304b6ab73SAndrey Ignatov 	struct bpf_insn insns[] = {
76404b6ab73SAndrey Ignatov 		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
76504b6ab73SAndrey Ignatov 
76604b6ab73SAndrey Ignatov 		/* if (sk.family == AF_INET && */
76704b6ab73SAndrey Ignatov 		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
76804b6ab73SAndrey Ignatov 			    offsetof(struct bpf_sock_addr, family)),
76904b6ab73SAndrey Ignatov 		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 8),
77004b6ab73SAndrey Ignatov 
77104b6ab73SAndrey Ignatov 		/*     sk.type == SOCK_DGRAM)  { */
77204b6ab73SAndrey Ignatov 		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
77304b6ab73SAndrey Ignatov 			    offsetof(struct bpf_sock_addr, type)),
77404b6ab73SAndrey Ignatov 		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 6),
77504b6ab73SAndrey Ignatov 
77604b6ab73SAndrey Ignatov 		/*      msg_src_ip4 = src4_rw_ip */
77704b6ab73SAndrey Ignatov 		BPF_MOV32_IMM(BPF_REG_7, src4_rw_ip.s_addr),
77804b6ab73SAndrey Ignatov 		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
77904b6ab73SAndrey Ignatov 			    offsetof(struct bpf_sock_addr, msg_src_ip4)),
78004b6ab73SAndrey Ignatov 
78104b6ab73SAndrey Ignatov 		/*      user_ip4 = dst4_rw_addr.sin_addr */
78204b6ab73SAndrey Ignatov 		BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_addr.s_addr),
78304b6ab73SAndrey Ignatov 		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
78404b6ab73SAndrey Ignatov 			    offsetof(struct bpf_sock_addr, user_ip4)),
78504b6ab73SAndrey Ignatov 
78604b6ab73SAndrey Ignatov 		/*      user_port = dst4_rw_addr.sin_port */
78704b6ab73SAndrey Ignatov 		BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_port),
78804b6ab73SAndrey Ignatov 		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
78904b6ab73SAndrey Ignatov 			    offsetof(struct bpf_sock_addr, user_port)),
79004b6ab73SAndrey Ignatov 		/* } */
79104b6ab73SAndrey Ignatov 
79204b6ab73SAndrey Ignatov 		/* return 1 */
79304b6ab73SAndrey Ignatov 		BPF_MOV64_IMM(BPF_REG_0, 1),
79404b6ab73SAndrey Ignatov 		BPF_EXIT_INSN(),
79504b6ab73SAndrey Ignatov 	};
79604b6ab73SAndrey Ignatov 
797f98d6dd1SGuo Zhengkui 	return load_insns(test, insns, ARRAY_SIZE(insns));
79804b6ab73SAndrey Ignatov }
79904b6ab73SAndrey Ignatov 
recvmsg4_rw_c_prog_load(const struct sock_addr_test * test)80035749060SStanislav Fomichev static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test)
8011812291eSDaniel Borkmann {
80235749060SStanislav Fomichev 	return load_path(test, RECVMSG4_PROG_PATH);
8031812291eSDaniel Borkmann }
8041812291eSDaniel Borkmann 
sendmsg4_rw_c_prog_load(const struct sock_addr_test * test)80504b6ab73SAndrey Ignatov static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test)
80604b6ab73SAndrey Ignatov {
80704b6ab73SAndrey Ignatov 	return load_path(test, SENDMSG4_PROG_PATH);
80804b6ab73SAndrey Ignatov }
80904b6ab73SAndrey Ignatov 
sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test * test,const char * rw_dst_ip)81004b6ab73SAndrey Ignatov static int sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test *test,
81104b6ab73SAndrey Ignatov 					 const char *rw_dst_ip)
81204b6ab73SAndrey Ignatov {
81304b6ab73SAndrey Ignatov 	struct sockaddr_in6 dst6_rw_addr;
81404b6ab73SAndrey Ignatov 	struct in6_addr src6_rw_ip;
81504b6ab73SAndrey Ignatov 
81604b6ab73SAndrey Ignatov 	if (inet_pton(AF_INET6, SRC6_REWRITE_IP, (void *)&src6_rw_ip) != 1) {
81704b6ab73SAndrey Ignatov 		log_err("Invalid IPv6: %s", SRC6_REWRITE_IP);
81804b6ab73SAndrey Ignatov 		return -1;
81904b6ab73SAndrey Ignatov 	}
82004b6ab73SAndrey Ignatov 
82104b6ab73SAndrey Ignatov 	if (mk_sockaddr(AF_INET6, rw_dst_ip, SERV6_REWRITE_PORT,
82204b6ab73SAndrey Ignatov 			(struct sockaddr *)&dst6_rw_addr,
82304b6ab73SAndrey Ignatov 			sizeof(dst6_rw_addr)) == -1)
82404b6ab73SAndrey Ignatov 		return -1;
82504b6ab73SAndrey Ignatov 
82604b6ab73SAndrey Ignatov 	struct bpf_insn insns[] = {
82704b6ab73SAndrey Ignatov 		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
82804b6ab73SAndrey Ignatov 
82904b6ab73SAndrey Ignatov 		/* if (sk.family == AF_INET6) { */
83004b6ab73SAndrey Ignatov 		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
83104b6ab73SAndrey Ignatov 			    offsetof(struct bpf_sock_addr, family)),
83204b6ab73SAndrey Ignatov 		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18),
83304b6ab73SAndrey Ignatov 
83404b6ab73SAndrey Ignatov #define STORE_IPV6_WORD_N(DST, SRC, N)					       \
83504b6ab73SAndrey Ignatov 		BPF_MOV32_IMM(BPF_REG_7, SRC[N]),			       \
83604b6ab73SAndrey Ignatov 		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,		       \
83704b6ab73SAndrey Ignatov 			    offsetof(struct bpf_sock_addr, DST[N]))
83804b6ab73SAndrey Ignatov 
83904b6ab73SAndrey Ignatov #define STORE_IPV6(DST, SRC)						       \
84004b6ab73SAndrey Ignatov 		STORE_IPV6_WORD_N(DST, SRC, 0),				       \
84104b6ab73SAndrey Ignatov 		STORE_IPV6_WORD_N(DST, SRC, 1),				       \
84204b6ab73SAndrey Ignatov 		STORE_IPV6_WORD_N(DST, SRC, 2),				       \
84304b6ab73SAndrey Ignatov 		STORE_IPV6_WORD_N(DST, SRC, 3)
84404b6ab73SAndrey Ignatov 
84504b6ab73SAndrey Ignatov 		STORE_IPV6(msg_src_ip6, src6_rw_ip.s6_addr32),
84604b6ab73SAndrey Ignatov 		STORE_IPV6(user_ip6, dst6_rw_addr.sin6_addr.s6_addr32),
84704b6ab73SAndrey Ignatov 
84804b6ab73SAndrey Ignatov 		/*      user_port = dst6_rw_addr.sin6_port */
84904b6ab73SAndrey Ignatov 		BPF_MOV32_IMM(BPF_REG_7, dst6_rw_addr.sin6_port),
85004b6ab73SAndrey Ignatov 		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
85104b6ab73SAndrey Ignatov 			    offsetof(struct bpf_sock_addr, user_port)),
85204b6ab73SAndrey Ignatov 
85304b6ab73SAndrey Ignatov 		/* } */
85404b6ab73SAndrey Ignatov 
85504b6ab73SAndrey Ignatov 		/* return 1 */
85604b6ab73SAndrey Ignatov 		BPF_MOV64_IMM(BPF_REG_0, 1),
85704b6ab73SAndrey Ignatov 		BPF_EXIT_INSN(),
85804b6ab73SAndrey Ignatov 	};
85904b6ab73SAndrey Ignatov 
860f98d6dd1SGuo Zhengkui 	return load_insns(test, insns, ARRAY_SIZE(insns));
86104b6ab73SAndrey Ignatov }
86204b6ab73SAndrey Ignatov 
sendmsg6_rw_asm_prog_load(const struct sock_addr_test * test)86304b6ab73SAndrey Ignatov static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test)
86404b6ab73SAndrey Ignatov {
86504b6ab73SAndrey Ignatov 	return sendmsg6_rw_dst_asm_prog_load(test, SERV6_REWRITE_IP);
86604b6ab73SAndrey Ignatov }
86704b6ab73SAndrey Ignatov 
recvmsg6_rw_c_prog_load(const struct sock_addr_test * test)86835749060SStanislav Fomichev static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test)
8691812291eSDaniel Borkmann {
87035749060SStanislav Fomichev 	return load_path(test, RECVMSG6_PROG_PATH);
8711812291eSDaniel Borkmann }
8721812291eSDaniel Borkmann 
sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test * test)87304b6ab73SAndrey Ignatov static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test)
87404b6ab73SAndrey Ignatov {
87504b6ab73SAndrey Ignatov 	return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP);
87604b6ab73SAndrey Ignatov }
87704b6ab73SAndrey Ignatov 
sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test * test)878976b4f3aSAndrey Ignatov static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test)
879976b4f3aSAndrey Ignatov {
880976b4f3aSAndrey Ignatov 	return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP);
881976b4f3aSAndrey Ignatov }
882976b4f3aSAndrey Ignatov 
sendmsg6_rw_c_prog_load(const struct sock_addr_test * test)88304b6ab73SAndrey Ignatov static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test)
88404b6ab73SAndrey Ignatov {
88504b6ab73SAndrey Ignatov 	return load_path(test, SENDMSG6_PROG_PATH);
88604b6ab73SAndrey Ignatov }
88704b6ab73SAndrey Ignatov 
cmp_addr(const struct sockaddr_storage * addr1,const struct sockaddr_storage * addr2,int cmp_port)8889be71aa6SAndrey Ignatov static int cmp_addr(const struct sockaddr_storage *addr1,
8899be71aa6SAndrey Ignatov 		    const struct sockaddr_storage *addr2, int cmp_port)
890e50b0a6fSAndrey Ignatov {
8919be71aa6SAndrey Ignatov 	const struct sockaddr_in *four1, *four2;
8929be71aa6SAndrey Ignatov 	const struct sockaddr_in6 *six1, *six2;
893e50b0a6fSAndrey Ignatov 
8949be71aa6SAndrey Ignatov 	if (addr1->ss_family != addr2->ss_family)
8959be71aa6SAndrey Ignatov 		return -1;
896e50b0a6fSAndrey Ignatov 
8979be71aa6SAndrey Ignatov 	if (addr1->ss_family == AF_INET) {
8989be71aa6SAndrey Ignatov 		four1 = (const struct sockaddr_in *)addr1;
8999be71aa6SAndrey Ignatov 		four2 = (const struct sockaddr_in *)addr2;
9009be71aa6SAndrey Ignatov 		return !((four1->sin_port == four2->sin_port || !cmp_port) &&
9019be71aa6SAndrey Ignatov 			 four1->sin_addr.s_addr == four2->sin_addr.s_addr);
9029be71aa6SAndrey Ignatov 	} else if (addr1->ss_family == AF_INET6) {
9039be71aa6SAndrey Ignatov 		six1 = (const struct sockaddr_in6 *)addr1;
9049be71aa6SAndrey Ignatov 		six2 = (const struct sockaddr_in6 *)addr2;
9059be71aa6SAndrey Ignatov 		return !((six1->sin6_port == six2->sin6_port || !cmp_port) &&
9069be71aa6SAndrey Ignatov 			 !memcmp(&six1->sin6_addr, &six2->sin6_addr,
9079be71aa6SAndrey Ignatov 				 sizeof(struct in6_addr)));
908e50b0a6fSAndrey Ignatov 	}
909e50b0a6fSAndrey Ignatov 
9109be71aa6SAndrey Ignatov 	return -1;
9119be71aa6SAndrey Ignatov }
9129be71aa6SAndrey Ignatov 
cmp_sock_addr(info_fn fn,int sock1,const struct sockaddr_storage * addr2,int cmp_port)9139be71aa6SAndrey Ignatov static int cmp_sock_addr(info_fn fn, int sock1,
9149be71aa6SAndrey Ignatov 			 const struct sockaddr_storage *addr2, int cmp_port)
915e50b0a6fSAndrey Ignatov {
9169be71aa6SAndrey Ignatov 	struct sockaddr_storage addr1;
9179be71aa6SAndrey Ignatov 	socklen_t len1 = sizeof(addr1);
9189be71aa6SAndrey Ignatov 
9199be71aa6SAndrey Ignatov 	memset(&addr1, 0, len1);
9209be71aa6SAndrey Ignatov 	if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0)
9219be71aa6SAndrey Ignatov 		return -1;
9229be71aa6SAndrey Ignatov 
9239be71aa6SAndrey Ignatov 	return cmp_addr(&addr1, addr2, cmp_port);
924e50b0a6fSAndrey Ignatov }
925e50b0a6fSAndrey Ignatov 
cmp_local_ip(int sock1,const struct sockaddr_storage * addr2)9269be71aa6SAndrey Ignatov static int cmp_local_ip(int sock1, const struct sockaddr_storage *addr2)
927622adafbSAndrey Ignatov {
9289be71aa6SAndrey Ignatov 	return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 0);
9299be71aa6SAndrey Ignatov }
9309be71aa6SAndrey Ignatov 
cmp_local_addr(int sock1,const struct sockaddr_storage * addr2)9319be71aa6SAndrey Ignatov static int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2)
9329be71aa6SAndrey Ignatov {
9339be71aa6SAndrey Ignatov 	return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 1);
9349be71aa6SAndrey Ignatov }
9359be71aa6SAndrey Ignatov 
cmp_peer_addr(int sock1,const struct sockaddr_storage * addr2)9369be71aa6SAndrey Ignatov static int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2)
9379be71aa6SAndrey Ignatov {
9389be71aa6SAndrey Ignatov 	return cmp_sock_addr(getpeername, sock1, addr2, /*cmp_port*/ 1);
939622adafbSAndrey Ignatov }
940622adafbSAndrey Ignatov 
start_server(int type,const struct sockaddr_storage * addr,socklen_t addr_len)941e50b0a6fSAndrey Ignatov static int start_server(int type, const struct sockaddr_storage *addr,
942e50b0a6fSAndrey Ignatov 			socklen_t addr_len)
943e50b0a6fSAndrey Ignatov {
944e50b0a6fSAndrey Ignatov 	int fd;
945e50b0a6fSAndrey Ignatov 
946e50b0a6fSAndrey Ignatov 	fd = socket(addr->ss_family, type, 0);
947e50b0a6fSAndrey Ignatov 	if (fd == -1) {
948e50b0a6fSAndrey Ignatov 		log_err("Failed to create server socket");
949e50b0a6fSAndrey Ignatov 		goto out;
950e50b0a6fSAndrey Ignatov 	}
951e50b0a6fSAndrey Ignatov 
952e50b0a6fSAndrey Ignatov 	if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) {
953e50b0a6fSAndrey Ignatov 		log_err("Failed to bind server socket");
954e50b0a6fSAndrey Ignatov 		goto close_out;
955e50b0a6fSAndrey Ignatov 	}
956e50b0a6fSAndrey Ignatov 
957e50b0a6fSAndrey Ignatov 	if (type == SOCK_STREAM) {
958e50b0a6fSAndrey Ignatov 		if (listen(fd, 128) == -1) {
959e50b0a6fSAndrey Ignatov 			log_err("Failed to listen on server socket");
960e50b0a6fSAndrey Ignatov 			goto close_out;
961e50b0a6fSAndrey Ignatov 		}
962e50b0a6fSAndrey Ignatov 	}
963e50b0a6fSAndrey Ignatov 
964e50b0a6fSAndrey Ignatov 	goto out;
965e50b0a6fSAndrey Ignatov close_out:
966e50b0a6fSAndrey Ignatov 	close(fd);
967e50b0a6fSAndrey Ignatov 	fd = -1;
968e50b0a6fSAndrey Ignatov out:
969e50b0a6fSAndrey Ignatov 	return fd;
970e50b0a6fSAndrey Ignatov }
971e50b0a6fSAndrey Ignatov 
connect_to_server(int type,const struct sockaddr_storage * addr,socklen_t addr_len)972622adafbSAndrey Ignatov static int connect_to_server(int type, const struct sockaddr_storage *addr,
973622adafbSAndrey Ignatov 			     socklen_t addr_len)
974622adafbSAndrey Ignatov {
975622adafbSAndrey Ignatov 	int domain;
9769be71aa6SAndrey Ignatov 	int fd = -1;
977622adafbSAndrey Ignatov 
978622adafbSAndrey Ignatov 	domain = addr->ss_family;
979622adafbSAndrey Ignatov 
980622adafbSAndrey Ignatov 	if (domain != AF_INET && domain != AF_INET6) {
981622adafbSAndrey Ignatov 		log_err("Unsupported address family");
9829be71aa6SAndrey Ignatov 		goto err;
983622adafbSAndrey Ignatov 	}
984622adafbSAndrey Ignatov 
985622adafbSAndrey Ignatov 	fd = socket(domain, type, 0);
986622adafbSAndrey Ignatov 	if (fd == -1) {
9879be71aa6SAndrey Ignatov 		log_err("Failed to create client socket");
9889be71aa6SAndrey Ignatov 		goto err;
989622adafbSAndrey Ignatov 	}
990622adafbSAndrey Ignatov 
991622adafbSAndrey Ignatov 	if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) {
992622adafbSAndrey Ignatov 		log_err("Fail to connect to server");
993622adafbSAndrey Ignatov 		goto err;
994622adafbSAndrey Ignatov 	}
995622adafbSAndrey Ignatov 
9969be71aa6SAndrey Ignatov 	goto out;
9979be71aa6SAndrey Ignatov err:
9989be71aa6SAndrey Ignatov 	close(fd);
9999be71aa6SAndrey Ignatov 	fd = -1;
10009be71aa6SAndrey Ignatov out:
10019be71aa6SAndrey Ignatov 	return fd;
10029be71aa6SAndrey Ignatov }
10039be71aa6SAndrey Ignatov 
init_pktinfo(int domain,struct cmsghdr * cmsg)100404b6ab73SAndrey Ignatov int init_pktinfo(int domain, struct cmsghdr *cmsg)
100504b6ab73SAndrey Ignatov {
100604b6ab73SAndrey Ignatov 	struct in6_pktinfo *pktinfo6;
100704b6ab73SAndrey Ignatov 	struct in_pktinfo *pktinfo4;
100804b6ab73SAndrey Ignatov 
100904b6ab73SAndrey Ignatov 	if (domain == AF_INET) {
101004b6ab73SAndrey Ignatov 		cmsg->cmsg_level = SOL_IP;
101104b6ab73SAndrey Ignatov 		cmsg->cmsg_type = IP_PKTINFO;
101204b6ab73SAndrey Ignatov 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
101304b6ab73SAndrey Ignatov 		pktinfo4 = (struct in_pktinfo *)CMSG_DATA(cmsg);
101404b6ab73SAndrey Ignatov 		memset(pktinfo4, 0, sizeof(struct in_pktinfo));
101504b6ab73SAndrey Ignatov 		if (inet_pton(domain, SRC4_IP,
101604b6ab73SAndrey Ignatov 			      (void *)&pktinfo4->ipi_spec_dst) != 1)
101704b6ab73SAndrey Ignatov 			return -1;
101804b6ab73SAndrey Ignatov 	} else if (domain == AF_INET6) {
101904b6ab73SAndrey Ignatov 		cmsg->cmsg_level = SOL_IPV6;
102004b6ab73SAndrey Ignatov 		cmsg->cmsg_type = IPV6_PKTINFO;
102104b6ab73SAndrey Ignatov 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
102204b6ab73SAndrey Ignatov 		pktinfo6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
102304b6ab73SAndrey Ignatov 		memset(pktinfo6, 0, sizeof(struct in6_pktinfo));
102404b6ab73SAndrey Ignatov 		if (inet_pton(domain, SRC6_IP,
102504b6ab73SAndrey Ignatov 			      (void *)&pktinfo6->ipi6_addr) != 1)
102604b6ab73SAndrey Ignatov 			return -1;
102704b6ab73SAndrey Ignatov 	} else {
102804b6ab73SAndrey Ignatov 		return -1;
102904b6ab73SAndrey Ignatov 	}
103004b6ab73SAndrey Ignatov 
103104b6ab73SAndrey Ignatov 	return 0;
103204b6ab73SAndrey Ignatov }
103304b6ab73SAndrey Ignatov 
sendmsg_to_server(int type,const struct sockaddr_storage * addr,socklen_t addr_len,int set_cmsg,int flags,int * syscall_err)1034a7f7547fSAndrey Ignatov static int sendmsg_to_server(int type, const struct sockaddr_storage *addr,
1035a7f7547fSAndrey Ignatov 			     socklen_t addr_len, int set_cmsg, int flags,
1036a7f7547fSAndrey Ignatov 			     int *syscall_err)
103704b6ab73SAndrey Ignatov {
103804b6ab73SAndrey Ignatov 	union {
103904b6ab73SAndrey Ignatov 		char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
104004b6ab73SAndrey Ignatov 		struct cmsghdr align;
104104b6ab73SAndrey Ignatov 	} control6;
104204b6ab73SAndrey Ignatov 	union {
104304b6ab73SAndrey Ignatov 		char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
104404b6ab73SAndrey Ignatov 		struct cmsghdr align;
104504b6ab73SAndrey Ignatov 	} control4;
104604b6ab73SAndrey Ignatov 	struct msghdr hdr;
104704b6ab73SAndrey Ignatov 	struct iovec iov;
104804b6ab73SAndrey Ignatov 	char data = 'a';
104904b6ab73SAndrey Ignatov 	int domain;
105004b6ab73SAndrey Ignatov 	int fd = -1;
105104b6ab73SAndrey Ignatov 
105204b6ab73SAndrey Ignatov 	domain = addr->ss_family;
105304b6ab73SAndrey Ignatov 
105404b6ab73SAndrey Ignatov 	if (domain != AF_INET && domain != AF_INET6) {
105504b6ab73SAndrey Ignatov 		log_err("Unsupported address family");
105604b6ab73SAndrey Ignatov 		goto err;
105704b6ab73SAndrey Ignatov 	}
105804b6ab73SAndrey Ignatov 
1059a7f7547fSAndrey Ignatov 	fd = socket(domain, type, 0);
106004b6ab73SAndrey Ignatov 	if (fd == -1) {
106104b6ab73SAndrey Ignatov 		log_err("Failed to create client socket");
106204b6ab73SAndrey Ignatov 		goto err;
106304b6ab73SAndrey Ignatov 	}
106404b6ab73SAndrey Ignatov 
106504b6ab73SAndrey Ignatov 	memset(&iov, 0, sizeof(iov));
106604b6ab73SAndrey Ignatov 	iov.iov_base = &data;
106704b6ab73SAndrey Ignatov 	iov.iov_len = sizeof(data);
106804b6ab73SAndrey Ignatov 
106904b6ab73SAndrey Ignatov 	memset(&hdr, 0, sizeof(hdr));
107004b6ab73SAndrey Ignatov 	hdr.msg_name = (void *)addr;
107104b6ab73SAndrey Ignatov 	hdr.msg_namelen = addr_len;
107204b6ab73SAndrey Ignatov 	hdr.msg_iov = &iov;
107304b6ab73SAndrey Ignatov 	hdr.msg_iovlen = 1;
107404b6ab73SAndrey Ignatov 
107504b6ab73SAndrey Ignatov 	if (set_cmsg) {
107604b6ab73SAndrey Ignatov 		if (domain == AF_INET) {
107704b6ab73SAndrey Ignatov 			hdr.msg_control = &control4;
107804b6ab73SAndrey Ignatov 			hdr.msg_controllen = sizeof(control4.buf);
107904b6ab73SAndrey Ignatov 		} else if (domain == AF_INET6) {
108004b6ab73SAndrey Ignatov 			hdr.msg_control = &control6;
108104b6ab73SAndrey Ignatov 			hdr.msg_controllen = sizeof(control6.buf);
108204b6ab73SAndrey Ignatov 		}
108304b6ab73SAndrey Ignatov 		if (init_pktinfo(domain, CMSG_FIRSTHDR(&hdr))) {
108404b6ab73SAndrey Ignatov 			log_err("Fail to init pktinfo");
108504b6ab73SAndrey Ignatov 			goto err;
108604b6ab73SAndrey Ignatov 		}
108704b6ab73SAndrey Ignatov 	}
108804b6ab73SAndrey Ignatov 
1089a7f7547fSAndrey Ignatov 	if (sendmsg(fd, &hdr, flags) != sizeof(data)) {
109004b6ab73SAndrey Ignatov 		log_err("Fail to send message to server");
109104b6ab73SAndrey Ignatov 		*syscall_err = errno;
109204b6ab73SAndrey Ignatov 		goto err;
109304b6ab73SAndrey Ignatov 	}
109404b6ab73SAndrey Ignatov 
109504b6ab73SAndrey Ignatov 	goto out;
109604b6ab73SAndrey Ignatov err:
109704b6ab73SAndrey Ignatov 	close(fd);
109804b6ab73SAndrey Ignatov 	fd = -1;
109904b6ab73SAndrey Ignatov out:
110004b6ab73SAndrey Ignatov 	return fd;
110104b6ab73SAndrey Ignatov }
110204b6ab73SAndrey Ignatov 
fastconnect_to_server(const struct sockaddr_storage * addr,socklen_t addr_len)1103a7f7547fSAndrey Ignatov static int fastconnect_to_server(const struct sockaddr_storage *addr,
1104a7f7547fSAndrey Ignatov 				 socklen_t addr_len)
1105a7f7547fSAndrey Ignatov {
1106a7f7547fSAndrey Ignatov 	int sendmsg_err;
1107a7f7547fSAndrey Ignatov 
1108a7f7547fSAndrey Ignatov 	return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0,
1109a7f7547fSAndrey Ignatov 				 MSG_FASTOPEN, &sendmsg_err);
1110a7f7547fSAndrey Ignatov }
1111a7f7547fSAndrey Ignatov 
recvmsg_from_client(int sockfd,struct sockaddr_storage * src_addr)111204b6ab73SAndrey Ignatov static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr)
111304b6ab73SAndrey Ignatov {
111404b6ab73SAndrey Ignatov 	struct timeval tv;
111504b6ab73SAndrey Ignatov 	struct msghdr hdr;
111604b6ab73SAndrey Ignatov 	struct iovec iov;
111704b6ab73SAndrey Ignatov 	char data[64];
111804b6ab73SAndrey Ignatov 	fd_set rfds;
111904b6ab73SAndrey Ignatov 
112004b6ab73SAndrey Ignatov 	FD_ZERO(&rfds);
112104b6ab73SAndrey Ignatov 	FD_SET(sockfd, &rfds);
112204b6ab73SAndrey Ignatov 
112304b6ab73SAndrey Ignatov 	tv.tv_sec = 2;
112404b6ab73SAndrey Ignatov 	tv.tv_usec = 0;
112504b6ab73SAndrey Ignatov 
112604b6ab73SAndrey Ignatov 	if (select(sockfd + 1, &rfds, NULL, NULL, &tv) <= 0 ||
112704b6ab73SAndrey Ignatov 	    !FD_ISSET(sockfd, &rfds))
112804b6ab73SAndrey Ignatov 		return -1;
112904b6ab73SAndrey Ignatov 
113004b6ab73SAndrey Ignatov 	memset(&iov, 0, sizeof(iov));
113104b6ab73SAndrey Ignatov 	iov.iov_base = data;
113204b6ab73SAndrey Ignatov 	iov.iov_len = sizeof(data);
113304b6ab73SAndrey Ignatov 
113404b6ab73SAndrey Ignatov 	memset(&hdr, 0, sizeof(hdr));
113504b6ab73SAndrey Ignatov 	hdr.msg_name = src_addr;
113604b6ab73SAndrey Ignatov 	hdr.msg_namelen = sizeof(struct sockaddr_storage);
113704b6ab73SAndrey Ignatov 	hdr.msg_iov = &iov;
113804b6ab73SAndrey Ignatov 	hdr.msg_iovlen = 1;
113904b6ab73SAndrey Ignatov 
114004b6ab73SAndrey Ignatov 	return recvmsg(sockfd, &hdr, 0);
114104b6ab73SAndrey Ignatov }
114204b6ab73SAndrey Ignatov 
init_addrs(const struct sock_addr_test * test,struct sockaddr_storage * requested_addr,struct sockaddr_storage * expected_addr,struct sockaddr_storage * expected_src_addr)11439be71aa6SAndrey Ignatov static int init_addrs(const struct sock_addr_test *test,
11449be71aa6SAndrey Ignatov 		      struct sockaddr_storage *requested_addr,
11459be71aa6SAndrey Ignatov 		      struct sockaddr_storage *expected_addr,
11469be71aa6SAndrey Ignatov 		      struct sockaddr_storage *expected_src_addr)
11479be71aa6SAndrey Ignatov {
11489be71aa6SAndrey Ignatov 	socklen_t addr_len = sizeof(struct sockaddr_storage);
11499be71aa6SAndrey Ignatov 
11509be71aa6SAndrey Ignatov 	if (mk_sockaddr(test->domain, test->expected_ip, test->expected_port,
11519be71aa6SAndrey Ignatov 			(struct sockaddr *)expected_addr, addr_len) == -1)
11529be71aa6SAndrey Ignatov 		goto err;
11539be71aa6SAndrey Ignatov 
11549be71aa6SAndrey Ignatov 	if (mk_sockaddr(test->domain, test->requested_ip, test->requested_port,
11559be71aa6SAndrey Ignatov 			(struct sockaddr *)requested_addr, addr_len) == -1)
11569be71aa6SAndrey Ignatov 		goto err;
11579be71aa6SAndrey Ignatov 
11589be71aa6SAndrey Ignatov 	if (test->expected_src_ip &&
11599be71aa6SAndrey Ignatov 	    mk_sockaddr(test->domain, test->expected_src_ip, 0,
11609be71aa6SAndrey Ignatov 			(struct sockaddr *)expected_src_addr, addr_len) == -1)
11619be71aa6SAndrey Ignatov 		goto err;
1162622adafbSAndrey Ignatov 
1163622adafbSAndrey Ignatov 	return 0;
1164622adafbSAndrey Ignatov err:
1165622adafbSAndrey Ignatov 	return -1;
1166622adafbSAndrey Ignatov }
1167622adafbSAndrey Ignatov 
run_bind_test_case(const struct sock_addr_test * test)11689be71aa6SAndrey Ignatov static int run_bind_test_case(const struct sock_addr_test *test)
1169e50b0a6fSAndrey Ignatov {
11709be71aa6SAndrey Ignatov 	socklen_t addr_len = sizeof(struct sockaddr_storage);
11719be71aa6SAndrey Ignatov 	struct sockaddr_storage requested_addr;
11729be71aa6SAndrey Ignatov 	struct sockaddr_storage expected_addr;
11739be71aa6SAndrey Ignatov 	int clientfd = -1;
1174e50b0a6fSAndrey Ignatov 	int servfd = -1;
1175e50b0a6fSAndrey Ignatov 	int err = 0;
1176e50b0a6fSAndrey Ignatov 
11779be71aa6SAndrey Ignatov 	if (init_addrs(test, &requested_addr, &expected_addr, NULL))
11789be71aa6SAndrey Ignatov 		goto err;
1179e50b0a6fSAndrey Ignatov 
11809be71aa6SAndrey Ignatov 	servfd = start_server(test->type, &requested_addr, addr_len);
1181e50b0a6fSAndrey Ignatov 	if (servfd == -1)
1182e50b0a6fSAndrey Ignatov 		goto err;
1183e50b0a6fSAndrey Ignatov 
11849be71aa6SAndrey Ignatov 	if (cmp_local_addr(servfd, &expected_addr))
11859be71aa6SAndrey Ignatov 		goto err;
11869be71aa6SAndrey Ignatov 
11879be71aa6SAndrey Ignatov 	/* Try to connect to server just in case */
11889be71aa6SAndrey Ignatov 	clientfd = connect_to_server(test->type, &expected_addr, addr_len);
11899be71aa6SAndrey Ignatov 	if (clientfd == -1)
1190622adafbSAndrey Ignatov 		goto err;
1191622adafbSAndrey Ignatov 
1192e50b0a6fSAndrey Ignatov 	goto out;
1193e50b0a6fSAndrey Ignatov err:
1194e50b0a6fSAndrey Ignatov 	err = -1;
1195e50b0a6fSAndrey Ignatov out:
11969be71aa6SAndrey Ignatov 	close(clientfd);
1197e50b0a6fSAndrey Ignatov 	close(servfd);
1198e50b0a6fSAndrey Ignatov 	return err;
1199e50b0a6fSAndrey Ignatov }
1200e50b0a6fSAndrey Ignatov 
run_connect_test_case(const struct sock_addr_test * test)12019be71aa6SAndrey Ignatov static int run_connect_test_case(const struct sock_addr_test *test)
1202e50b0a6fSAndrey Ignatov {
12039be71aa6SAndrey Ignatov 	socklen_t addr_len = sizeof(struct sockaddr_storage);
12049be71aa6SAndrey Ignatov 	struct sockaddr_storage expected_src_addr;
12059be71aa6SAndrey Ignatov 	struct sockaddr_storage requested_addr;
12069be71aa6SAndrey Ignatov 	struct sockaddr_storage expected_addr;
12079be71aa6SAndrey Ignatov 	int clientfd = -1;
12089be71aa6SAndrey Ignatov 	int servfd = -1;
1209e50b0a6fSAndrey Ignatov 	int err = 0;
1210e50b0a6fSAndrey Ignatov 
12119be71aa6SAndrey Ignatov 	if (init_addrs(test, &requested_addr, &expected_addr,
12129be71aa6SAndrey Ignatov 		       &expected_src_addr))
1213e50b0a6fSAndrey Ignatov 		goto err;
1214e50b0a6fSAndrey Ignatov 
12159be71aa6SAndrey Ignatov 	/* Prepare server to connect to */
12169be71aa6SAndrey Ignatov 	servfd = start_server(test->type, &expected_addr, addr_len);
12179be71aa6SAndrey Ignatov 	if (servfd == -1)
1218e50b0a6fSAndrey Ignatov 		goto err;
1219e50b0a6fSAndrey Ignatov 
12209be71aa6SAndrey Ignatov 	clientfd = connect_to_server(test->type, &requested_addr, addr_len);
12219be71aa6SAndrey Ignatov 	if (clientfd == -1)
12229be71aa6SAndrey Ignatov 		goto err;
12239be71aa6SAndrey Ignatov 
12249be71aa6SAndrey Ignatov 	/* Make sure src and dst addrs were overridden properly */
12259be71aa6SAndrey Ignatov 	if (cmp_peer_addr(clientfd, &expected_addr))
12269be71aa6SAndrey Ignatov 		goto err;
12279be71aa6SAndrey Ignatov 
12289be71aa6SAndrey Ignatov 	if (cmp_local_ip(clientfd, &expected_src_addr))
1229e50b0a6fSAndrey Ignatov 		goto err;
1230e50b0a6fSAndrey Ignatov 
1231a7f7547fSAndrey Ignatov 	if (test->type == SOCK_STREAM) {
1232a7f7547fSAndrey Ignatov 		/* Test TCP Fast Open scenario */
1233a7f7547fSAndrey Ignatov 		clientfd = fastconnect_to_server(&requested_addr, addr_len);
1234a7f7547fSAndrey Ignatov 		if (clientfd == -1)
1235a7f7547fSAndrey Ignatov 			goto err;
1236a7f7547fSAndrey Ignatov 
1237a7f7547fSAndrey Ignatov 		/* Make sure src and dst addrs were overridden properly */
1238a7f7547fSAndrey Ignatov 		if (cmp_peer_addr(clientfd, &expected_addr))
1239a7f7547fSAndrey Ignatov 			goto err;
1240a7f7547fSAndrey Ignatov 
1241a7f7547fSAndrey Ignatov 		if (cmp_local_ip(clientfd, &expected_src_addr))
1242a7f7547fSAndrey Ignatov 			goto err;
1243a7f7547fSAndrey Ignatov 	}
1244a7f7547fSAndrey Ignatov 
1245e50b0a6fSAndrey Ignatov 	goto out;
1246e50b0a6fSAndrey Ignatov err:
1247e50b0a6fSAndrey Ignatov 	err = -1;
1248e50b0a6fSAndrey Ignatov out:
12499be71aa6SAndrey Ignatov 	close(clientfd);
12509be71aa6SAndrey Ignatov 	close(servfd);
1251e50b0a6fSAndrey Ignatov 	return err;
1252e50b0a6fSAndrey Ignatov }
1253e50b0a6fSAndrey Ignatov 
run_xmsg_test_case(const struct sock_addr_test * test,int max_cmsg)12541812291eSDaniel Borkmann static int run_xmsg_test_case(const struct sock_addr_test *test, int max_cmsg)
125504b6ab73SAndrey Ignatov {
125604b6ab73SAndrey Ignatov 	socklen_t addr_len = sizeof(struct sockaddr_storage);
125704b6ab73SAndrey Ignatov 	struct sockaddr_storage expected_addr;
12581812291eSDaniel Borkmann 	struct sockaddr_storage server_addr;
12591812291eSDaniel Borkmann 	struct sockaddr_storage sendmsg_addr;
12601812291eSDaniel Borkmann 	struct sockaddr_storage recvmsg_addr;
126104b6ab73SAndrey Ignatov 	int clientfd = -1;
126204b6ab73SAndrey Ignatov 	int servfd = -1;
126304b6ab73SAndrey Ignatov 	int set_cmsg;
126404b6ab73SAndrey Ignatov 	int err = 0;
126504b6ab73SAndrey Ignatov 
126604b6ab73SAndrey Ignatov 	if (test->type != SOCK_DGRAM)
126704b6ab73SAndrey Ignatov 		goto err;
126804b6ab73SAndrey Ignatov 
12691812291eSDaniel Borkmann 	if (init_addrs(test, &sendmsg_addr, &server_addr, &expected_addr))
127004b6ab73SAndrey Ignatov 		goto err;
127104b6ab73SAndrey Ignatov 
127204b6ab73SAndrey Ignatov 	/* Prepare server to sendmsg to */
12731812291eSDaniel Borkmann 	servfd = start_server(test->type, &server_addr, addr_len);
127404b6ab73SAndrey Ignatov 	if (servfd == -1)
127504b6ab73SAndrey Ignatov 		goto err;
127604b6ab73SAndrey Ignatov 
12771812291eSDaniel Borkmann 	for (set_cmsg = 0; set_cmsg <= max_cmsg; ++set_cmsg) {
127804b6ab73SAndrey Ignatov 		if (clientfd >= 0)
127904b6ab73SAndrey Ignatov 			close(clientfd);
128004b6ab73SAndrey Ignatov 
12811812291eSDaniel Borkmann 		clientfd = sendmsg_to_server(test->type, &sendmsg_addr,
1282a7f7547fSAndrey Ignatov 					     addr_len, set_cmsg, /*flags*/0,
1283a7f7547fSAndrey Ignatov 					     &err);
128404b6ab73SAndrey Ignatov 		if (err)
128504b6ab73SAndrey Ignatov 			goto out;
128604b6ab73SAndrey Ignatov 		else if (clientfd == -1)
128704b6ab73SAndrey Ignatov 			goto err;
128804b6ab73SAndrey Ignatov 
128904b6ab73SAndrey Ignatov 		/* Try to receive message on server instead of using
129004b6ab73SAndrey Ignatov 		 * getpeername(2) on client socket, to check that client's
129104b6ab73SAndrey Ignatov 		 * destination address was rewritten properly, since
129204b6ab73SAndrey Ignatov 		 * getpeername(2) doesn't work with unconnected datagram
129304b6ab73SAndrey Ignatov 		 * sockets.
129404b6ab73SAndrey Ignatov 		 *
129504b6ab73SAndrey Ignatov 		 * Get source address from recvmsg(2) as well to make sure
129604b6ab73SAndrey Ignatov 		 * source was rewritten properly: getsockname(2) can't be used
129704b6ab73SAndrey Ignatov 		 * since socket is unconnected and source defined for one
129804b6ab73SAndrey Ignatov 		 * specific packet may differ from the one used by default and
129904b6ab73SAndrey Ignatov 		 * returned by getsockname(2).
130004b6ab73SAndrey Ignatov 		 */
13011812291eSDaniel Borkmann 		if (recvmsg_from_client(servfd, &recvmsg_addr) == -1)
130204b6ab73SAndrey Ignatov 			goto err;
130304b6ab73SAndrey Ignatov 
13041812291eSDaniel Borkmann 		if (cmp_addr(&recvmsg_addr, &expected_addr, /*cmp_port*/0))
130504b6ab73SAndrey Ignatov 			goto err;
130604b6ab73SAndrey Ignatov 	}
130704b6ab73SAndrey Ignatov 
130804b6ab73SAndrey Ignatov 	goto out;
130904b6ab73SAndrey Ignatov err:
131004b6ab73SAndrey Ignatov 	err = -1;
131104b6ab73SAndrey Ignatov out:
131204b6ab73SAndrey Ignatov 	close(clientfd);
131304b6ab73SAndrey Ignatov 	close(servfd);
131404b6ab73SAndrey Ignatov 	return err;
131504b6ab73SAndrey Ignatov }
131604b6ab73SAndrey Ignatov 
run_test_case(int cgfd,const struct sock_addr_test * test)13179be71aa6SAndrey Ignatov static int run_test_case(int cgfd, const struct sock_addr_test *test)
1318e50b0a6fSAndrey Ignatov {
13199be71aa6SAndrey Ignatov 	int progfd = -1;
13209be71aa6SAndrey Ignatov 	int err = 0;
13219be71aa6SAndrey Ignatov 
13229be71aa6SAndrey Ignatov 	printf("Test case: %s .. ", test->descr);
13239be71aa6SAndrey Ignatov 
13249be71aa6SAndrey Ignatov 	progfd = test->loadfn(test);
13259be71aa6SAndrey Ignatov 	if (test->expected_result == LOAD_REJECT && progfd < 0)
13269be71aa6SAndrey Ignatov 		goto out;
13279be71aa6SAndrey Ignatov 	else if (test->expected_result == LOAD_REJECT || progfd < 0)
13289be71aa6SAndrey Ignatov 		goto err;
13299be71aa6SAndrey Ignatov 
13309be71aa6SAndrey Ignatov 	err = bpf_prog_attach(progfd, cgfd, test->attach_type,
13319be71aa6SAndrey Ignatov 			      BPF_F_ALLOW_OVERRIDE);
13329be71aa6SAndrey Ignatov 	if (test->expected_result == ATTACH_REJECT && err) {
13339be71aa6SAndrey Ignatov 		err = 0; /* error was expected, reset it */
13349be71aa6SAndrey Ignatov 		goto out;
13359be71aa6SAndrey Ignatov 	} else if (test->expected_result == ATTACH_REJECT || err) {
13369be71aa6SAndrey Ignatov 		goto err;
13371812291eSDaniel Borkmann 	} else if (test->expected_result == ATTACH_OKAY) {
13381812291eSDaniel Borkmann 		err = 0;
13391812291eSDaniel Borkmann 		goto out;
13409be71aa6SAndrey Ignatov 	}
13419be71aa6SAndrey Ignatov 
13429be71aa6SAndrey Ignatov 	switch (test->attach_type) {
13439be71aa6SAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
13449be71aa6SAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
13459be71aa6SAndrey Ignatov 		err = run_bind_test_case(test);
13469be71aa6SAndrey Ignatov 		break;
13479be71aa6SAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
13489be71aa6SAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
13499be71aa6SAndrey Ignatov 		err = run_connect_test_case(test);
13509be71aa6SAndrey Ignatov 		break;
135104b6ab73SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
135204b6ab73SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
13531812291eSDaniel Borkmann 		err = run_xmsg_test_case(test, 1);
13541812291eSDaniel Borkmann 		break;
13551812291eSDaniel Borkmann 	case BPF_CGROUP_UDP4_RECVMSG:
13561812291eSDaniel Borkmann 	case BPF_CGROUP_UDP6_RECVMSG:
13571812291eSDaniel Borkmann 		err = run_xmsg_test_case(test, 0);
135804b6ab73SAndrey Ignatov 		break;
13599be71aa6SAndrey Ignatov 	default:
13609be71aa6SAndrey Ignatov 		goto err;
13619be71aa6SAndrey Ignatov 	}
13629be71aa6SAndrey Ignatov 
136304b6ab73SAndrey Ignatov 	if (test->expected_result == SYSCALL_EPERM && err == EPERM) {
136404b6ab73SAndrey Ignatov 		err = 0; /* error was expected, reset it */
136504b6ab73SAndrey Ignatov 		goto out;
136604b6ab73SAndrey Ignatov 	}
136704b6ab73SAndrey Ignatov 
136804b6ab73SAndrey Ignatov 	if (test->expected_result == SYSCALL_ENOTSUPP && err == ENOTSUPP) {
136904b6ab73SAndrey Ignatov 		err = 0; /* error was expected, reset it */
137004b6ab73SAndrey Ignatov 		goto out;
137104b6ab73SAndrey Ignatov 	}
137204b6ab73SAndrey Ignatov 
13739be71aa6SAndrey Ignatov 	if (err || test->expected_result != SUCCESS)
13749be71aa6SAndrey Ignatov 		goto err;
13759be71aa6SAndrey Ignatov 
13769be71aa6SAndrey Ignatov 	goto out;
13779be71aa6SAndrey Ignatov err:
13789be71aa6SAndrey Ignatov 	err = -1;
13799be71aa6SAndrey Ignatov out:
13809be71aa6SAndrey Ignatov 	/* Detaching w/o checking return code: best effort attempt. */
13819be71aa6SAndrey Ignatov 	if (progfd != -1)
13829be71aa6SAndrey Ignatov 		bpf_prog_detach(cgfd, test->attach_type);
13839be71aa6SAndrey Ignatov 	close(progfd);
13849be71aa6SAndrey Ignatov 	printf("[%s]\n", err ? "FAIL" : "PASS");
13859be71aa6SAndrey Ignatov 	return err;
13869be71aa6SAndrey Ignatov }
13879be71aa6SAndrey Ignatov 
run_tests(int cgfd)13889be71aa6SAndrey Ignatov static int run_tests(int cgfd)
13899be71aa6SAndrey Ignatov {
13909be71aa6SAndrey Ignatov 	int passes = 0;
13919be71aa6SAndrey Ignatov 	int fails = 0;
13929be71aa6SAndrey Ignatov 	int i;
13939be71aa6SAndrey Ignatov 
13949be71aa6SAndrey Ignatov 	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
13959be71aa6SAndrey Ignatov 		if (run_test_case(cgfd, &tests[i]))
13969be71aa6SAndrey Ignatov 			++fails;
13979be71aa6SAndrey Ignatov 		else
13989be71aa6SAndrey Ignatov 			++passes;
13999be71aa6SAndrey Ignatov 	}
14009be71aa6SAndrey Ignatov 	printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
14019be71aa6SAndrey Ignatov 	return fails ? -1 : 0;
14029be71aa6SAndrey Ignatov }
14039be71aa6SAndrey Ignatov 
main(int argc,char ** argv)14049be71aa6SAndrey Ignatov int main(int argc, char **argv)
14059be71aa6SAndrey Ignatov {
1406e50b0a6fSAndrey Ignatov 	int cgfd = -1;
1407e50b0a6fSAndrey Ignatov 	int err = 0;
1408e50b0a6fSAndrey Ignatov 
14099be71aa6SAndrey Ignatov 	if (argc < 2) {
14109be71aa6SAndrey Ignatov 		fprintf(stderr,
14119be71aa6SAndrey Ignatov 			"%s has to be run via %s.sh. Skip direct run.\n",
14129be71aa6SAndrey Ignatov 			argv[0], argv[0]);
14139be71aa6SAndrey Ignatov 		exit(err);
14149be71aa6SAndrey Ignatov 	}
1415e50b0a6fSAndrey Ignatov 
14164939b284SJohn Fastabend 	cgfd = cgroup_setup_and_join(CG_PATH);
1417a8911d6dSStanislav Fomichev 	if (cgfd < 0)
1418e50b0a6fSAndrey Ignatov 		goto err;
1419e50b0a6fSAndrey Ignatov 
1420b858ba8cSYafang Shao 	/* Use libbpf 1.0 API mode */
1421b858ba8cSYafang Shao 	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
1422b858ba8cSYafang Shao 
14239be71aa6SAndrey Ignatov 	if (run_tests(cgfd))
1424e50b0a6fSAndrey Ignatov 		goto err;
1425e50b0a6fSAndrey Ignatov 
1426e50b0a6fSAndrey Ignatov 	goto out;
1427e50b0a6fSAndrey Ignatov err:
1428e50b0a6fSAndrey Ignatov 	err = -1;
1429e50b0a6fSAndrey Ignatov out:
1430e50b0a6fSAndrey Ignatov 	close(cgfd);
1431e50b0a6fSAndrey Ignatov 	cleanup_cgroup_environment();
1432e50b0a6fSAndrey Ignatov 	return err;
1433e50b0a6fSAndrey Ignatov }
1434