xref: /openbsd/regress/sys/net/pf_trans/iocmd-limit.c (revision b6a86f14)
1*b6a86f14Santon /*	$OpenBSD: iocmd-limit.c,v 1.2 2023/07/10 17:45:17 anton Exp $ */
2e8c6dd7bSsashan 
3e8c6dd7bSsashan /*
4e8c6dd7bSsashan  * Copyright (c) 2023 Alexandr Nedvedicky <sashan@openbsd.org>
5e8c6dd7bSsashan  *
6e8c6dd7bSsashan  * Permission to use, copy, modify, and distribute this software for any
7e8c6dd7bSsashan  * purpose with or without fee is hereby granted, provided that the above
8e8c6dd7bSsashan  * copyright notice and this permission notice appear in all copies.
9e8c6dd7bSsashan  *
10e8c6dd7bSsashan  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e8c6dd7bSsashan  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e8c6dd7bSsashan  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e8c6dd7bSsashan  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e8c6dd7bSsashan  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e8c6dd7bSsashan  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e8c6dd7bSsashan  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e8c6dd7bSsashan  */
18e8c6dd7bSsashan 
19e8c6dd7bSsashan #include <sys/types.h>
20e8c6dd7bSsashan #include <sys/ioctl.h>
21e8c6dd7bSsashan #include <sys/socket.h>
22e8c6dd7bSsashan #include <sys/stat.h>
23e8c6dd7bSsashan 
24e8c6dd7bSsashan #include <net/if.h>
25e8c6dd7bSsashan #include <netinet/in.h>
26e8c6dd7bSsashan #include <net/pfvar.h>
27e8c6dd7bSsashan 
28e8c6dd7bSsashan #include <err.h>
29e8c6dd7bSsashan #include <errno.h>
30e8c6dd7bSsashan #include <fcntl.h>
31e8c6dd7bSsashan #include <limits.h>
32e8c6dd7bSsashan #include <string.h>
33e8c6dd7bSsashan #include <unistd.h>
34e8c6dd7bSsashan 
35e8c6dd7bSsashan #include <stdio.h>
36e8c6dd7bSsashan #include <stdlib.h>
37e8c6dd7bSsashan #include <stdint.h>
38e8c6dd7bSsashan 
39e8c6dd7bSsashan #define REGRESS_ANCHOR "regress"
40e8c6dd7bSsashan 
41e8c6dd7bSsashan static void
usage(const char * progname)42e8c6dd7bSsashan usage(const char *progname)
43e8c6dd7bSsashan {
44e8c6dd7bSsashan 	fprintf(stderr,
45e8c6dd7bSsashan 	    "%s -c iocmd [-i iterations ]\n"
46e8c6dd7bSsashan 	    "\t-c iocmd to test, currently DIOCGETRULES "
47e8c6dd7bSsashan 	    "and DIOCXEND are supported\n"
48e8c6dd7bSsashan 	    "\t-i number of iterations is 1 by default\n", progname);
49e8c6dd7bSsashan 	exit(1);
50e8c6dd7bSsashan }
51e8c6dd7bSsashan 
52e8c6dd7bSsashan static int
do_DIOCGETRULES_test(int dev)53e8c6dd7bSsashan do_DIOCGETRULES_test(int dev)
54e8c6dd7bSsashan {
55e8c6dd7bSsashan 	struct pfioc_rule pr;
56e8c6dd7bSsashan 	int rv;
57e8c6dd7bSsashan 
58e8c6dd7bSsashan 	memset(&pr, 0, sizeof(pr));
59e8c6dd7bSsashan 	memcpy(pr.anchor, REGRESS_ANCHOR, sizeof(REGRESS_ANCHOR));
60e8c6dd7bSsashan 	pr.rule.action = PF_PASS;
61e8c6dd7bSsashan 
62e8c6dd7bSsashan 	if ((rv = ioctl(dev, DIOCGETRULES, &pr)) == -1) {
63e8c6dd7bSsashan 		/*
64e8c6dd7bSsashan 		 * we expect to see EBUSY anything else is odd and we should
65e8c6dd7bSsashan 		 * exit right away.
66e8c6dd7bSsashan 		 */
67e8c6dd7bSsashan 		if (errno != EBUSY)
68*b6a86f14Santon 			err(1, "%s DIOCGETRULES", __func__);
69e8c6dd7bSsashan 	}
70e8c6dd7bSsashan 
71e8c6dd7bSsashan 	return (rv);
72e8c6dd7bSsashan }
73e8c6dd7bSsashan 
74e8c6dd7bSsashan static int
result_DIOCGETRULES(unsigned int iterations,unsigned int limit)75e8c6dd7bSsashan result_DIOCGETRULES(unsigned int iterations, unsigned int limit)
76e8c6dd7bSsashan {
77e8c6dd7bSsashan 	int	rv;
78e8c6dd7bSsashan 	/*
79e8c6dd7bSsashan 	 * DIOCGETRULES must see EBUSY before iterations reach limit
80e8c6dd7bSsashan 	 * to conclude test is successful.
81e8c6dd7bSsashan 	 */
82e8c6dd7bSsashan 	rv = (iterations < limit) ? 0 : 1;
83e8c6dd7bSsashan 	if (rv)
84e8c6dd7bSsashan 		printf(
85e8c6dd7bSsashan 		    "DIOCGETRULES could obtain %u tickets, reaching the limit "
86e8c6dd7bSsashan 		    "of %u tickets\n",
87e8c6dd7bSsashan 		    iterations, limit);
88e8c6dd7bSsashan 
89e8c6dd7bSsashan 	return (rv);
90e8c6dd7bSsashan }
91e8c6dd7bSsashan 
92e8c6dd7bSsashan static int
do_DIOCXEND_test(int dev)93e8c6dd7bSsashan do_DIOCXEND_test(int dev)
94e8c6dd7bSsashan {
95e8c6dd7bSsashan 	struct pfioc_rule pr;
96e8c6dd7bSsashan 	int rv;
97e8c6dd7bSsashan 
98e8c6dd7bSsashan 	memset(&pr, 0, sizeof(pr));
99e8c6dd7bSsashan 	memcpy(pr.anchor, REGRESS_ANCHOR, sizeof(REGRESS_ANCHOR));
100e8c6dd7bSsashan 	pr.rule.action = PF_PASS;
101e8c6dd7bSsashan 
102e8c6dd7bSsashan 	if ((rv = ioctl(dev, DIOCGETRULES, &pr)) == -1)
103*b6a86f14Santon 		warn("%s DIOCGETRULES", __func__);
104e8c6dd7bSsashan 	else if ((rv = ioctl(dev, DIOCXEND, &pr.ticket)) == -1)
105*b6a86f14Santon 		warn("%s DIOCXEND", __func__);
106e8c6dd7bSsashan 
107e8c6dd7bSsashan 	return (rv);
108e8c6dd7bSsashan }
109e8c6dd7bSsashan 
110e8c6dd7bSsashan static int
result_DIOCXEND(unsigned int iterations,unsigned int limit)111e8c6dd7bSsashan result_DIOCXEND(unsigned int iterations, unsigned int limit)
112e8c6dd7bSsashan {
113e8c6dd7bSsashan 	int rv;
114e8c6dd7bSsashan 	/*
115e8c6dd7bSsashan 	 * failing to reach limit when also closing tickets
116e8c6dd7bSsashan 	 * using DIOXXEND is an error.
117e8c6dd7bSsashan 	 */
118e8c6dd7bSsashan 	rv = (iterations < limit) ? 1 : 0;
119e8c6dd7bSsashan 	if (rv)
120e8c6dd7bSsashan 		printf(
121e8c6dd7bSsashan 		    "Although test is is using DIOCXEND it still"
122e8c6dd7bSsashan 		    "hits limit (%u)\n", iterations);
123e8c6dd7bSsashan 	return (rv);
124e8c6dd7bSsashan }
125e8c6dd7bSsashan 
126e8c6dd7bSsashan static struct iocmd_test {
127e8c6dd7bSsashan 	const char *iocmd_name;
128e8c6dd7bSsashan 	int (*iocmd_test)(int);
129e8c6dd7bSsashan 	int (*iocmd_result)(unsigned int, unsigned int);
130e8c6dd7bSsashan } iocmd_test_tab[] = {
131e8c6dd7bSsashan 	{ "DIOCGETRULES", do_DIOCGETRULES_test, result_DIOCGETRULES },
132e8c6dd7bSsashan 	{ "DIOCXEND", do_DIOCXEND_test, result_DIOCXEND },
133e8c6dd7bSsashan 	{ NULL, NULL }
134e8c6dd7bSsashan };
135e8c6dd7bSsashan 
136e8c6dd7bSsashan static struct iocmd_test *
parse_iocmd_name(const char * iocmd_name)137e8c6dd7bSsashan parse_iocmd_name(const char *iocmd_name)
138e8c6dd7bSsashan {
139e8c6dd7bSsashan 	int	i = 0;
140e8c6dd7bSsashan 
141e8c6dd7bSsashan 	while (iocmd_test_tab[i].iocmd_name != NULL) {
142e8c6dd7bSsashan 		if (strcasecmp(iocmd_test_tab[i].iocmd_name, iocmd_name) == 0)
143e8c6dd7bSsashan 			break;
144e8c6dd7bSsashan 		i++;
145e8c6dd7bSsashan 	}
146e8c6dd7bSsashan 
147e8c6dd7bSsashan 	return ((iocmd_test_tab[i].iocmd_name == NULL) ?
148e8c6dd7bSsashan 	    NULL : &iocmd_test_tab[i]);
149e8c6dd7bSsashan }
150e8c6dd7bSsashan 
151e8c6dd7bSsashan int
main(int argc,char * const argv[])152e8c6dd7bSsashan main(int argc, char *const argv[])
153e8c6dd7bSsashan {
154e8c6dd7bSsashan 	const char *errstr = NULL;
155e8c6dd7bSsashan 	unsigned int iterations = 1;
156e8c6dd7bSsashan 	unsigned int i = 0;
157e8c6dd7bSsashan 	int dev;
158e8c6dd7bSsashan 	int c;
159e8c6dd7bSsashan 	struct iocmd_test *test_iocmd = NULL;
160e8c6dd7bSsashan 
161e8c6dd7bSsashan 	while ((c = getopt(argc, argv, "i:c:")) != -1) {
162e8c6dd7bSsashan 		switch (c) {
163e8c6dd7bSsashan 		case 'i':
164e8c6dd7bSsashan 			iterations = strtonum(optarg, 1, UINT32_MAX, &errstr);
165e8c6dd7bSsashan 			if (errstr != NULL) {
166e8c6dd7bSsashan 				fprintf(stderr,
167e8c6dd7bSsashan 				    "%s: number of iteration (-i %s) "
168e8c6dd7bSsashan 				    "is invalid: %s\n",
169e8c6dd7bSsashan 				    argv[0], optarg, errstr);
170e8c6dd7bSsashan 				usage(argv[0]);
171e8c6dd7bSsashan 			}
172e8c6dd7bSsashan 			break;
173e8c6dd7bSsashan 		case 'c':
174e8c6dd7bSsashan 			test_iocmd = parse_iocmd_name(optarg);
175e8c6dd7bSsashan 			if (test_iocmd == NULL) {
176e8c6dd7bSsashan 				fprintf(stderr, "%s invalid iocmd: %s\n",
177e8c6dd7bSsashan 				    argv[0], optarg);
178e8c6dd7bSsashan 				usage(argv[0]);
179e8c6dd7bSsashan 			}
180e8c6dd7bSsashan 			break;
181e8c6dd7bSsashan 		default:
182e8c6dd7bSsashan 			usage(argv[0]);
183e8c6dd7bSsashan 		}
184e8c6dd7bSsashan 	}
185e8c6dd7bSsashan 
186e8c6dd7bSsashan 	if (test_iocmd == NULL) {
187e8c6dd7bSsashan 		fprintf(stderr, "%s -c option is required\n", argv[0]);
188e8c6dd7bSsashan 		usage(argv[0]);
189e8c6dd7bSsashan 	}
190e8c6dd7bSsashan 
191e8c6dd7bSsashan 	dev = open("/dev/pf", O_RDONLY);
192e8c6dd7bSsashan 	if (dev < 0)
193*b6a86f14Santon 		err(1, "open(\"dev/pf\")");
194e8c6dd7bSsashan 
195e8c6dd7bSsashan 	while (i < iterations) {
196e8c6dd7bSsashan 		if (test_iocmd->iocmd_test(dev) != 0)
197e8c6dd7bSsashan 			break;
198e8c6dd7bSsashan 		i++;
199e8c6dd7bSsashan 	}
200e8c6dd7bSsashan 
201e8c6dd7bSsashan 	return (test_iocmd->iocmd_result(i, iterations));
202e8c6dd7bSsashan }
203