xref: /linux/tools/testing/selftests/bpf/prog_tests/setget_sockopt.c (revision 5cf2c21ab0900b41c0e29c925b9a640a92340d40)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
3 
4 #define _GNU_SOURCE
5 #include <sched.h>
6 #include <linux/socket.h>
7 #include <linux/tls.h>
8 #include <net/if.h>
9 
10 #include "test_progs.h"
11 #include "cgroup_helpers.h"
12 #include "network_helpers.h"
13 
14 #include "setget_sockopt.skel.h"
15 
16 #define CG_NAME "/setget-sockopt-test"
17 
18 static const char addr4_str[] = "127.0.0.1";
19 static const char addr6_str[] = "::1";
20 static struct setget_sockopt *skel;
21 static int cg_fd;
22 
23 static int create_netns(void)
24 {
25 	if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
26 		return -1;
27 
28 	if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up"))
29 		return -1;
30 
31 	if (!ASSERT_OK(system("ip link add dev binddevtest1 type veth peer name binddevtest2"),
32 		       "add veth"))
33 		return -1;
34 
35 	if (!ASSERT_OK(system("ip link set dev binddevtest1 up"),
36 		       "bring veth up"))
37 		return -1;
38 
39 	return 0;
40 }
41 
42 static void test_tcp(int family)
43 {
44 	struct setget_sockopt__bss *bss = skel->bss;
45 	int sfd, cfd;
46 
47 	memset(bss, 0, sizeof(*bss));
48 
49 	sfd = start_server(family, SOCK_STREAM,
50 			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
51 	if (!ASSERT_GE(sfd, 0, "start_server"))
52 		return;
53 
54 	cfd = connect_to_fd(sfd, 0);
55 	if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) {
56 		close(sfd);
57 		return;
58 	}
59 	close(sfd);
60 	close(cfd);
61 
62 	ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
63 	ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
64 	ASSERT_EQ(bss->nr_active, 1, "nr_active");
65 	ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
66 	ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
67 	ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
68 }
69 
70 static void test_udp(int family)
71 {
72 	struct setget_sockopt__bss *bss = skel->bss;
73 	int sfd;
74 
75 	memset(bss, 0, sizeof(*bss));
76 
77 	sfd = start_server(family, SOCK_DGRAM,
78 			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
79 	if (!ASSERT_GE(sfd, 0, "start_server"))
80 		return;
81 	close(sfd);
82 
83 	ASSERT_GE(bss->nr_socket_post_create, 1, "nr_socket_post_create");
84 	ASSERT_EQ(bss->nr_binddev, 1, "nr_bind");
85 }
86 
87 static void test_ktls(int family)
88 {
89 	struct tls12_crypto_info_aes_gcm_128 aes128;
90 	struct setget_sockopt__bss *bss = skel->bss;
91 	int cfd = -1, sfd = -1, fd = -1, ret;
92 	char buf;
93 
94 	memset(bss, 0, sizeof(*bss));
95 
96 	sfd = start_server(family, SOCK_STREAM,
97 			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
98 	if (!ASSERT_GE(sfd, 0, "start_server"))
99 		return;
100 	fd = connect_to_fd(sfd, 0);
101 	if (!ASSERT_GE(fd, 0, "connect_to_fd"))
102 		goto err_out;
103 
104 	cfd = accept(sfd, NULL, 0);
105 	if (!ASSERT_GE(cfd, 0, "accept"))
106 		goto err_out;
107 
108 	close(sfd);
109 	sfd = -1;
110 
111 	/* Setup KTLS */
112 	ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
113 	if (!ASSERT_OK(ret, "setsockopt"))
114 		goto err_out;
115 	ret = setsockopt(cfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
116 	if (!ASSERT_OK(ret, "setsockopt"))
117 		goto err_out;
118 
119 	memset(&aes128, 0, sizeof(aes128));
120 	aes128.info.version = TLS_1_2_VERSION;
121 	aes128.info.cipher_type = TLS_CIPHER_AES_GCM_128;
122 
123 	ret = setsockopt(fd, SOL_TLS, TLS_TX, &aes128, sizeof(aes128));
124 	if (!ASSERT_OK(ret, "setsockopt"))
125 		goto err_out;
126 
127 	ret = setsockopt(cfd, SOL_TLS, TLS_RX, &aes128, sizeof(aes128));
128 	if (!ASSERT_OK(ret, "setsockopt"))
129 		goto err_out;
130 
131 	/* KTLS is enabled */
132 
133 	close(fd);
134 	/* At this point, the cfd socket is at the CLOSE_WAIT state
135 	 * and still run TLS protocol.  The test for
136 	 * BPF_TCP_CLOSE_WAIT should be run at this point.
137 	 */
138 	ret = read(cfd, &buf, sizeof(buf));
139 	ASSERT_EQ(ret, 0, "read");
140 	close(cfd);
141 
142 	ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
143 	ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
144 	ASSERT_EQ(bss->nr_active, 1, "nr_active");
145 	ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
146 	ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
147 	ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
148 	ASSERT_EQ(bss->nr_fin_wait1, 1, "nr_fin_wait1");
149 	return;
150 
151 err_out:
152 	close(fd);
153 	close(cfd);
154 	close(sfd);
155 }
156 
157 static void test_nonstandard_opt(int family)
158 {
159 	struct setget_sockopt__bss *bss = skel->bss;
160 	struct bpf_link *getsockopt_link = NULL;
161 	int sfd = -1, fd = -1, cfd = -1, flags;
162 	socklen_t flagslen = sizeof(flags);
163 
164 	memset(bss, 0, sizeof(*bss));
165 
166 	sfd = start_server(family, SOCK_STREAM,
167 			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
168 	if (!ASSERT_GE(sfd, 0, "start_server"))
169 		return;
170 
171 	fd = connect_to_fd(sfd, 0);
172 	if (!ASSERT_GE(fd, 0, "connect_to_fd_server"))
173 		goto err_out;
174 
175 	/* cgroup/getsockopt prog will intercept getsockopt() below and
176 	 * retrieve the tcp socket bpf_sock_ops_cb_flags value for the
177 	 * accept()ed socket; this was set earlier in the passive established
178 	 * callback for the accept()ed socket via bpf_setsockopt().
179 	 */
180 	getsockopt_link = bpf_program__attach_cgroup(skel->progs._getsockopt, cg_fd);
181 	if (!ASSERT_OK_PTR(getsockopt_link, "getsockopt prog"))
182 		goto err_out;
183 
184 	cfd = accept(sfd, NULL, 0);
185 	if (!ASSERT_GE(cfd, 0, "accept"))
186 		goto err_out;
187 
188 	if (!ASSERT_OK(getsockopt(cfd, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, &flagslen),
189 		       "getsockopt_flags"))
190 		goto err_out;
191 	ASSERT_EQ(flags & BPF_SOCK_OPS_STATE_CB_FLAG, BPF_SOCK_OPS_STATE_CB_FLAG,
192 		  "cb_flags_set");
193 err_out:
194 	close(sfd);
195 	if (fd != -1)
196 		close(fd);
197 	if (cfd != -1)
198 		close(cfd);
199 	bpf_link__destroy(getsockopt_link);
200 }
201 
202 static int connect_to_v4mapped_v6_fd(int server_fd)
203 {
204 	struct sockaddr_storage addr;
205 	struct sockaddr_in *addr4 = (void *)&addr;
206 	socklen_t addrlen = sizeof(addr);
207 	struct sockaddr_in6 addr6 = {};
208 	int fd = -1, v6only = 0, err;
209 
210 	err = getsockname(server_fd, (struct sockaddr *)&addr, &addrlen);
211 	if (!ASSERT_OK(err, "getsockname"))
212 		return -1;
213 
214 	fd = socket(AF_INET6, SOCK_STREAM, 0);
215 	if (!ASSERT_GE(fd, 0, "socket"))
216 		return -1;
217 
218 	err = settimeo(fd, 0);
219 	if (!ASSERT_OK(err, "settimeo"))
220 		goto err_out;
221 
222 	err = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only));
223 	if (!ASSERT_OK(err, "clear_v6only"))
224 		goto err_out;
225 
226 	addr6.sin6_family = AF_INET6;
227 	addr6.sin6_port = addr4->sin_port;
228 	addr6.sin6_addr.s6_addr[10] = 0xff;
229 	addr6.sin6_addr.s6_addr[11] = 0xff;
230 	memcpy(&addr6.sin6_addr.s6_addr[12], &addr4->sin_addr, sizeof(addr4->sin_addr));
231 
232 	err = connect(fd, (struct sockaddr *)&addr6, sizeof(addr6));
233 	if (!ASSERT_OK(err, "connect"))
234 		goto err_out;
235 
236 	return fd;
237 
238 err_out:
239 	close(fd);
240 	return -1;
241 }
242 
243 static void test_v4mapped_v6_ip_tos(void)
244 {
245 	struct setget_sockopt__bss *bss = skel->bss;
246 	int sfd = -1, fd = -1, got = 0, exp = 0x1c;
247 	socklen_t optlen;
248 
249 	memset(bss, 0, sizeof(*bss));
250 	bss->v4mapped_v6_ip_tos_enable = 1;
251 	bss->v4mapped_v6_ip_tos_ret = -1;
252 	bss->v4mapped_v6_ip_tos_val = exp;
253 
254 	sfd = start_server(AF_INET, SOCK_STREAM, addr4_str, 0, 0);
255 	if (!ASSERT_GE(sfd, 0, "start_server"))
256 		goto err_out;
257 
258 	fd = connect_to_v4mapped_v6_fd(sfd);
259 	if (!ASSERT_GE(fd, 0, "connect_to_v4mapped_v6_fd"))
260 		goto err_out;
261 
262 	ASSERT_GT(bss->v4mapped_v6_ip_tos_cnt, 0, "v4mapped_v6_ip_tos_cnt");
263 	ASSERT_EQ(bss->v4mapped_v6_ip_tos_ret, 0, "v4mapped_v6_ip_tos_ret");
264 
265 	optlen = sizeof(got);
266 	if (!ASSERT_OK(getsockopt(fd, SOL_IP, IP_TOS, &got, &optlen), "getsockopt_ip_tos"))
267 		goto err_out;
268 
269 	ASSERT_EQ(got, exp, "ip_tos");
270 
271 err_out:
272 	bss->v4mapped_v6_ip_tos_enable = 0;
273 	if (fd >= 0)
274 		close(fd);
275 	if (sfd >= 0)
276 		close(sfd);
277 }
278 
279 void test_setget_sockopt(void)
280 {
281 	cg_fd = test__join_cgroup(CG_NAME);
282 	if (!ASSERT_OK_FD(cg_fd, "join cgroup"))
283 		return;
284 
285 	if (create_netns())
286 		goto done;
287 
288 	skel = setget_sockopt__open();
289 	if (!ASSERT_OK_PTR(skel, "open skel"))
290 		goto done;
291 
292 	strscpy(skel->rodata->veth, "binddevtest1");
293 	skel->rodata->veth_ifindex = if_nametoindex("binddevtest1");
294 	if (!ASSERT_GT(skel->rodata->veth_ifindex, 0, "if_nametoindex"))
295 		goto done;
296 
297 	if (!ASSERT_OK(setget_sockopt__load(skel), "load skel"))
298 		goto done;
299 
300 	skel->links.skops_sockopt =
301 		bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd);
302 	if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup"))
303 		goto done;
304 
305 	skel->links.socket_post_create =
306 		bpf_program__attach_cgroup(skel->progs.socket_post_create, cg_fd);
307 	if (!ASSERT_OK_PTR(skel->links.socket_post_create, "attach_cgroup"))
308 		goto done;
309 
310 	test_tcp(AF_INET6);
311 	test_tcp(AF_INET);
312 	test_udp(AF_INET6);
313 	test_udp(AF_INET);
314 	test_ktls(AF_INET6);
315 	test_ktls(AF_INET);
316 	test_nonstandard_opt(AF_INET);
317 	test_nonstandard_opt(AF_INET6);
318 	test_v4mapped_v6_ip_tos();
319 
320 done:
321 	setget_sockopt__destroy(skel);
322 	close(cg_fd);
323 }
324