xref: /linux/tools/testing/selftests/net/ipv6_flowlabel_mgr.c (revision c36461825469a9ceee2346a2e89286c522525da7)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Test IPV6_FLOWINFO_MGR */
3 
4 #define _GNU_SOURCE
5 
6 #include <arpa/inet.h>
7 #include <error.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <limits.h>
11 #include <linux/in6.h>
12 #include <net/if.h>
13 #include <sched.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/ioctl.h>
20 #include <sys/socket.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 #include "kselftest_harness.h"
27 
28 /* uapi/glibc weirdness may leave this undefined */
29 #ifndef IPV6_FLOWLABEL_MGR
30 #define IPV6_FLOWLABEL_MGR	32
31 #endif
32 #ifndef IPV6_FLOWINFO_SEND
33 #define IPV6_FLOWINFO_SEND	33
34 #endif
35 
36 /* from net/ipv6/ip6_flowlabel.c */
37 #define FL_MIN_LINGER		6
38 
39 static int flowlabel_get(int fd, uint32_t label, uint8_t share, uint16_t flags)
40 {
41 	struct in6_flowlabel_req req = {
42 		.flr_action = IPV6_FL_A_GET,
43 		.flr_label = htonl(label),
44 		.flr_flags = flags,
45 		.flr_share = share,
46 	};
47 
48 	/* do not pass IPV6_ADDR_ANY or IPV6_ADDR_MAPPED */
49 	req.flr_dst.s6_addr[0] = 0xfd;
50 	req.flr_dst.s6_addr[15] = 0x1;
51 
52 	return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
53 }
54 
55 static int flowlabel_put(int fd, uint32_t label)
56 {
57 	struct in6_flowlabel_req req = {
58 		.flr_action = IPV6_FL_A_PUT,
59 		.flr_label = htonl(label),
60 	};
61 
62 	return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
63 }
64 
65 static int flowlabel_renew(int fd, uint32_t label, uint8_t share,
66 			   uint16_t linger)
67 {
68 	struct in6_flowlabel_req req = {
69 		.flr_action = IPV6_FL_A_RENEW,
70 		.flr_label = htonl(label),
71 		.flr_share = share,
72 		.flr_linger = linger,
73 	};
74 
75 	return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
76 }
77 
78 static struct sockaddr_in6 loopback_addr(void)
79 {
80 	struct sockaddr_in6 addr = {
81 		.sin6_family	= AF_INET6,
82 		.sin6_addr	= IN6ADDR_LOOPBACK_INIT,
83 		.sin6_port	= htons(8888),
84 	};
85 
86 	return addr;
87 }
88 
89 static int tcp_listen(void)
90 {
91 	struct sockaddr_in6 addr = loopback_addr();
92 	const int one = 1;
93 	int fd;
94 
95 	fd = socket(PF_INET6, SOCK_STREAM, 0);
96 	if (fd == -1)
97 		error(1, errno, "socket listener");
98 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
99 		error(1, errno, "setsockopt SO_REUSEADDR");
100 	if (bind(fd, (void *)&addr, sizeof(addr)))
101 		error(1, errno, "bind");
102 	if (listen(fd, 1))
103 		error(1, errno, "listen");
104 
105 	return fd;
106 }
107 
108 static void tcp_connect(int listener, uint32_t flowlabel,
109 			int *client, int *accepted)
110 {
111 	struct sockaddr_in6 addr = loopback_addr();
112 	const int one = 1;
113 	int cfd, afd;
114 
115 	cfd = socket(PF_INET6, SOCK_STREAM, 0);
116 	if (cfd == -1)
117 		error(1, errno, "socket client");
118 
119 	if (flowlabel_get(cfd, flowlabel, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE))
120 		error(1, errno, "flowlabel_get");
121 	if (setsockopt(cfd, SOL_IPV6, IPV6_FLOWINFO_SEND, &one, sizeof(one)))
122 		error(1, errno, "setsockopt flowinfo_send");
123 	addr.sin6_flowinfo = htonl(flowlabel);
124 
125 	if (connect(cfd, (void *)&addr, sizeof(addr)))
126 		error(1, errno, "connect");
127 
128 	afd = accept(listener, NULL, NULL);
129 	if (afd == -1)
130 		error(1, errno, "accept");
131 
132 	if (flowlabel_put(cfd, flowlabel))
133 		error(1, errno, "flowlabel_put");
134 
135 	*client = cfd;
136 	*accepted = afd;
137 }
138 
139 static int bringup_loopback(void)
140 {
141 	struct ifreq ifr = {
142 		.ifr_name = "lo"
143 	};
144 	int fd;
145 
146 	fd = socket(AF_LOCAL, SOCK_STREAM, 0);
147 	if (fd < 0)
148 		return -1;
149 
150 	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
151 		goto err;
152 
153 	ifr.ifr_flags = ifr.ifr_flags | IFF_UP;
154 
155 	if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
156 		goto err;
157 
158 	close(fd);
159 	return 0;
160 
161 err:
162 	close(fd);
163 	return -1;
164 }
165 
166 FIXTURE(flowlabel) {};
167 
168 FIXTURE_SETUP(flowlabel)
169 {
170 	int ret;
171 
172 	ret = unshare(CLONE_NEWNET);
173 	ASSERT_EQ(ret, 0) {
174 		TH_LOG("unshare(CLONE_NEWNET) failed: %s", strerror(errno));
175 	}
176 
177 	ret = bringup_loopback();
178 	ASSERT_EQ(ret, 0) TH_LOG("Failed to bring up loopback interface");
179 }
180 
181 FIXTURE_TEARDOWN(flowlabel)
182 {
183 }
184 
185 TEST_F(flowlabel, cannot_get_non_existent_label)
186 {
187 	int fd, err;
188 
189 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
190 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
191 
192 	err = flowlabel_get(fd, 9, IPV6_FL_S_ANY, 0);
193 	EXPECT_TRUE(err) TH_LOG("expected get of a non-existent label to fail");
194 	EXPECT_EQ(ENOENT, errno) TH_LOG("expected ENOENT, got %d", errno);
195 
196 	EXPECT_EQ(0, close(fd));
197 }
198 
199 TEST_F(flowlabel, cannot_put_non_existent_label)
200 {
201 	int fd, err;
202 
203 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
204 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
205 
206 	err = flowlabel_put(fd, 10);
207 	EXPECT_TRUE(err) TH_LOG("expected put of a non-existent label to fail");
208 	EXPECT_EQ(ESRCH, errno) TH_LOG("expected ESRCH, got %d", errno);
209 
210 	EXPECT_EQ(0, close(fd));
211 }
212 
213 TEST_F(flowlabel, cannot_create_label_greater_than_20_bits)
214 {
215 	int fd, err;
216 
217 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
218 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
219 
220 	err = flowlabel_get(fd, 0x1FFFFF, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
221 	EXPECT_TRUE(err) TH_LOG("expected label > 20 bits to be rejected");
222 	EXPECT_EQ(EINVAL, errno) TH_LOG("expected EINVAL, got %d", errno);
223 
224 	EXPECT_EQ(0, close(fd));
225 }
226 
227 TEST_F(flowlabel, can_create_and_get_and_put_labels)
228 {
229 	int fd, err;
230 
231 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
232 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
233 
234 	err = flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
235 	EXPECT_TRUE(!err) TH_LOG("failed to create label (FL_F_CREATE)");
236 
237 	err = flowlabel_get(fd, 1, IPV6_FL_S_ANY, 0);
238 	EXPECT_TRUE(!err) TH_LOG("failed to get the label without FL_F_CREATE");
239 
240 	err = flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
241 	EXPECT_TRUE(!err)
242 		TH_LOG("failed to get it again with create flag set, too");
243 
244 	err = flowlabel_get(fd, 1, IPV6_FL_S_ANY,
245 			    IPV6_FL_F_CREATE | IPV6_FL_F_EXCL);
246 	EXPECT_TRUE(err)
247 		TH_LOG("expected FL_F_EXCL to reject existing label");
248 	EXPECT_EQ(EEXIST, errno) TH_LOG("expected EEXIST, got %d", errno);
249 
250 	err = flowlabel_put(fd, 1);
251 	EXPECT_TRUE(!err) TH_LOG("failed to put first reference");
252 	err = flowlabel_put(fd, 1);
253 	EXPECT_TRUE(!err) TH_LOG("failed to put second reference");
254 	err = flowlabel_put(fd, 1);
255 	EXPECT_TRUE(!err) TH_LOG("failed to put third reference");
256 	err = flowlabel_put(fd, 1);
257 	EXPECT_TRUE(err)
258 		TH_LOG("expected fourth put to fail, no references left");
259 	EXPECT_EQ(ESRCH, errno) TH_LOG("expected ESRCH, got %d", errno);
260 
261 	EXPECT_EQ(0, close(fd));
262 }
263 
264 TEST_F(flowlabel, exclusive_label_share)
265 {
266 	int fd, err;
267 
268 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
269 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
270 
271 	err = flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
272 	EXPECT_TRUE(!err)
273 		TH_LOG("failed to create a new exclusive label (FL_S_EXCL)");
274 
275 	err = flowlabel_get(fd, 2, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
276 	EXPECT_TRUE(err) TH_LOG("expected reuse in non-exclusive mode to fail");
277 	EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
278 
279 	err = flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
280 	EXPECT_TRUE(err) TH_LOG("expected reuse in exclusive mode to fail too");
281 	EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
282 
283 	err = flowlabel_put(fd, 2);
284 	EXPECT_TRUE(!err) TH_LOG("failed to put the exclusive label");
285 
286 	err = flowlabel_get(fd, 2, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
287 	EXPECT_TRUE(err) TH_LOG("expected reuse to fail, due to linger");
288 	EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
289 
290 	sleep(FL_MIN_LINGER * 2 + 1);
291 
292 	err = flowlabel_get(fd, 2, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
293 	EXPECT_TRUE(!err) TH_LOG("expected reuse to succeed after linger");
294 
295 	EXPECT_EQ(0, close(fd));
296 }
297 
298 TEST_F(flowlabel, user_private_label_share)
299 {
300 	int fd, err, wstatus;
301 	pid_t pid;
302 
303 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
304 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
305 
306 	err = flowlabel_get(fd, 3, IPV6_FL_S_USER, IPV6_FL_F_CREATE);
307 	EXPECT_TRUE(!err)
308 		TH_LOG("failed to create a new user-private label (FL_S_USER)");
309 
310 	err = flowlabel_get(fd, 3, IPV6_FL_S_ANY, 0);
311 	EXPECT_TRUE(err) TH_LOG("expected get in non-exclusive mode to fail");
312 	EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
313 
314 	err = flowlabel_get(fd, 3, IPV6_FL_S_EXCL, 0);
315 	EXPECT_TRUE(err) TH_LOG("expected get in exclusive mode to fail");
316 	EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
317 
318 	err = flowlabel_get(fd, 3, IPV6_FL_S_USER, 0);
319 	EXPECT_TRUE(!err) TH_LOG("failed to get it again in user mode");
320 
321 	pid = fork();
322 	ASSERT_NE(-1, pid) TH_LOG("fork failed");
323 	if (!pid) {
324 		err = flowlabel_get(fd, 3, IPV6_FL_S_USER, 0);
325 		EXPECT_TRUE(!err)
326 			TH_LOG("child failed to get the user-private label");
327 
328 		if (setuid(USHRT_MAX))
329 			exit(KSFT_SKIP);
330 
331 		err = flowlabel_get(fd, 3, IPV6_FL_S_USER, 0);
332 		EXPECT_TRUE(err)
333 			TH_LOG("child unexpectedly got label after setuid");
334 		EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
335 		exit(0);
336 	}
337 	ASSERT_EQ(pid, wait(&wstatus)) TH_LOG("wait failed");
338 	ASSERT_TRUE(WIFEXITED(wstatus)) TH_LOG("child did not exit normally");
339 	if (WEXITSTATUS(wstatus) == KSFT_SKIP)
340 		SKIP(return,
341 		     "setuid(USHRT_MAX) unavailable (no CAP_SETUID or uid unmapped)");
342 	EXPECT_EQ(0, WEXITSTATUS(wstatus))
343 		TH_LOG("child reported unexpected result");
344 
345 	EXPECT_EQ(0, close(fd));
346 }
347 
348 TEST_F(flowlabel, process_private_label_share)
349 {
350 	int fd, err, wstatus;
351 	pid_t pid;
352 
353 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
354 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
355 
356 	err = flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, IPV6_FL_F_CREATE);
357 	EXPECT_TRUE(!err)
358 		TH_LOG("failed to create a new process-private label");
359 
360 	err = flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0);
361 	EXPECT_TRUE(!err) TH_LOG("failed to get it again");
362 
363 	pid = fork();
364 	ASSERT_NE(-1, pid) TH_LOG("fork failed");
365 	if (!pid) {
366 		err = flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0);
367 		EXPECT_TRUE(err)
368 			TH_LOG("child unexpectedly got process-private label");
369 		EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
370 		exit(0);
371 	}
372 	ASSERT_EQ(pid, wait(&wstatus)) TH_LOG("wait failed");
373 	ASSERT_TRUE(WIFEXITED(wstatus)) TH_LOG("child did not exit normally");
374 	EXPECT_EQ(0, WEXITSTATUS(wstatus))
375 		TH_LOG("child reported unexpected result");
376 
377 	EXPECT_EQ(0, close(fd));
378 }
379 
380 TEST_F(flowlabel, cannot_renew_non_existent_label)
381 {
382 	int fd, err;
383 
384 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
385 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
386 
387 	err = flowlabel_renew(fd, 5, IPV6_FL_S_EXCL,
388 			      2 * (FL_MIN_LINGER * 2 + 1));
389 	EXPECT_TRUE(err)
390 		TH_LOG("expected renew of a non-existent label to fail");
391 	EXPECT_EQ(ESRCH, errno) TH_LOG("expected ESRCH, got %d", errno);
392 
393 	EXPECT_EQ(0, close(fd));
394 }
395 
396 TEST_F(flowlabel, can_renew_existing_label)
397 {
398 	int fd, err;
399 
400 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
401 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
402 
403 	err = flowlabel_get(fd, 5, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
404 	EXPECT_TRUE(!err)
405 		TH_LOG("failed to create a new label for renew validation");
406 
407 	err = flowlabel_renew(fd, 5, IPV6_FL_S_EXCL,
408 			      2 * (FL_MIN_LINGER * 2 + 1));
409 	EXPECT_TRUE(!err) TH_LOG("failed to renew an existing valid label");
410 
411 	err = flowlabel_put(fd, 5);
412 	EXPECT_TRUE(!err) TH_LOG("failed to put the label");
413 
414 	EXPECT_EQ(0, close(fd));
415 }
416 
417 TEST_F(flowlabel, renew_label_linger)
418 {
419 	/* RENEW must extend a label's linger period: putting a renewed
420 	 * label and waiting out its original linger time must not be
421 	 * enough to allow the label to be recreated.
422 	 */
423 	int fd, err;
424 
425 	fd = socket(PF_INET6, SOCK_DGRAM, 0);
426 	ASSERT_GE(fd, 0) TH_LOG("socket failed");
427 
428 	err = flowlabel_get(fd, 6, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
429 	EXPECT_TRUE(!err)
430 		TH_LOG("failed to create label with FL_MIN_LINGER linger time");
431 
432 	err = flowlabel_renew(fd, 6, IPV6_FL_S_EXCL,
433 			      2 * (FL_MIN_LINGER * 2 + 1));
434 	EXPECT_TRUE(!err)
435 		TH_LOG("failed to renew the label to increase its linger time");
436 
437 	err = flowlabel_put(fd, 6);
438 	EXPECT_TRUE(!err) TH_LOG("failed to put the label");
439 
440 	sleep(FL_MIN_LINGER * 2 + 1);
441 
442 	err = flowlabel_get(fd, 6, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
443 	EXPECT_TRUE(err)
444 		TH_LOG("expected reuse to fail, new linger time not over yet");
445 	EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
446 
447 	EXPECT_EQ(0, close(fd));
448 }
449 
450 TEST_F(flowlabel, remote_flag)
451 {
452 	/* The REMOTE flag, used for getsockopt, is expected to retrieve the
453 	 * label from the latest received header.
454 	 */
455 	struct in6_flowlabel_req freq = {
456 		.flr_action = IPV6_FL_A_GET,
457 		.flr_flags = IPV6_FL_F_REMOTE,
458 	};
459 	socklen_t freq_len = sizeof(freq);
460 	int listener, cfd, afd, err;
461 
462 	listener = tcp_listen();
463 	tcp_connect(listener, 7, &cfd, &afd);
464 
465 	err = getsockopt(afd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &freq, &freq_len);
466 	EXPECT_TRUE(!err) TH_LOG("getsockopt with IPV6_FL_F_REMOTE failed");
467 	EXPECT_EQ(7, ntohl(freq.flr_label))
468 		TH_LOG("unexpected remote flow label");
469 
470 	EXPECT_EQ(0, close(afd));
471 	EXPECT_EQ(0, close(cfd));
472 	EXPECT_EQ(0, close(listener));
473 }
474 
475 static bool disable_flowlabel_consistency(void)
476 {
477 	int fd;
478 
479 	fd = open("/proc/sys/net/ipv6/flowlabel_consistency", O_WRONLY);
480 	if (fd == -1)
481 		return false;
482 
483 	if (write(fd, "0", 1) != 1) {
484 		close(fd);
485 		return false;
486 	}
487 	close(fd);
488 
489 	return true;
490 }
491 
492 TEST_F(flowlabel, reflect_flag)
493 {
494 	/* The REFLECT flag acts as a trigger to the REPFLOW bit. When REPFLOW
495 	 * is triggered for a socket, it adopts the label received from the
496 	 * connected socket.
497 	 */
498 	struct in6_flowlabel_req reflect_on = {
499 		.flr_action = IPV6_FL_A_GET,
500 		.flr_flags = IPV6_FL_F_REFLECT,
501 	};
502 	struct in6_flowlabel_req reflect_query = {
503 		.flr_action = IPV6_FL_A_GET,
504 	};
505 	struct in6_flowlabel_req reflect_off = {
506 		.flr_action = IPV6_FL_A_PUT,
507 		.flr_flags = IPV6_FL_F_REFLECT,
508 	};
509 	socklen_t reflect_query_len = sizeof(reflect_query);
510 	int listener, cfd, afd, err;
511 
512 	if (!disable_flowlabel_consistency())
513 		SKIP(return,
514 		     "cannot disable net.ipv6.flowlabel_consistency");
515 
516 	listener = tcp_listen();
517 	err = setsockopt(listener, SOL_IPV6, IPV6_FLOWLABEL_MGR,
518 			 &reflect_on, sizeof(reflect_on));
519 	EXPECT_TRUE(!err) TH_LOG("failed to enable REFLECT on the listener");
520 
521 	tcp_connect(listener, 8, &cfd, &afd);
522 
523 	err = getsockopt(afd, SOL_IPV6, IPV6_FLOWLABEL_MGR,
524 			 &reflect_query, &reflect_query_len);
525 	EXPECT_TRUE(!err)
526 		TH_LOG("failed to query the accepted socket's outgoing label");
527 	EXPECT_EQ(8, ntohl(reflect_query.flr_label))
528 		TH_LOG("accepted socket did not reflect client's label");
529 
530 	err = setsockopt(afd, SOL_IPV6, IPV6_FLOWLABEL_MGR,
531 			 &reflect_off, sizeof(reflect_off));
532 	EXPECT_TRUE(!err)
533 		TH_LOG("failed to disable REFLECT on the accepted socket");
534 
535 	err = setsockopt(afd, SOL_IPV6, IPV6_FLOWLABEL_MGR,
536 			 &reflect_off, sizeof(reflect_off));
537 	EXPECT_TRUE(err) TH_LOG("expected disabling REFLECT twice to fail");
538 	EXPECT_EQ(ESRCH, errno) TH_LOG("expected ESRCH, got %d", errno);
539 
540 	EXPECT_EQ(0, close(afd));
541 	EXPECT_EQ(0, close(cfd));
542 	EXPECT_EQ(0, close(listener));
543 }
544 
545 TEST_HARNESS_MAIN
546