brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · af95b48 Raw
200 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Test IPV6_FLOWINFO_MGR */3 4#define _GNU_SOURCE5 6#include <arpa/inet.h>7#include <error.h>8#include <errno.h>9#include <limits.h>10#include <linux/in6.h>11#include <stdbool.h>12#include <stdio.h>13#include <stdint.h>14#include <stdlib.h>15#include <string.h>16#include <sys/socket.h>17#include <sys/stat.h>18#include <sys/time.h>19#include <sys/types.h>20#include <sys/wait.h>21#include <unistd.h>22 23/* uapi/glibc weirdness may leave this undefined */24#ifndef IPV6_FLOWLABEL_MGR25#define IPV6_FLOWLABEL_MGR	3226#endif27 28/* from net/ipv6/ip6_flowlabel.c */29#define FL_MIN_LINGER		630 31#define explain(x)							\32	do { if (cfg_verbose) fprintf(stderr, "       " x "\n"); } while (0)33 34#define __expect(x)							\35	do {								\36		if (!(x))						\37			fprintf(stderr, "[OK]   " #x "\n");		\38		else							\39			error(1, 0, "[ERR]  " #x " (line %d)", __LINE__); \40	} while (0)41 42#define expect_pass(x)	__expect(x)43#define expect_fail(x)	__expect(!(x))44 45static bool cfg_long_running;46static bool cfg_verbose;47 48static int flowlabel_get(int fd, uint32_t label, uint8_t share, uint16_t flags)49{50	struct in6_flowlabel_req req = {51		.flr_action = IPV6_FL_A_GET,52		.flr_label = htonl(label),53		.flr_flags = flags,54		.flr_share = share,55	};56 57	/* do not pass IPV6_ADDR_ANY or IPV6_ADDR_MAPPED */58	req.flr_dst.s6_addr[0] = 0xfd;59	req.flr_dst.s6_addr[15] = 0x1;60 61	return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));62}63 64static int flowlabel_put(int fd, uint32_t label)65{66	struct in6_flowlabel_req req = {67		.flr_action = IPV6_FL_A_PUT,68		.flr_label = htonl(label),69	};70 71	return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));72}73 74static void run_tests(int fd)75{76	int wstatus;77	pid_t pid;78 79	explain("cannot get non-existent label");80	expect_fail(flowlabel_get(fd, 1, IPV6_FL_S_ANY, 0));81 82	explain("cannot put non-existent label");83	expect_fail(flowlabel_put(fd, 1));84 85	explain("cannot create label greater than 20 bits");86	expect_fail(flowlabel_get(fd, 0x1FFFFF, IPV6_FL_S_ANY,87				  IPV6_FL_F_CREATE));88 89	explain("create a new label (FL_F_CREATE)");90	expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));91	explain("can get the label (without FL_F_CREATE)");92	expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, 0));93	explain("can get it again with create flag set, too");94	expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));95	explain("cannot get it again with the exclusive (FL_FL_EXCL) flag");96	expect_fail(flowlabel_get(fd, 1, IPV6_FL_S_ANY,97					 IPV6_FL_F_CREATE | IPV6_FL_F_EXCL));98	explain("can now put exactly three references");99	expect_pass(flowlabel_put(fd, 1));100	expect_pass(flowlabel_put(fd, 1));101	expect_pass(flowlabel_put(fd, 1));102	expect_fail(flowlabel_put(fd, 1));103 104	explain("create a new exclusive label (FL_S_EXCL)");105	expect_pass(flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE));106	explain("cannot get it again in non-exclusive mode");107	expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_ANY,  IPV6_FL_F_CREATE));108	explain("cannot get it again in exclusive mode either");109	expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE));110	expect_pass(flowlabel_put(fd, 2));111 112	if (cfg_long_running) {113		explain("cannot reuse the label, due to linger");114		expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_ANY,115					  IPV6_FL_F_CREATE));116		explain("after sleep, can reuse");117		sleep(FL_MIN_LINGER * 2 + 1);118		expect_pass(flowlabel_get(fd, 2, IPV6_FL_S_ANY,119					  IPV6_FL_F_CREATE));120	}121 122	explain("create a new user-private label (FL_S_USER)");123	expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, IPV6_FL_F_CREATE));124	explain("cannot get it again in non-exclusive mode");125	expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_ANY, 0));126	explain("cannot get it again in exclusive mode");127	expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_EXCL, 0));128	explain("can get it again in user mode");129	expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));130	explain("child process can get it too, but not after setuid(nobody)");131	pid = fork();132	if (pid == -1)133		error(1, errno, "fork");134	if (!pid) {135		expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));136		if (setuid(USHRT_MAX))137			fprintf(stderr, "[INFO] skip setuid child test\n");138		else139			expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));140		exit(0);141	}142	if (wait(&wstatus) == -1)143		error(1, errno, "wait");144	if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)145		error(1, errno, "wait: unexpected child result");146 147	explain("create a new process-private label (FL_S_PROCESS)");148	expect_pass(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, IPV6_FL_F_CREATE));149	explain("can get it again");150	expect_pass(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0));151	explain("child process cannot can get it");152	pid = fork();153	if (pid == -1)154		error(1, errno, "fork");155	if (!pid) {156		expect_fail(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0));157		exit(0);158	}159	if (wait(&wstatus) == -1)160		error(1, errno, "wait");161	if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)162		error(1, errno, "wait: unexpected child result");163}164 165static void parse_opts(int argc, char **argv)166{167	int c;168 169	while ((c = getopt(argc, argv, "lv")) != -1) {170		switch (c) {171		case 'l':172			cfg_long_running = true;173			break;174		case 'v':175			cfg_verbose = true;176			break;177		default:178			error(1, 0, "%s: parse error", argv[0]);179		}180	}181}182 183int main(int argc, char **argv)184{185	int fd;186 187	parse_opts(argc, argv);188 189	fd = socket(PF_INET6, SOCK_DGRAM, 0);190	if (fd == -1)191		error(1, errno, "socket");192 193	run_tests(fd);194 195	if (close(fd))196		error(1, errno, "close");197 198	return 0;199}200