Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 10 Apr 2021 09:16:21 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0d6c8174ef2f - main - pfctl: Use the new DIOCGETRULENV ioctl
Message-ID:  <202104100916.13A9GLWm068998@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=0d6c8174ef2f3d8d6fb02ec97753a0937796a5c6

commit 0d6c8174ef2f3d8d6fb02ec97753a0937796a5c6
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-03-26 10:22:15 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-04-10 09:16:01 +0000

    pfctl: Use the new DIOCGETRULENV ioctl
    
    Create wrapper functions to handle the parsing of the nvlist and move
    that code into pfctl_ioctl.c.
    At some point this should be moved into a libpfctl.
    
    MFC after:      4 weeks
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D29560
---
 sbin/pfctl/Makefile         |   2 +-
 sbin/pfctl/pfctl.c          |  12 +-
 sbin/pfctl/pfctl_ioctl.c    | 339 ++++++++++++++++++++++++++++++++++++++++++++
 sbin/pfctl/pfctl_ioctl.h    |  43 ++++++
 sbin/pfctl/pfctl_optimize.c |   7 +-
 5 files changed, 396 insertions(+), 7 deletions(-)

diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile
index 74cefe6824a4..c84d558c989d 100644
--- a/sbin/pfctl/Makefile
+++ b/sbin/pfctl/Makefile
@@ -9,7 +9,7 @@ MAN=	pfctl.8
 
 SRCS = pfctl.c parse.y pfctl_parser.c pf_print_state.c pfctl_altq.c
 SRCS+= pfctl_osfp.c pfctl_radix.c pfctl_table.c pfctl_qstats.c
-SRCS+= pfctl_optimize.c
+SRCS+= pfctl_optimize.c pfctl_ioctl.c
 SRCS+= pf_ruleset.c
 
 WARNS?=	2
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 58a87a2b8395..1aa17065597b 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
 #include <string.h>
 #include <unistd.h>
 
+#include "pfctl_ioctl.h"
 #include "pfctl_parser.h"
 #include "pfctl.h"
 
@@ -952,8 +953,9 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
 
 	for (nr = 0; nr < mnr; ++nr) {
 		pr.nr = nr;
-		if (ioctl(dev, DIOCGETRULE, &pr)) {
-			warn("DIOCGETRULE");
+		if (pfctl_get_rule(dev, nr, pr.ticket, path, PF_SCRUB,
+		    &pr.rule, pr.anchor_call)) {
+			warn("DIOCGETRULENV");
 			goto error;
 		}
 
@@ -984,7 +986,8 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
 	mnr = pr.nr;
 	for (nr = 0; nr < mnr; ++nr) {
 		pr.nr = nr;
-		if (ioctl(dev, DIOCGETRULE, &pr)) {
+		if (pfctl_get_rule(dev, nr, pr.ticket, path, PF_PASS,
+		    &pr.rule, pr.anchor_call)) {
 			warn("DIOCGETRULE");
 			goto error;
 		}
@@ -1074,7 +1077,8 @@ pfctl_show_nat(int dev, int opts, char *anchorname)
 		mnr = pr.nr;
 		for (nr = 0; nr < mnr; ++nr) {
 			pr.nr = nr;
-			if (ioctl(dev, DIOCGETRULE, &pr)) {
+			if (pfctl_get_rule(dev, nr, pr.ticket, anchorname,
+			    nattype[i], &pr.rule, pr.anchor_call)) {
 				warn("DIOCGETRULE");
 				return (-1);
 			}
diff --git a/sbin/pfctl/pfctl_ioctl.c b/sbin/pfctl/pfctl_ioctl.c
new file mode 100644
index 000000000000..878a57de0fe4
--- /dev/null
+++ b/sbin/pfctl/pfctl_ioctl.c
@@ -0,0 +1,339 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    - Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    - Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/ioctl.h>
+#include <sys/nv.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pfctl_ioctl.h"
+
+static void
+pf_nvuint_8_array(const nvlist_t *nvl, const char *name, size_t maxelems,
+    u_int8_t *numbers, size_t *nelems)
+{
+	const uint64_t *tmp;
+	size_t elems;
+
+	tmp = nvlist_get_number_array(nvl, name, &elems);
+	assert(elems <= maxelems);
+
+	for (size_t i = 0; i < elems; i++)
+		numbers[i] = tmp[i];
+
+	if (nelems)
+		*nelems = elems;
+}
+
+static void
+pf_nvuint_16_array(const nvlist_t *nvl, const char *name, size_t maxelems,
+    u_int16_t *numbers, size_t *nelems)
+{
+	const uint64_t *tmp;
+	size_t elems;
+
+	tmp = nvlist_get_number_array(nvl, name, &elems);
+	assert(elems <= maxelems);
+
+	for (size_t i = 0; i < elems; i++)
+		numbers[i] = tmp[i];
+
+	if (nelems)
+		*nelems = elems;
+}
+
+static void
+pf_nvuint_32_array(const nvlist_t *nvl, const char *name, size_t maxelems,
+    u_int32_t *numbers, size_t *nelems)
+{
+	const uint64_t *tmp;
+	size_t elems;
+
+	tmp = nvlist_get_number_array(nvl, name, &elems);
+	assert(elems <= maxelems);
+
+	for (size_t i = 0; i < elems; i++)
+		numbers[i] = tmp[i];
+
+	if (nelems)
+		*nelems = elems;
+}
+
+static void
+pf_nvuint_64_array(const nvlist_t *nvl, const char *name, size_t maxelems,
+    u_int64_t *numbers, size_t *nelems)
+{
+	const uint64_t *tmp;
+	size_t elems;
+
+	tmp = nvlist_get_number_array(nvl, name, &elems);
+	assert(elems <= maxelems);
+
+	for (size_t i = 0; i < elems; i++)
+		numbers[i] = tmp[i];
+
+	if (nelems)
+		*nelems = elems;
+}
+
+static void
+pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *addr)
+{
+	size_t len;
+	const void *data;
+
+	data = nvlist_get_binary(nvl, "addr", &len);
+	assert(len == sizeof(struct pf_addr));
+	memcpy(addr, data, len);
+}
+
+static void
+pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
+{
+	addr->type = nvlist_get_number(nvl, "type");
+	addr->iflags = nvlist_get_number(nvl, "iflags");
+	strlcpy(addr->v.ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
+	strlcpy(addr->v.tblname, nvlist_get_string(nvl, "tblname"),
+	    PF_TABLE_NAME_SIZE);
+
+	pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &addr->v.a.addr);
+	pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"), &addr->v.a.mask);
+}
+
+static void
+pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
+{
+	pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"), &addr->addr);
+
+	pf_nvuint_16_array(nvl, "port", 2, addr->port, NULL);
+	addr->neg = nvlist_get_number(nvl, "neg");
+	addr->port_op = nvlist_get_number(nvl, "port_op");
+}
+
+static void
+pf_nvpool_to_pool(const nvlist_t *nvl, struct pf_pool *pool)
+{
+	size_t len;
+	const void *data;
+
+	data = nvlist_get_binary(nvl, "key", &len);
+	assert(len == sizeof(pool->key));
+	memcpy(&pool->key, data, len);
+
+	pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"), &pool->counter);
+
+	pool->tblidx = nvlist_get_number(nvl, "tblidx");
+	pf_nvuint_16_array(nvl, "proxy_port", 2, pool->proxy_port, NULL);
+	pool->opts = nvlist_get_number(nvl, "opts");
+}
+
+static void
+pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
+{
+	pf_nvuint_32_array(nvl, "uid", 2, uid->uid, NULL);
+	uid->op = nvlist_get_number(nvl, "op");
+}
+
+static void
+pf_nvdivert_to_divert(const nvlist_t *nvl, struct pf_rule *rule)
+{
+	pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &rule->divert.addr);
+	rule->divert.port = nvlist_get_number(nvl, "port");
+}
+
+static void
+pf_nvrule_to_rule(const nvlist_t *nvl, struct pf_rule *rule)
+{
+	const uint64_t *skip;
+	size_t skipcount;
+
+	rule->nr = nvlist_get_number(nvl, "nr");
+
+	pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"), &rule->src);
+	pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"), &rule->dst);
+
+	skip = nvlist_get_number_array(nvl, "skip", &skipcount);
+	assert(skip);
+	assert(skipcount == PF_SKIP_COUNT);
+	for (int i = 0; i < PF_SKIP_COUNT; i++)
+		rule->skip[i].nr = skip[i];
+
+	strlcpy(rule->label, nvlist_get_string(nvl, "label"), PF_RULE_LABEL_SIZE);
+	strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
+	strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE);
+	strlcpy(rule->pqname, nvlist_get_string(nvl, "pqname"), PF_QNAME_SIZE);
+	strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"),
+	    PF_TAG_NAME_SIZE);
+	strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"),
+	    PF_TAG_NAME_SIZE);
+
+	strlcpy(rule->overload_tblname, nvlist_get_string(nvl, "overload_tblname"),
+	    PF_TABLE_NAME_SIZE);
+
+	pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"), &rule->rpool);
+
+	rule->evaluations = nvlist_get_number(nvl, "evaluations");
+	pf_nvuint_64_array(nvl, "packets", 2, rule->packets, NULL);
+	pf_nvuint_64_array(nvl, "bytes", 2, rule->bytes, NULL);
+
+	rule->os_fingerprint = nvlist_get_number(nvl, "os_fingerprint");
+
+	rule->rtableid = nvlist_get_number(nvl, "rtableid");
+	pf_nvuint_32_array(nvl, "timeout", PFTM_MAX, rule->timeout, NULL);
+	rule->max_states = nvlist_get_number(nvl, "max_states");
+	rule->max_src_nodes = nvlist_get_number(nvl, "max_src_nodes");
+	rule->max_src_states = nvlist_get_number(nvl, "max_src_states");
+	rule->max_src_conn = nvlist_get_number(nvl, "max_src_conn");
+	rule->max_src_conn_rate.limit =
+	    nvlist_get_number(nvl, "max_src_conn_rate.limit");
+	rule->max_src_conn_rate.seconds =
+	    nvlist_get_number(nvl, "max_src_conn_rate.seconds");
+	rule->qid = nvlist_get_number(nvl, "qid");
+	rule->pqid = nvlist_get_number(nvl, "pqid");
+	rule->prob = nvlist_get_number(nvl, "prob");
+	rule->cuid = nvlist_get_number(nvl, "cuid");
+	rule->cpid = nvlist_get_number(nvl, "cpid");
+
+	rule->return_icmp = nvlist_get_number(nvl, "return_icmp");
+	rule->return_icmp6 = nvlist_get_number(nvl, "return_icmp6");
+	rule->max_mss = nvlist_get_number(nvl, "max_mss");
+	rule->scrub_flags = nvlist_get_number(nvl, "scrub_flags");
+
+	pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"), &rule->uid);
+	pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "gid"),
+	    (struct pf_rule_uid *)&rule->gid);
+
+	rule->rule_flag = nvlist_get_number(nvl, "rule_flag");
+	rule->action = nvlist_get_number(nvl, "action");
+	rule->direction = nvlist_get_number(nvl, "direction");
+	rule->log = nvlist_get_number(nvl, "log");
+	rule->logif = nvlist_get_number(nvl, "logif");
+	rule->quick = nvlist_get_number(nvl, "quick");
+	rule->ifnot = nvlist_get_number(nvl, "ifnot");
+	rule->match_tag_not = nvlist_get_number(nvl, "match_tag_not");
+	rule->natpass = nvlist_get_number(nvl, "natpass");
+
+	rule->keep_state = nvlist_get_number(nvl, "keep_state");
+	rule->af = nvlist_get_number(nvl, "af");
+	rule->proto = nvlist_get_number(nvl, "proto");
+	rule->type = nvlist_get_number(nvl, "type");
+	rule->code = nvlist_get_number(nvl, "code");
+	rule->flags = nvlist_get_number(nvl, "flags");
+	rule->flagset = nvlist_get_number(nvl, "flagset");
+	rule->min_ttl = nvlist_get_number(nvl, "min_ttl");
+	rule->allow_opts = nvlist_get_number(nvl, "allow_opts");
+	rule->rt = nvlist_get_number(nvl, "rt");
+	rule->return_ttl  = nvlist_get_number(nvl, "return_ttl");
+	rule->tos = nvlist_get_number(nvl, "tos");
+	rule->set_tos = nvlist_get_number(nvl, "set_tos");
+	rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative");
+	rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard");
+
+	rule->flush = nvlist_get_number(nvl, "flush");
+	rule->prio = nvlist_get_number(nvl, "prio");
+	pf_nvuint_8_array(nvl, "set_prio", 2, rule->set_prio, NULL);
+
+	pf_nvdivert_to_divert(nvlist_get_nvlist(nvl, "divert"), rule);
+
+	rule->u_states_cur = nvlist_get_number(nvl, "states_cur");
+	rule->u_states_tot = nvlist_get_number(nvl, "states_tot");
+	rule->u_src_nodes = nvlist_get_number(nvl, "src_nodes");
+}
+
+
+int
+pfctl_get_rule(int dev, u_int32_t nr, u_int32_t ticket, const char *anchor,
+    u_int32_t ruleset, struct pf_rule *rule, char *anchor_call)
+{
+	struct pfioc_nv nv;
+	nvlist_t *nvl;
+	void *nvlpacked;
+	int ret;
+
+	nvl = nvlist_create(0);
+	if (nvl == 0)
+		return (ENOMEM);
+
+	nvlist_add_number(nvl, "nr", nr);
+	nvlist_add_number(nvl, "ticket", ticket);
+	nvlist_add_string(nvl, "anchor", anchor);
+	nvlist_add_number(nvl, "ruleset", ruleset);
+
+	nvlpacked = nvlist_pack(nvl, &nv.len);
+	if (nvlpacked == NULL) {
+		nvlist_destroy(nvl);
+		return (ENOMEM);
+	}
+	nv.data = malloc(8182);
+	nv.size = 8192;
+	assert(nv.len <= nv.size);
+	memcpy(nv.data, nvlpacked, nv.len);
+	nvlist_destroy(nvl);
+	nvl = NULL;
+	free(nvlpacked);
+
+	ret = ioctl(dev, DIOCGETRULENV, &nv);
+	if (ret != 0) {
+		free(nv.data);
+		return (ret);
+	}
+
+	nvl = nvlist_unpack(nv.data, nv.len, 0);
+	if (nvl == NULL) {
+		free(nv.data);
+		return (EIO);
+	}
+
+	pf_nvrule_to_rule(nvlist_get_nvlist(nvl, "rule"), rule);
+
+	if (anchor_call)
+		strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"),
+		    MAXPATHLEN);
+
+	free(nv.data);
+	nvlist_destroy(nvl);
+
+	return (0);
+}
diff --git a/sbin/pfctl/pfctl_ioctl.h b/sbin/pfctl/pfctl_ioctl.h
new file mode 100644
index 000000000000..41dd0776854a
--- /dev/null
+++ b/sbin/pfctl/pfctl_ioctl.h
@@ -0,0 +1,43 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    - Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    - Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PFCTL_IOCTL_H_
+#define _PFCTL_IOCTL_H_
+
+#include <netpfil/pf/pf.h>
+
+int	pfctl_get_rule(int dev, u_int32_t nr, u_int32_t ticket,
+	    const char *anchor, u_int32_t ruleset, struct pf_rule *rule,
+	    char *anchor_call);
+
+#endif
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index 599ed2424ebf..d3f0aa1bf3a4 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <stdlib.h>
 #include <string.h>
 
+#include "pfctl_ioctl.h"
 #include "pfctl_parser.h"
 #include "pfctl.h"
 
@@ -909,8 +910,10 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
 			return (1);
 		}
 		pr.nr = nr;
-		if (ioctl(pf->dev, DIOCGETRULE, &pr)) {
-			warn("DIOCGETRULES");
+
+		if (pfctl_get_rule(pf->dev, nr, pr.ticket, "", PF_PASS,
+		    &pr.rule, pr.anchor_call)) {
+			warn("DIOCGETRULENV");
 			return (1);
 		}
 		memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202104100916.13A9GLWm068998>