xref: /linux/tools/testing/selftests/bpf/prog_tests/connect_force_port.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <test_progs.h>
4 #include "cgroup_helpers.h"
5 #include "network_helpers.h"
6 
7 static int verify_ports(int family, int fd,
8 			__u16 expected_local, __u16 expected_peer)
9 {
10 	struct sockaddr_storage addr;
11 	socklen_t len = sizeof(addr);
12 	__u16 port;
13 
14 	if (getsockname(fd, (struct sockaddr *)&addr, &len)) {
15 		log_err("Failed to get server addr");
16 		return -1;
17 	}
18 
19 	if (family == AF_INET)
20 		port = ((struct sockaddr_in *)&addr)->sin_port;
21 	else
22 		port = ((struct sockaddr_in6 *)&addr)->sin6_port;
23 
24 	if (ntohs(port) != expected_local) {
25 		log_err("Unexpected local port %d, expected %d", ntohs(port),
26 			expected_local);
27 		return -1;
28 	}
29 
30 	if (getpeername(fd, (struct sockaddr *)&addr, &len)) {
31 		log_err("Failed to get peer addr");
32 		return -1;
33 	}
34 
35 	if (family == AF_INET)
36 		port = ((struct sockaddr_in *)&addr)->sin_port;
37 	else
38 		port = ((struct sockaddr_in6 *)&addr)->sin6_port;
39 
40 	if (ntohs(port) != expected_peer) {
41 		log_err("Unexpected peer port %d, expected %d", ntohs(port),
42 			expected_peer);
43 		return -1;
44 	}
45 
46 	return 0;
47 }
48 
49 static int run_test(int cgroup_fd, int server_fd, int family, int type)
50 {
51 	bool v4 = family == AF_INET;
52 	__u16 expected_local_port = v4 ? 22222 : 22223;
53 	__u16 expected_peer_port = 60000;
54 	struct bpf_program *prog;
55 	struct bpf_object *obj;
56 	struct bpf_map *map;
57 	__u16 *port_ptr;
58 	size_t port_size;
59 	const char *obj_file = v4 ? "connect_force_port4.bpf.o" : "connect_force_port6.bpf.o";
60 	int fd, err;
61 	__u32 duration = 0;
62 
63 	obj = bpf_object__open_file(obj_file, NULL);
64 	if (!ASSERT_OK_PTR(obj, "bpf_obj_open"))
65 		return -1;
66 
67 	map = bpf_object__find_map_by_name(obj, ".bss");
68 	if (!ASSERT_OK_PTR(map, "find bss map")) {
69 		err = -EIO;
70 		goto close_bpf_object;
71 	}
72 
73 	port_ptr = bpf_map__initial_value(map, &port_size);
74 	if (!ASSERT_OK_PTR(port_ptr, "get bss initial value")) {
75 		err = -EIO;
76 		goto close_bpf_object;
77 	}
78 
79 	/* Auto assigns the port according to availability */
80 	*port_ptr = ntohs(get_socket_local_port(server_fd));
81 
82 	err = bpf_object__load(obj);
83 	if (!ASSERT_OK(err, "bpf_obj_load")) {
84 		err = -EIO;
85 		goto close_bpf_object;
86 	}
87 
88 	prog = bpf_object__find_program_by_name(obj, v4 ?
89 						"connect4" :
90 						"connect6");
91 	if (CHECK(!prog, "find_prog", "connect prog not found\n")) {
92 		err = -EIO;
93 		goto close_bpf_object;
94 	}
95 
96 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
97 			      BPF_CGROUP_INET4_CONNECT :
98 			      BPF_CGROUP_INET6_CONNECT, 0);
99 	if (err) {
100 		log_err("Failed to attach BPF program");
101 		goto close_bpf_object;
102 	}
103 
104 	prog = bpf_object__find_program_by_name(obj, v4 ?
105 						"getpeername4" :
106 						"getpeername6");
107 	if (CHECK(!prog, "find_prog", "getpeername prog not found\n")) {
108 		err = -EIO;
109 		goto close_bpf_object;
110 	}
111 
112 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
113 			      BPF_CGROUP_INET4_GETPEERNAME :
114 			      BPF_CGROUP_INET6_GETPEERNAME, 0);
115 	if (err) {
116 		log_err("Failed to attach BPF program");
117 		goto close_bpf_object;
118 	}
119 
120 	prog = bpf_object__find_program_by_name(obj, v4 ?
121 						"getsockname4" :
122 						"getsockname6");
123 	if (CHECK(!prog, "find_prog", "getsockname prog not found\n")) {
124 		err = -EIO;
125 		goto close_bpf_object;
126 	}
127 
128 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
129 			      BPF_CGROUP_INET4_GETSOCKNAME :
130 			      BPF_CGROUP_INET6_GETSOCKNAME, 0);
131 	if (err) {
132 		log_err("Failed to attach BPF program");
133 		goto close_bpf_object;
134 	}
135 
136 	fd = connect_to_fd(server_fd, 0);
137 	if (fd < 0) {
138 		err = -1;
139 		goto close_bpf_object;
140 	}
141 
142 	err = verify_ports(family, fd, expected_local_port,
143 			   expected_peer_port);
144 	close(fd);
145 
146 close_bpf_object:
147 	bpf_object__close(obj);
148 	return err;
149 }
150 
151 void test_connect_force_port(void)
152 {
153 	int server_fd, cgroup_fd;
154 
155 	cgroup_fd = test__join_cgroup("/connect_force_port");
156 	if (CHECK_FAIL(cgroup_fd < 0))
157 		return;
158 
159 	server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);
160 	if (CHECK_FAIL(server_fd < 0))
161 		goto close_cgroup_fd;
162 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_STREAM));
163 	close(server_fd);
164 
165 	server_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
166 	if (CHECK_FAIL(server_fd < 0))
167 		goto close_cgroup_fd;
168 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_STREAM));
169 	close(server_fd);
170 
171 	server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
172 	if (CHECK_FAIL(server_fd < 0))
173 		goto close_cgroup_fd;
174 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_DGRAM));
175 	close(server_fd);
176 
177 	server_fd = start_server(AF_INET6, SOCK_DGRAM, NULL, 0, 0);
178 	if (CHECK_FAIL(server_fd < 0))
179 		goto close_cgroup_fd;
180 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_DGRAM));
181 	close(server_fd);
182 
183 close_cgroup_fd:
184 	close(cgroup_fd);
185 }
186