]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/pfctl/tests/pfctl_test.c
[pfctl_tests] Add missing void to empty function declaration
[FreeBSD/FreeBSD.git] / sbin / pfctl / tests / pfctl_test.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright 2020 Alex Richardson <arichardson@FreeBSD.org>
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory (Department of Computer Science and
8  * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
9  * DARPA SSITH research programme.
10  *
11  * This work was supported by Innovate UK project 105694, "Digital Security by
12  * Design (DSbD) Technology Platform Prototype".
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are met:
16  * 1. Redistributions of source code must retain the above copyright notice,
17  *    this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
23  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdbool.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <spawn.h>
45 #include <sys/module.h>
46 #include <sys/sbuf.h>
47 #include <sys/stat.h>
48 #include <sys/wait.h>
49
50 #include <atf-c.h>
51
52 /*
53  * Tests 0001-0999 are copied from OpenBSD's regress/sbin/pfctl.
54  * Tests 1001-1999 are ours (FreeBSD's own).
55  *
56  * pf: Run pfctl -nv on pfNNNN.in and check that the output matches pfNNNN.ok.
57  *     Copied from OpenBSD.  Main differences are some things not working
58  *     in FreeBSD:
59  *         * The action 'match'
60  *         * The command 'set reassemble'
61  *         * The 'from'/'to' options together with 'route-to'
62  *         * The option 'scrub' (it is an action in FreeBSD)
63  *         * Accepting undefined routing tables in actions (??: see pf0093.in)
64  *         * The 'route' option
65  *         * The 'set queue def' option
66  * selfpf: Feed pfctl output through pfctl again and verify it stays the same.
67  *         Copied from OpenBSD.
68  */
69
70 static bool
71 check_pf_module_available(void)
72 {
73         int modid;
74         struct module_stat stat;
75
76         if ((modid = modfind("pf")) < 0) {
77                 warn("pf module not found");
78                 return false;
79         }
80         stat.version = sizeof(struct module_stat);
81         if (modstat(modid, &stat) < 0) {
82                 warn("can't stat pf module id %d", modid);
83                 return false;
84         }
85         return (true);
86 }
87
88 extern char **environ;
89
90 static struct sbuf *
91 read_fd(int fd, size_t sizehint)
92 {
93         struct sbuf *sb;
94         ssize_t count;
95         char buffer[MAXBSIZE];
96
97         sb = sbuf_new(NULL, NULL, sizehint, SBUF_AUTOEXTEND);
98         errno = 0;
99         while ((count = read(fd, buffer, sizeof(buffer) - 1)) > 0) {
100                 sbuf_bcat(sb, buffer, count);
101         }
102         ATF_REQUIRE_ERRNO(0, count == 0 && "Should have reached EOF");
103         sbuf_finish(sb); /* Ensure NULL-termination */
104         return (sb);
105 }
106
107 static struct sbuf *
108 read_file(const char *filename)
109 {
110         struct stat s;
111         struct sbuf *result;
112         int fd;
113
114         errno = 0;
115         ATF_REQUIRE_EQ_MSG(stat(filename, &s), 0, "cannot stat %s", filename);
116         fd = open(filename, O_RDONLY);
117         ATF_REQUIRE_ERRNO(0, fd > 0);
118         result = read_fd(fd, s.st_size);
119         ATF_REQUIRE_ERRNO(0, close(fd) == 0);
120         return (result);
121 }
122
123 static void
124 run_pfctl_test(const char *input_path, const char *expected_path,
125     const atf_tc_t *tc)
126 {
127         int status;
128         pid_t pid;
129         int pipefds[2];
130         char input_files_path[PATH_MAX];
131         struct sbuf *expected_output;
132         struct sbuf *real_output;
133         posix_spawn_file_actions_t action;
134
135         if (!check_pf_module_available())
136                 atf_tc_skip("pf(4) is not loaded");
137
138         /* The test inputs need to be able to use relative includes. */
139         snprintf(input_files_path, sizeof(input_files_path), "%s/files",
140             atf_tc_get_config_var(tc, "srcdir"));
141         ATF_REQUIRE_ERRNO(0, chdir(input_files_path) == 0);
142
143         ATF_REQUIRE_ERRNO(0, pipe(pipefds) == 0);
144         expected_output = read_file(expected_path);
145
146         posix_spawn_file_actions_init(&action);
147         posix_spawn_file_actions_addclose(&action, STDIN_FILENO);
148         posix_spawn_file_actions_addclose(&action, pipefds[1]);
149         posix_spawn_file_actions_adddup2(&action, pipefds[0], STDOUT_FILENO);
150         posix_spawn_file_actions_adddup2(&action, pipefds[0], STDERR_FILENO);
151
152         const char *argv[] = { "pfctl", "-o", "none", "-nvf", input_path,
153                 NULL };
154         printf("Running %s %s %s %s %s\n", argv[0], argv[1], argv[2], argv[3],
155             argv[4]);
156         status = posix_spawnp(
157             &pid, "pfctl", &action, NULL, __DECONST(char **, argv), environ);
158         ATF_REQUIRE_EQ_MSG(
159             status, 0, "posix_spawn failed: %s", strerror(errno));
160         posix_spawn_file_actions_destroy(&action);
161         close(pipefds[0]);
162
163         real_output = read_fd(pipefds[1], 0);
164         printf("---\n%s---\n", sbuf_data(real_output));
165         ATF_REQUIRE_EQ(waitpid(pid, &status, 0), pid);
166         ATF_REQUIRE_MSG(WIFEXITED(status),
167             "pfctl returned non-zero! Output:\n %s", sbuf_data(real_output));
168
169         ATF_CHECK_STREQ(sbuf_data(expected_output), sbuf_data(real_output));
170         sbuf_delete(expected_output);
171         sbuf_delete(real_output);
172         close(pipefds[1]);
173 }
174
175 static void
176 do_pf_test(const char *number, const atf_tc_t *tc)
177 {
178         char *input_path;
179         char *expected_path;
180         asprintf(&input_path, "%s/files/pf%s.in",
181             atf_tc_get_config_var(tc, "srcdir"), number);
182         asprintf(&expected_path, "%s/files/pf%s.ok",
183             atf_tc_get_config_var(tc, "srcdir"), number);
184         run_pfctl_test(input_path, expected_path, tc);
185         free(input_path);
186         free(expected_path);
187 }
188
189 static void
190 do_selfpf_test(const char *number, const atf_tc_t *tc)
191 {
192         char *expected_path;
193         asprintf(&expected_path, "%s/files/pf%s.ok",
194             atf_tc_get_config_var(tc, "srcdir"), number);
195         run_pfctl_test(expected_path, expected_path, tc);
196         free(expected_path);
197 }
198
199 #define PFCTL_TEST(number, descr)                               \
200         ATF_TC(pf##number);                                     \
201         ATF_TC_HEAD(pf##number, tc)                             \
202         {                                                       \
203                 atf_tc_set_md_var(tc, "descr", descr);          \
204         }                                                       \
205         ATF_TC_BODY(pf##number, tc)                             \
206         {                                                       \
207                 do_pf_test(#number, tc);                        \
208         }                                                       \
209         ATF_TC(selfpf##number);                                 \
210         ATF_TC_HEAD(selfpf##number, tc)                         \
211         {                                                       \
212                 atf_tc_set_md_var(tc, "descr", "Self " descr);  \
213         }                                                       \
214         ATF_TC_BODY(selfpf##number, tc)                         \
215         {                                                       \
216                 do_selfpf_test(#number, tc);                    \
217         }
218 #include "pfctl_test_list.inc"
219 #undef PFCTL_TEST
220
221 ATF_TP_ADD_TCS(tp)
222 {
223 #define PFCTL_TEST(number, descr)               \
224         ATF_TP_ADD_TC(tp, pf##number);          \
225         ATF_TP_ADD_TC(tp, selfpf##number);
226 #include "pfctl_test_list.inc"
227 #undef PFCTL_TEST
228
229         return atf_no_error();
230 }