diff options
author | Alexandr Nedvedicky <sashan@cvs.openbsd.org> | 2021-11-11 12:49:54 +0000 |
---|---|---|
committer | Alexandr Nedvedicky <sashan@cvs.openbsd.org> | 2021-11-11 12:49:54 +0000 |
commit | 7f919c68db9a7c1b020686cf2821b554a0f077c6 (patch) | |
tree | fc2798acb14a131341057a7770829e1210e359ad /regress | |
parent | 72e2e2b10d9bc6b6ae0cb8468c3d4f7d2c90e544 (diff) |
add tests to cover DIOCCHANGERULE ioctl(2)
OK bluhm@
Diffstat (limited to 'regress')
-rw-r--r-- | regress/sbin/pfctl/Makefile | 44 | ||||
-rw-r--r-- | regress/sbin/pfctl/changerule-after.ok | 8 | ||||
-rw-r--r-- | regress/sbin/pfctl/changerule-before.ok | 7 | ||||
-rw-r--r-- | regress/sbin/pfctl/changerule-head.ok | 6 | ||||
-rw-r--r-- | regress/sbin/pfctl/changerule-tail.ok | 6 | ||||
-rw-r--r-- | regress/sbin/pfctl/changerule.c | 221 |
6 files changed, 291 insertions, 1 deletions
diff --git a/regress/sbin/pfctl/Makefile b/regress/sbin/pfctl/Makefile index 61816a858f8..20e1f095226 100644 --- a/regress/sbin/pfctl/Makefile +++ b/regress/sbin/pfctl/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.233 2021/10/25 14:56:47 sashan Exp $ +# $OpenBSD: Makefile,v 1.234 2021/11/11 12:49:53 sashan Exp $ # TARGETS # pf: feed pfNN.in through pfctl and check whether the output matches pfNN.ok @@ -12,6 +12,7 @@ # pfopt: as target pf, but supply extra command line options # pfcmd: test pfctl command line parsing # pfloadanchors: load anchor from nested files +# pf-changerule: covers DIOCCHANGERULE ioctl(2) PFTESTS=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 PFTESTS+=28 29 30 31 32 34 35 36 38 39 40 41 44 46 47 48 49 50 @@ -36,6 +37,20 @@ PFLOADANCHORS=112 113 PFCTL ?= /sbin/pfctl +.PATH: ${.CURDIR}/../../../sbin/pfctl ${.CURDIR}/../../../sys/net + +PROG= changerule +SRCS= changerule.c parse.y pfctl_parser.c pf_print_state.c +SRCS+= pfctl.c pfctl_osfp.c pfctl_radix.c pfctl_table.c +SRCS+= pfctl_optimize.c pf_ruleset.c pfctl_queue.c +CFLAGS= -Wall -Wmissing-prototypes -Wno-uninitialized -Wstrict-prototypes +CFLAGS+= -Wno-unused-variable +CFLAGS+= -I${.CURDIR}/../../../sbin/pfctl -DREGRESS_NOMAIN +YFLAGS= + +LDADD+= -lm +DPADD+= ${LIBM} + MAKEOBJDIRPREFIX= SHELL=/bin/sh @@ -106,6 +121,7 @@ selfpf: ${SELFPF_TARGETS} pf-update: ${PF_UPDATES} REGRESS_TARGETS+=pf-include-setup pf REGRESS_TARGETS+=selfpf +REGRESS_TARGETS+=pf-changerule UPDATE_TARGETS+=pf-update pf-include-setup: @@ -362,6 +378,32 @@ pf-loadanchors-setup: [ -f ${.OBJDIR}/$f ] || ln -s ${.CURDIR}/$f ${.OBJDIR} .endfor +pf-changerule: changerule changerule-tail.ok changerule-head.ok \ + changerule-before.ok changerule-after.ok + ${SUDO} ${PFCTL} -a 'regress/*' -Fr + echo 'pass all' | ${SUDO} ${PFCTL} -a regress -f - +.for i in 10 20 30 40 50 + echo "pass in proto tcp from any to any port $i" | \ + ${SUDO} ./changerule -a regress -i 0 +.endfor + ${SUDO} ${PFCTL} -a regress -sr | diff -u changerule-head.ok /dev/stdin + ${SUDO} ${PFCTL} -a 'regress/*' -Fr + echo 'pass all' | ${SUDO} ${PFCTL} -a regress -f - +.for i in 10 20 30 40 50 + echo "pass in proto tcp from any to any port $i" | \ + ${SUDO} ./changerule -a regress -i -1 +.endfor + ${SUDO} ${PFCTL} -a regress -sr | diff -u changerule-tail.ok /dev/stdin + echo 'pass in proto tcp from any to any port 15' | \ + ${SUDO} ./changerule -a regress -i 2 + ${SUDO} ${PFCTL} -a regress -sr | \ + diff -u changerule-before.ok /dev/stdin + echo 'pass in proto tcp from any to any port 25' | \ + ${SUDO} ./changerule -a regress -I 3 + ${SUDO} ${PFCTL} -a regress -sr | \ + diff -u changerule-after.ok /dev/stdin + ${SUDO} ${PFCTL} -a 'regress/*' -Fr + update: ${UPDATE_TARGETS} alltests: ${REGRESS_TARGETS} ${NODEFAULT_TARGETS} diff --git a/regress/sbin/pfctl/changerule-after.ok b/regress/sbin/pfctl/changerule-after.ok new file mode 100644 index 00000000000..d05519b7e8f --- /dev/null +++ b/regress/sbin/pfctl/changerule-after.ok @@ -0,0 +1,8 @@ +pass all flags S/SA +pass in proto tcp from any to any port = 10 flags S/SA +pass in proto tcp from any to any port = 15 flags S/SA +pass in proto tcp from any to any port = 20 flags S/SA +pass in proto tcp from any to any port = 25 flags S/SA +pass in proto tcp from any to any port = 30 flags S/SA +pass in proto tcp from any to any port = 40 flags S/SA +pass in proto tcp from any to any port = 50 flags S/SA diff --git a/regress/sbin/pfctl/changerule-before.ok b/regress/sbin/pfctl/changerule-before.ok new file mode 100644 index 00000000000..79a6e4224b5 --- /dev/null +++ b/regress/sbin/pfctl/changerule-before.ok @@ -0,0 +1,7 @@ +pass all flags S/SA +pass in proto tcp from any to any port = 10 flags S/SA +pass in proto tcp from any to any port = 15 flags S/SA +pass in proto tcp from any to any port = 20 flags S/SA +pass in proto tcp from any to any port = 30 flags S/SA +pass in proto tcp from any to any port = 40 flags S/SA +pass in proto tcp from any to any port = 50 flags S/SA diff --git a/regress/sbin/pfctl/changerule-head.ok b/regress/sbin/pfctl/changerule-head.ok new file mode 100644 index 00000000000..faf6ac0e958 --- /dev/null +++ b/regress/sbin/pfctl/changerule-head.ok @@ -0,0 +1,6 @@ +pass in proto tcp from any to any port = 50 flags S/SA +pass in proto tcp from any to any port = 40 flags S/SA +pass in proto tcp from any to any port = 30 flags S/SA +pass in proto tcp from any to any port = 20 flags S/SA +pass in proto tcp from any to any port = 10 flags S/SA +pass all flags S/SA diff --git a/regress/sbin/pfctl/changerule-tail.ok b/regress/sbin/pfctl/changerule-tail.ok new file mode 100644 index 00000000000..c4791d47e6c --- /dev/null +++ b/regress/sbin/pfctl/changerule-tail.ok @@ -0,0 +1,6 @@ +pass all flags S/SA +pass in proto tcp from any to any port = 10 flags S/SA +pass in proto tcp from any to any port = 20 flags S/SA +pass in proto tcp from any to any port = 30 flags S/SA +pass in proto tcp from any to any port = 40 flags S/SA +pass in proto tcp from any to any port = 50 flags S/SA diff --git a/regress/sbin/pfctl/changerule.c b/regress/sbin/pfctl/changerule.c new file mode 100644 index 00000000000..8efd47d9a36 --- /dev/null +++ b/regress/sbin/pfctl/changerule.c @@ -0,0 +1,221 @@ +/* $OpenBSD: changerule.c,v 1.1 2021/11/11 12:49:53 sashan Exp $ */ +/* + * Copyright (c) 2021 Alexandr Nedvedicky <sashan@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * changerule - simple tool to test DIOCCHANGERULE functionality (see pf(4)) + * Tool reads firewall rules from stdin only. If more rules are passed, then + * only the first one is being used. Examples: + * echo 'pass all' | changerule -a test -i 0 + * inserts a rule to the first position in ruleset test + * + * echo 'pass all' | changerule -a test -i -1 + * inserts a rule to the last position in ruleset test + * + * echo 'pass all' | changerule -a test -i 3 + * inserts a rule before existing No. 3 rule (rules numbering + * starts with 0) in ruleset test + * + * echo 'pass all' | changerule -a test -I 3 + * inserts a rule after existing No. 3 rule (rules numbering + * starts with 0) in ruleset test + * + * changerule -a test -r 3 + * removes existing No. 3 rule from ruleset test + * + */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <net/pfvar.h> +#include <arpa/inet.h> +#include <sys/sysctl.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <syslog.h> +#include <stdarg.h> +#include <libgen.h> + +#include "pfctl_parser.h" +#include "pfctl.h" + +void changerule_usage(void); +int do_chng_cmd(char *, int, int); + +extern int dev; +extern char *anchoropt; +extern char *pf_device; + +__dead void +changerule_usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s", __progname); + fprintf(stderr, "[-a anchor] [ -i ruleNo ] [ -I ruleNo ]\n"); + exit(1); +} + +int +do_chng_cmd(char *anchorname, int cmd, int rule_no) +{ + struct pfctl pf; + struct pf_anchor rs_anchor; + struct pf_ruleset *rs = &rs_anchor.ruleset; + struct pfioc_rule pcr; + + memset(&pf, 0, sizeof(pf)); + memset(&rs_anchor, 0, sizeof(rs_anchor)); + pf.anchor = &rs_anchor; + pf_init_ruleset(rs); + + if (strlcpy(pf.anchor->path, anchorname, + sizeof(pf.anchor->path)) >= sizeof (pf.anchor->path)) + errx(1, "%s: strlcpy\n", __func__); + + pf.astack[0] = pf.anchor; + pf.asd = 0; + pf.dev = dev; + + memset(&pcr, 0, sizeof(pcr)); + strlcpy(pcr.anchor, anchorname, sizeof(pcr.anchor)); + pcr.action = PF_CHANGE_GET_TICKET; + if (ioctl(dev, DIOCCHANGERULE, &pcr) < 0) + errx(1, "ioctl(ticket) @ %s", __func__); + + pcr.action = cmd; + pcr.nr = rule_no; + if (cmd != PF_CHANGE_REMOVE) { + if (parse_config("-", &pf) < 0) { + errx(1, "Syntax error in rule"); + return (1); + } + + if (TAILQ_FIRST(rs->rules.active.ptr) != NULL) + memcpy(&pcr.rule, TAILQ_FIRST(rs->rules.active.ptr), + sizeof(pcr.rule)); + else + errx(1, "no rule"); + } + + if (ioctl(dev, DIOCCHANGERULE, &pcr) < 0) { + errx(1, "ioctl(commit) @ %s", __func__); + } + + return (0); +} + +int +main(int argc, char *argv[]) +{ + char anchorname[PATH_MAX]; + const char *errstr; + int ch; + int rule_no; + int chng_cmd; + int after = 0; + + if (argc < 2) + changerule_usage(); + + while ((ch = getopt(argc, argv, "a:i:I:r:")) != -1) { + switch (ch) { + case 'a': + anchoropt = optarg; + break; + case 'I': + after = 1; + /* FALLTHROUGH */ + case 'i': + rule_no = strtonum(optarg, -1, 0x7fffffff, &errstr); + if (errstr != NULL) { + warnx("Rule number outside of range <%d, %d\n", + -1, 0x7fffffff); + exit(1); + } + switch (rule_no) { + case 0: + chng_cmd = PF_CHANGE_ADD_HEAD; + break; + case -1: + chng_cmd = PF_CHANGE_ADD_TAIL; + break; + default: + if (after) + chng_cmd = PF_CHANGE_ADD_AFTER; + else + chng_cmd = PF_CHANGE_ADD_BEFORE; + } + break; + case 'r': + rule_no = strtonum(optarg, -1, 0x7fffffff, &errstr); + if (errstr != NULL) { + warnx("Rule number outside of range <%d, %d\n", + -1, 0x7fffffff); + exit(1); + } + chng_cmd = PF_CHANGE_REMOVE; + break; + default: + changerule_usage(); + /* NOTREACHED */ + } + } + + if (argc != optind) { + warnx("unknown command line argument: %s ...", argv[optind]); + changerule_usage(); + /* NOTREACHED */ + } + + memset(anchorname, 0, sizeof(anchorname)); + if (anchoropt != NULL) { + if (anchoropt[0] == '\0') + errx(1, "anchor name must not be empty"); + + if (anchoropt[0] == '_' || strstr(anchoropt, "/_") != NULL) + errx(1, "anchor names beginning with '_' cannot " + "be modified from the command line"); + int len = strlen(anchoropt); + + if (anchoropt[len - 1] == '*') { + warnx("wildcard anchors not supported\n"); + changerule_usage(); + } + if (strlcpy(anchorname, anchoropt, + sizeof(anchorname)) >= sizeof(anchorname)) + errx(1, "anchor name '%s' too long", + anchoropt); + } + + dev = open(pf_device, O_RDWR); + if (dev == -1) + err(1, "/dev/pf"); + + return (do_chng_cmd(anchoropt, chng_cmd, rule_no)); +} |