144ec023cSAlex Richardson /*- 244ec023cSAlex Richardson * SPDX-License-Identifier: BSD-2-Clause 344ec023cSAlex Richardson * 444ec023cSAlex Richardson * Copyright 2020 Alex Richardson <arichardson@FreeBSD.org> 544ec023cSAlex Richardson * 644ec023cSAlex Richardson * This software was developed by SRI International and the University of 744ec023cSAlex Richardson * Cambridge Computer Laboratory (Department of Computer Science and 844ec023cSAlex Richardson * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the 944ec023cSAlex Richardson * DARPA SSITH research programme. 1044ec023cSAlex Richardson * 1144ec023cSAlex Richardson * This work was supported by Innovate UK project 105694, "Digital Security by 1244ec023cSAlex Richardson * Design (DSbD) Technology Platform Prototype". 1344ec023cSAlex Richardson * 1444ec023cSAlex Richardson * Redistribution and use in source and binary forms, with or without 1544ec023cSAlex Richardson * modification, are permitted provided that the following conditions are met: 1644ec023cSAlex Richardson * 1. Redistributions of source code must retain the above copyright notice, 1744ec023cSAlex Richardson * this list of conditions and the following disclaimer. 1844ec023cSAlex Richardson * 2. Redistributions in binary form must reproduce the above copyright notice, 1944ec023cSAlex Richardson * this list of conditions and the following disclaimer in the documentation 2044ec023cSAlex Richardson * and/or other materials provided with the distribution. 2144ec023cSAlex Richardson * 2244ec023cSAlex Richardson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 2344ec023cSAlex Richardson * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2444ec023cSAlex Richardson * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2544ec023cSAlex Richardson * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY 2644ec023cSAlex Richardson * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2744ec023cSAlex Richardson * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2844ec023cSAlex Richardson * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2944ec023cSAlex Richardson * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3044ec023cSAlex Richardson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3144ec023cSAlex Richardson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3244ec023cSAlex Richardson */ 3344ec023cSAlex Richardson #include <sys/cdefs.h> 3444ec023cSAlex Richardson __FBSDID("$FreeBSD$"); 3544ec023cSAlex Richardson 3644ec023cSAlex Richardson #include <sys/types.h> 3744ec023cSAlex Richardson #include <sys/param.h> 3844ec023cSAlex Richardson #include <err.h> 3944ec023cSAlex Richardson #include <errno.h> 4044ec023cSAlex Richardson #include <fcntl.h> 4144ec023cSAlex Richardson #include <stdbool.h> 4244ec023cSAlex Richardson #include <stdio.h> 4344ec023cSAlex Richardson #include <stdlib.h> 4444ec023cSAlex Richardson #include <spawn.h> 4544ec023cSAlex Richardson #include <sys/module.h> 4644ec023cSAlex Richardson #include <sys/sbuf.h> 4744ec023cSAlex Richardson #include <sys/stat.h> 4844ec023cSAlex Richardson #include <sys/wait.h> 4944ec023cSAlex Richardson 5044ec023cSAlex Richardson #include <atf-c.h> 5144ec023cSAlex Richardson 5244ec023cSAlex Richardson /* 5344ec023cSAlex Richardson * Tests 0001-0999 are copied from OpenBSD's regress/sbin/pfctl. 5444ec023cSAlex Richardson * Tests 1001-1999 are ours (FreeBSD's own). 5544ec023cSAlex Richardson * 5644ec023cSAlex Richardson * pf: Run pfctl -nv on pfNNNN.in and check that the output matches pfNNNN.ok. 5744ec023cSAlex Richardson * Copied from OpenBSD. Main differences are some things not working 5844ec023cSAlex Richardson * in FreeBSD: 5944ec023cSAlex Richardson * * The action 'match' 6044ec023cSAlex Richardson * * The command 'set reassemble' 6144ec023cSAlex Richardson * * The 'from'/'to' options together with 'route-to' 6244ec023cSAlex Richardson * * The option 'scrub' (it is an action in FreeBSD) 6344ec023cSAlex Richardson * * Accepting undefined routing tables in actions (??: see pf0093.in) 6444ec023cSAlex Richardson * * The 'route' option 6544ec023cSAlex Richardson * * The 'set queue def' option 6644ec023cSAlex Richardson * selfpf: Feed pfctl output through pfctl again and verify it stays the same. 6744ec023cSAlex Richardson * Copied from OpenBSD. 6844ec023cSAlex Richardson */ 6944ec023cSAlex Richardson 7044ec023cSAlex Richardson static bool 71*d80b9f8dSAdrian Chadd check_pf_module_available(void) 7244ec023cSAlex Richardson { 7344ec023cSAlex Richardson int modid; 7444ec023cSAlex Richardson struct module_stat stat; 7544ec023cSAlex Richardson 7644ec023cSAlex Richardson if ((modid = modfind("pf")) < 0) { 7744ec023cSAlex Richardson warn("pf module not found"); 7844ec023cSAlex Richardson return false; 7944ec023cSAlex Richardson } 8044ec023cSAlex Richardson stat.version = sizeof(struct module_stat); 8144ec023cSAlex Richardson if (modstat(modid, &stat) < 0) { 8244ec023cSAlex Richardson warn("can't stat pf module id %d", modid); 8344ec023cSAlex Richardson return false; 8444ec023cSAlex Richardson } 8544ec023cSAlex Richardson return (true); 8644ec023cSAlex Richardson } 8744ec023cSAlex Richardson 8844ec023cSAlex Richardson extern char **environ; 8944ec023cSAlex Richardson 9044ec023cSAlex Richardson static struct sbuf * 9144ec023cSAlex Richardson read_fd(int fd, size_t sizehint) 9244ec023cSAlex Richardson { 9344ec023cSAlex Richardson struct sbuf *sb; 9444ec023cSAlex Richardson ssize_t count; 9544ec023cSAlex Richardson char buffer[MAXBSIZE]; 9644ec023cSAlex Richardson 9744ec023cSAlex Richardson sb = sbuf_new(NULL, NULL, sizehint, SBUF_AUTOEXTEND); 9844ec023cSAlex Richardson errno = 0; 9944ec023cSAlex Richardson while ((count = read(fd, buffer, sizeof(buffer) - 1)) > 0) { 10044ec023cSAlex Richardson sbuf_bcat(sb, buffer, count); 10144ec023cSAlex Richardson } 10244ec023cSAlex Richardson ATF_REQUIRE_ERRNO(0, count == 0 && "Should have reached EOF"); 10344ec023cSAlex Richardson sbuf_finish(sb); /* Ensure NULL-termination */ 10444ec023cSAlex Richardson return (sb); 10544ec023cSAlex Richardson } 10644ec023cSAlex Richardson 10744ec023cSAlex Richardson static struct sbuf * 10844ec023cSAlex Richardson read_file(const char *filename) 10944ec023cSAlex Richardson { 11044ec023cSAlex Richardson struct stat s; 11144ec023cSAlex Richardson struct sbuf *result; 11244ec023cSAlex Richardson int fd; 11344ec023cSAlex Richardson 11444ec023cSAlex Richardson errno = 0; 11544ec023cSAlex Richardson ATF_REQUIRE_EQ_MSG(stat(filename, &s), 0, "cannot stat %s", filename); 11644ec023cSAlex Richardson fd = open(filename, O_RDONLY); 11744ec023cSAlex Richardson ATF_REQUIRE_ERRNO(0, fd > 0); 11844ec023cSAlex Richardson result = read_fd(fd, s.st_size); 11944ec023cSAlex Richardson ATF_REQUIRE_ERRNO(0, close(fd) == 0); 12044ec023cSAlex Richardson return (result); 12144ec023cSAlex Richardson } 12244ec023cSAlex Richardson 12344ec023cSAlex Richardson static void 12444ec023cSAlex Richardson run_pfctl_test(const char *input_path, const char *expected_path, 12544ec023cSAlex Richardson const atf_tc_t *tc) 12644ec023cSAlex Richardson { 12744ec023cSAlex Richardson int status; 12844ec023cSAlex Richardson pid_t pid; 12944ec023cSAlex Richardson int pipefds[2]; 13044ec023cSAlex Richardson char input_files_path[PATH_MAX]; 13144ec023cSAlex Richardson struct sbuf *expected_output; 13244ec023cSAlex Richardson struct sbuf *real_output; 13344ec023cSAlex Richardson posix_spawn_file_actions_t action; 13444ec023cSAlex Richardson 13544ec023cSAlex Richardson if (!check_pf_module_available()) 13644ec023cSAlex Richardson atf_tc_skip("pf(4) is not loaded"); 13744ec023cSAlex Richardson 13844ec023cSAlex Richardson /* The test inputs need to be able to use relative includes. */ 13944ec023cSAlex Richardson snprintf(input_files_path, sizeof(input_files_path), "%s/files", 14044ec023cSAlex Richardson atf_tc_get_config_var(tc, "srcdir")); 14144ec023cSAlex Richardson ATF_REQUIRE_ERRNO(0, chdir(input_files_path) == 0); 14244ec023cSAlex Richardson 14344ec023cSAlex Richardson ATF_REQUIRE_ERRNO(0, pipe(pipefds) == 0); 14444ec023cSAlex Richardson expected_output = read_file(expected_path); 14544ec023cSAlex Richardson 14644ec023cSAlex Richardson posix_spawn_file_actions_init(&action); 14744ec023cSAlex Richardson posix_spawn_file_actions_addclose(&action, STDIN_FILENO); 14844ec023cSAlex Richardson posix_spawn_file_actions_addclose(&action, pipefds[1]); 14944ec023cSAlex Richardson posix_spawn_file_actions_adddup2(&action, pipefds[0], STDOUT_FILENO); 15044ec023cSAlex Richardson posix_spawn_file_actions_adddup2(&action, pipefds[0], STDERR_FILENO); 15144ec023cSAlex Richardson 15244ec023cSAlex Richardson const char *argv[] = { "pfctl", "-o", "none", "-nvf", input_path, 15344ec023cSAlex Richardson NULL }; 15444ec023cSAlex Richardson printf("Running %s %s %s %s %s\n", argv[0], argv[1], argv[2], argv[3], 15544ec023cSAlex Richardson argv[4]); 15644ec023cSAlex Richardson status = posix_spawnp( 15744ec023cSAlex Richardson &pid, "pfctl", &action, NULL, __DECONST(char **, argv), environ); 15844ec023cSAlex Richardson ATF_REQUIRE_EQ_MSG( 15944ec023cSAlex Richardson status, 0, "posix_spawn failed: %s", strerror(errno)); 16044ec023cSAlex Richardson posix_spawn_file_actions_destroy(&action); 16144ec023cSAlex Richardson close(pipefds[0]); 16244ec023cSAlex Richardson 16344ec023cSAlex Richardson real_output = read_fd(pipefds[1], 0); 16444ec023cSAlex Richardson printf("---\n%s---\n", sbuf_data(real_output)); 16544ec023cSAlex Richardson ATF_REQUIRE_EQ(waitpid(pid, &status, 0), pid); 16644ec023cSAlex Richardson ATF_REQUIRE_MSG(WIFEXITED(status), 16744ec023cSAlex Richardson "pfctl returned non-zero! Output:\n %s", sbuf_data(real_output)); 16844ec023cSAlex Richardson 16944ec023cSAlex Richardson ATF_CHECK_STREQ(sbuf_data(expected_output), sbuf_data(real_output)); 17044ec023cSAlex Richardson sbuf_delete(expected_output); 17144ec023cSAlex Richardson sbuf_delete(real_output); 17244ec023cSAlex Richardson close(pipefds[1]); 17344ec023cSAlex Richardson } 17444ec023cSAlex Richardson 17544ec023cSAlex Richardson static void 17644ec023cSAlex Richardson do_pf_test(const char *number, const atf_tc_t *tc) 17744ec023cSAlex Richardson { 17844ec023cSAlex Richardson char *input_path; 17944ec023cSAlex Richardson char *expected_path; 18044ec023cSAlex Richardson asprintf(&input_path, "%s/files/pf%s.in", 18144ec023cSAlex Richardson atf_tc_get_config_var(tc, "srcdir"), number); 18244ec023cSAlex Richardson asprintf(&expected_path, "%s/files/pf%s.ok", 18344ec023cSAlex Richardson atf_tc_get_config_var(tc, "srcdir"), number); 18444ec023cSAlex Richardson run_pfctl_test(input_path, expected_path, tc); 18544ec023cSAlex Richardson free(input_path); 18644ec023cSAlex Richardson free(expected_path); 18744ec023cSAlex Richardson } 18844ec023cSAlex Richardson 18944ec023cSAlex Richardson static void 19044ec023cSAlex Richardson do_selfpf_test(const char *number, const atf_tc_t *tc) 19144ec023cSAlex Richardson { 19244ec023cSAlex Richardson char *expected_path; 19344ec023cSAlex Richardson asprintf(&expected_path, "%s/files/pf%s.ok", 19444ec023cSAlex Richardson atf_tc_get_config_var(tc, "srcdir"), number); 19544ec023cSAlex Richardson run_pfctl_test(expected_path, expected_path, tc); 19644ec023cSAlex Richardson free(expected_path); 19744ec023cSAlex Richardson } 19844ec023cSAlex Richardson 19944ec023cSAlex Richardson #define PFCTL_TEST(number, descr) \ 20044ec023cSAlex Richardson ATF_TC(pf##number); \ 20144ec023cSAlex Richardson ATF_TC_HEAD(pf##number, tc) \ 20244ec023cSAlex Richardson { \ 20344ec023cSAlex Richardson atf_tc_set_md_var(tc, "descr", descr); \ 20444ec023cSAlex Richardson } \ 20544ec023cSAlex Richardson ATF_TC_BODY(pf##number, tc) \ 20644ec023cSAlex Richardson { \ 20744ec023cSAlex Richardson do_pf_test(#number, tc); \ 20844ec023cSAlex Richardson } \ 20944ec023cSAlex Richardson ATF_TC(selfpf##number); \ 21044ec023cSAlex Richardson ATF_TC_HEAD(selfpf##number, tc) \ 21144ec023cSAlex Richardson { \ 21244ec023cSAlex Richardson atf_tc_set_md_var(tc, "descr", "Self " descr); \ 21344ec023cSAlex Richardson } \ 21444ec023cSAlex Richardson ATF_TC_BODY(selfpf##number, tc) \ 21544ec023cSAlex Richardson { \ 21644ec023cSAlex Richardson do_selfpf_test(#number, tc); \ 21744ec023cSAlex Richardson } 21844ec023cSAlex Richardson #include "pfctl_test_list.inc" 21944ec023cSAlex Richardson #undef PFCTL_TEST 22044ec023cSAlex Richardson 22144ec023cSAlex Richardson ATF_TP_ADD_TCS(tp) 22244ec023cSAlex Richardson { 22344ec023cSAlex Richardson #define PFCTL_TEST(number, descr) \ 22444ec023cSAlex Richardson ATF_TP_ADD_TC(tp, pf##number); \ 22544ec023cSAlex Richardson ATF_TP_ADD_TC(tp, selfpf##number); 22644ec023cSAlex Richardson #include "pfctl_test_list.inc" 22744ec023cSAlex Richardson #undef PFCTL_TEST 22844ec023cSAlex Richardson 22944ec023cSAlex Richardson return atf_no_error(); 23044ec023cSAlex Richardson } 231