From nobody Wed Mar 30 09:17:22 2022 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 8C81E1A349D1; Wed, 30 Mar 2022 09:17:22 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4KT16V3N1Rz3Ggm; Wed, 30 Mar 2022 09:17:22 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1648631842; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=feSnclCIsRsXKsaSgRGC3rixEfGCf8QBuHERe9F2sjM=; b=dMWeZBh3sjb3xAlkaxy136u98zV+EItTi6L34ODuZ9r9DaBY3gbOEs8DbGqAVTulzJnqk+ JerxiZFfUFmI5LeFzn6OlwEnuY4rYXde9TOHZZrInDOAMX/GZ05u4fx0JXmK6XTw3Qg5n6 /rs30zJgjXYMU1+xNfkTd9imKX1UNBIphwoFWFQeYf2kjI40tqlCv8GyKNpIuH3ZfJtylT r3aIaggZNC3ymNYHnxM4QBlbptgq40jSLxFc1TrHH4lJgK1Pn4MsXPeKM+1mX7e+gzYYXg o86aMGX6PO6QC2HoD0zvoHhqQvbZnaGhU95o2exjqIKinMcF1RizJ+MzzXYJzw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 504F41037D; Wed, 30 Mar 2022 09:17:22 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 22U9HMSP090973; Wed, 30 Mar 2022 09:17:22 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 22U9HMb6090972; Wed, 30 Mar 2022 09:17:22 GMT (envelope-from git) Date: Wed, 30 Mar 2022 09:17:22 GMT Message-Id: <202203300917.22U9HMb6090972@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: 9bb06778f822 - main - pf: support listing ethernet anchors List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 9bb06778f822ad6b47d2a825d47e284ca8dd29a1 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1648631842; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=feSnclCIsRsXKsaSgRGC3rixEfGCf8QBuHERe9F2sjM=; b=cUcSq46EtULOJYUTQWL9mbPLdjiI+mm4SqGg4JAKmTOCLr94owiiXl9Y0F6L64ckEvoBF5 PlgLzghrpSHQAY2q9DaO9MVMf0mkJWS+W0/sOS808J6qpYl6CMfc6yAILcqFKAGfBpor53 V43+bLKbKz5eziGO335W3Z3/Rs9c3YTu/cCQ76JesgNbJnSmm5DWFYSeX2iyeRGpDgK3o2 DZ2n9/lzm8VYP9b3izYHCDXeogNXfRAHJf8MxwDPMHKL/zJd2j901Jstsp3LVTfOQfP5nY dFulF0jR6nONvgl4SNBKB/1QTXx1GKa0GBVfmld4MY5JEvIKkrClUvbL/h/u2A== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1648631842; a=rsa-sha256; cv=none; b=ASz2ix3hU9p7KKtIMhg0B68KBBnQZO398ea5U6WDINwUXWEAXL8EqiKDR8+n6QnxgpxSEN KFn7FfkwhJsnc0slWZEBnG8ylprcYQebG6vzlMHy3jSX41Wjw4WFV5dMyN044HRcy5Bsa+ ZWmCpJ7mmG5NdryHOe18GNoHT3F3Tny6tqYcZpaVhtomW/H4tNY4G260qW0BMQr5AV6zAq f5Wqbhv/kcFh8hDd4rVEDWq71fxO0sJKgce6Jvuf71/7Cxs729GOwxIaP56b2GTo20mZKb ofeBTANcyYOmrm3zA45ki9wHWgePko1P3KZp2cOmOWFVAtlA7yqRqHLHHbNVOg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=9bb06778f822ad6b47d2a825d47e284ca8dd29a1 commit 9bb06778f822ad6b47d2a825d47e284ca8dd29a1 Author: Kristof Provost AuthorDate: 2022-03-29 12:15:10 +0000 Commit: Kristof Provost CommitDate: 2022-03-30 08:28:19 +0000 pf: support listing ethernet anchors Sponsored by: Rubicon Communications, LLC ("Netgate") --- lib/libpfctl/libpfctl.c | 75 +++++++++++++++++ lib/libpfctl/libpfctl.h | 14 ++++ sbin/pfctl/pfctl.c | 40 ++++++++++ sys/net/pfvar.h | 2 + sys/netpfil/pf/pf_ioctl.c | 182 ++++++++++++++++++++++++++++++++++++++++++ tests/sys/netpfil/pf/ether.sh | 2 + 6 files changed, 315 insertions(+) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index 8f064594260b..1e1a90594210 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -622,6 +622,81 @@ pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule) rule->action = nvlist_get_number(nvl, "action"); } +int +pfctl_get_eth_rulesets_info(int dev, struct pfctl_eth_rulesets_info *ri, + const char *path) +{ + uint8_t buf[1024]; + struct pfioc_nv nv; + nvlist_t *nvl; + void *packed; + size_t len; + + bzero(ri, sizeof(*ri)); + + nvl = nvlist_create(0); + nvlist_add_string(nvl, "path", path); + packed = nvlist_pack(nvl, &len); + memcpy(buf, packed, len); + free(packed); + nvlist_destroy(nvl); + + nv.data = buf; + nv.len = len; + nv.size = sizeof(buf); + + if (ioctl(dev, DIOCGETETHRULESETS, &nv) != 0) + return (errno); + + nvl = nvlist_unpack(buf, nv.len, 0); + if (nvl == NULL) + return (EIO); + + ri->nr = nvlist_get_number(nvl, "nr"); + + nvlist_destroy(nvl); + return (0); +} + +int +pfctl_get_eth_ruleset(int dev, const char *path, int nr, + struct pfctl_eth_ruleset_info *ri) +{ + uint8_t buf[1024]; + struct pfioc_nv nv; + nvlist_t *nvl; + void *packed; + size_t len; + + bzero(ri, sizeof(*ri)); + + nvl = nvlist_create(0); + nvlist_add_string(nvl, "path", path); + nvlist_add_number(nvl, "nr", nr); + packed = nvlist_pack(nvl, &len); + memcpy(buf, packed, len); + free(packed); + nvlist_destroy(nvl); + + nv.data = buf; + nv.len = len; + nv.size = sizeof(buf); + + if (ioctl(dev, DIOCGETETHRULESET, &nv) != 0) + return (errno); + + nvl = nvlist_unpack(buf, nv.len, 0); + if (nvl == NULL) + return (EIO); + + ri->nr = nvlist_get_number(nvl, "nr"); + strlcpy(ri->path, nvlist_get_string(nvl, "path"), MAXPATHLEN); + strlcpy(ri->name, nvlist_get_string(nvl, "name"), + PF_ANCHOR_NAME_SIZE); + + return (0); +} + int pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules, const char *path) diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h index b7f703b64def..92a1ea9b7cef 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -66,6 +66,10 @@ struct pfctl_status { uint64_t bcounters[2][2]; }; +struct pfctl_eth_rulesets_info { + uint32_t nr; +}; + struct pfctl_eth_rules_info { uint32_t nr; uint32_t ticket; @@ -111,6 +115,12 @@ struct pfctl_eth_rule { }; TAILQ_HEAD(pfctl_eth_rules, pfctl_eth_rule); +struct pfctl_eth_ruleset_info { + uint32_t nr; + char name[PF_ANCHOR_NAME_SIZE]; + char path[MAXPATHLEN]; +}; + struct pfctl_eth_ruleset { struct pfctl_eth_rules rules; struct pfctl_eth_anchor *anchor; @@ -356,6 +366,10 @@ struct pfctl_syncookies { struct pfctl_status* pfctl_get_status(int dev); void pfctl_free_status(struct pfctl_status *status); +int pfctl_get_eth_rulesets_info(int dev, + struct pfctl_eth_rulesets_info *ri, const char *path); +int pfctl_get_eth_ruleset(int dev, const char *path, int nr, + struct pfctl_eth_ruleset_info *ri); int pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules, const char *path); int pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket, diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 88a96bd303a0..67358a325f77 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -111,6 +111,7 @@ int pfctl_show_limits(int, int); void pfctl_debug(int, u_int32_t, int); int pfctl_test_altqsupport(int, int); int pfctl_show_anchors(int, int, char *); +int pfctl_show_eth_anchors(int, int, char *); int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *, bool); int pfctl_eth_ruleset_trans(struct pfctl *, char *, struct pfctl_eth_anchor *); @@ -2604,6 +2605,44 @@ pfctl_show_anchors(int dev, int opts, char *anchorname) return (0); } +int +pfctl_show_eth_anchors(int dev, int opts, char *anchorname) +{ + struct pfctl_eth_rulesets_info ri; + struct pfctl_eth_ruleset_info rs; + int ret; + + if ((ret = pfctl_get_eth_rulesets_info(dev, &ri, anchorname)) != 0) { + if (ret == ENOENT) + fprintf(stderr, "Anchor '%s' not found.\n", + anchorname); + else + err(1, "DIOCGETETHRULESETS"); + return (-1); + } + + for (int nr = 0; nr < ri.nr; nr++) { + char sub[MAXPATHLEN]; + + if (pfctl_get_eth_ruleset(dev, anchorname, nr, &rs) != 0) + err(1, "DIOCGETETHRULESET"); + + if (!strcmp(rs.name, PF_RESERVED_ANCHOR)) + continue; + sub[0] = 0; + if (rs.path[0]) { + strlcat(sub, rs.path, sizeof(sub)); + strlcat(sub, "/", sizeof(sub)); + } + strlcat(sub, rs.name, sizeof(sub)); + if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) + printf(" %s\n", sub); + if ((opts & PF_OPT_VERBOSE) && pfctl_show_eth_anchors(dev, opts, sub)) + return (-1); + } + return (0); +} + const char * pfctl_lookup_option(char *cmd, const char * const *list) { @@ -2830,6 +2869,7 @@ main(int argc, char *argv[]) switch (*showopt) { case 'A': pfctl_show_anchors(dev, opts, anchorname); + pfctl_show_eth_anchors(dev, opts, anchorname); break; case 'r': pfctl_load_fingerprints(dev, opts); diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index ccc81ea137b9..db6b5c22f07f 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1865,6 +1865,8 @@ struct pfioc_iface { #define DIOCADDETHRULE _IOWR('D', 97, struct pfioc_nv) #define DIOCGETETHRULE _IOWR('D', 98, struct pfioc_nv) #define DIOCGETETHRULES _IOWR('D', 99, struct pfioc_nv) +#define DIOCGETETHRULESETS _IOWR('D', 100, struct pfioc_nv) +#define DIOCGETETHRULESET _IOWR('D', 101, struct pfioc_nv) struct pf_ifspeed_v0 { char ifname[IFNAMSIZ]; diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 6012825ead9b..3cb5552d20c5 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -2463,6 +2463,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCCLRIFFLAG: case DIOCGETETHRULES: case DIOCGETETHRULE: + case DIOCGETETHRULESETS: + case DIOCGETETHRULESET: break; case DIOCRCLRTABLES: case DIOCRADDTABLES: @@ -2512,6 +2514,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCGETRULENV: case DIOCGETETHRULES: case DIOCGETETHRULE: + case DIOCGETETHRULESETS: + case DIOCGETETHRULESET: break; case DIOCRCLRTABLES: case DIOCRADDTABLES: @@ -2864,6 +2868,184 @@ DIOCADDETHRULE_error: break; } + case DIOCGETETHRULESETS: { + struct epoch_tracker et; + struct pfioc_nv *nv = (struct pfioc_nv *)addr; + nvlist_t *nvl = NULL; + void *nvlpacked = NULL; + struct pf_keth_ruleset *ruleset; + struct pf_keth_anchor *anchor; + int nr = 0; + +#define ERROUT(x) do { error = (x); goto DIOCGETETHRULESETS_error; } while (0) + + if (nv->len > pf_ioctl_maxcount) + ERROUT(ENOMEM); + + nvlpacked = malloc(nv->len, M_NVLIST, M_WAITOK); + if (nvlpacked == NULL) + ERROUT(ENOMEM); + + error = copyin(nv->data, nvlpacked, nv->len); + if (error) + ERROUT(error); + + nvl = nvlist_unpack(nvlpacked, nv->len, 0); + if (nvl == NULL) + ERROUT(EBADMSG); + if (! nvlist_exists_string(nvl, "path")) + ERROUT(EBADMSG); + + NET_EPOCH_ENTER(et); + + if ((ruleset = pf_find_keth_ruleset( + nvlist_get_string(nvl, "path"))) == NULL) { + NET_EPOCH_EXIT(et); + ERROUT(ENOENT); + } + + if (ruleset->anchor == NULL) { + RB_FOREACH(anchor, pf_keth_anchor_global, &V_pf_keth_anchors) + if (anchor->parent == NULL) + nr++; + } else { + RB_FOREACH(anchor, pf_keth_anchor_node, + &ruleset->anchor->children) + nr++; + } + + NET_EPOCH_EXIT(et); + + nvlist_destroy(nvl); + nvl = NULL; + free(nvlpacked, M_NVLIST); + nvlpacked = NULL; + + nvl = nvlist_create(0); + if (nvl == NULL) + ERROUT(ENOMEM); + + nvlist_add_number(nvl, "nr", nr); + + nvlpacked = nvlist_pack(nvl, &nv->len); + if (nvlpacked == NULL) + ERROUT(ENOMEM); + + if (nv->size == 0) + ERROUT(0); + else if (nv->size < nv->len) + ERROUT(ENOSPC); + + error = copyout(nvlpacked, nv->data, nv->len); + +#undef ERROUT +DIOCGETETHRULESETS_error: + free(nvlpacked, M_NVLIST); + nvlist_destroy(nvl); + break; + } + + case DIOCGETETHRULESET: { + struct epoch_tracker et; + struct pfioc_nv *nv = (struct pfioc_nv *)addr; + nvlist_t *nvl = NULL; + void *nvlpacked = NULL; + struct pf_keth_ruleset *ruleset; + struct pf_keth_anchor *anchor; + int nr = 0, req_nr = 0; + bool found = false; + +#define ERROUT(x) do { error = (x); goto DIOCGETETHRULESET_error; } while (0) + + if (nv->len > pf_ioctl_maxcount) + ERROUT(ENOMEM); + + nvlpacked = malloc(nv->len, M_NVLIST, M_WAITOK); + if (nvlpacked == NULL) + ERROUT(ENOMEM); + + error = copyin(nv->data, nvlpacked, nv->len); + if (error) + ERROUT(error); + + nvl = nvlist_unpack(nvlpacked, nv->len, 0); + if (nvl == NULL) + ERROUT(EBADMSG); + if (! nvlist_exists_string(nvl, "path")) + ERROUT(EBADMSG); + if (! nvlist_exists_number(nvl, "nr")) + ERROUT(EBADMSG); + + req_nr = nvlist_get_number(nvl, "nr"); + + NET_EPOCH_ENTER(et); + + if ((ruleset = pf_find_keth_ruleset( + nvlist_get_string(nvl, "path"))) == NULL) { + NET_EPOCH_EXIT(et); + ERROUT(ENOENT); + } + + nvlist_destroy(nvl); + nvl = NULL; + free(nvlpacked, M_NVLIST); + nvlpacked = NULL; + + nvl = nvlist_create(0); + if (nvl == NULL) { + NET_EPOCH_EXIT(et); + ERROUT(ENOMEM); + } + + if (ruleset->anchor == NULL) { + RB_FOREACH(anchor, pf_keth_anchor_global, + &V_pf_keth_anchors) { + if (anchor->parent == NULL && nr++ == req_nr) { + found = true; + break; + } + } + } else { + RB_FOREACH(anchor, pf_keth_anchor_node, + &ruleset->anchor->children) { + if (nr++ == req_nr) { + found = true; + break; + } + } + } + + NET_EPOCH_EXIT(et); + if (found) { + nvlist_add_number(nvl, "nr", nr); + nvlist_add_string(nvl, "name", anchor->name); + if (ruleset->anchor) + nvlist_add_string(nvl, "path", + ruleset->anchor->path); + else + nvlist_add_string(nvl, "path", ""); + } else { + ERROUT(EBUSY); + } + + nvlpacked = nvlist_pack(nvl, &nv->len); + if (nvlpacked == NULL) + ERROUT(ENOMEM); + + if (nv->size == 0) + ERROUT(0); + else if (nv->size < nv->len) + ERROUT(ENOSPC); + + error = copyout(nvlpacked, nv->data, nv->len); + +#undef ERROUT +DIOCGETETHRULESET_error: + free(nvlpacked, M_NVLIST); + nvlist_destroy(nvl); + break; + } + case DIOCADDRULENV: { struct pfioc_nv *nv = (struct pfioc_nv *)addr; nvlist_t *nvl = NULL; diff --git a/tests/sys/netpfil/pf/ether.sh b/tests/sys/netpfil/pf/ether.sh index 6e81f07ca26e..7a7f91844148 100644 --- a/tests/sys/netpfil/pf/ether.sh +++ b/tests/sys/netpfil/pf/ether.sh @@ -490,6 +490,8 @@ anchor_body() "}" \ "ether pass in from ${epair_a_mac}" atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 + + atf_check -s exit:0 -o match:'baz' jexec alcatraz pfctl -sA } anchor_cleanup()