From nobody Mon Jun 20 09:09:07 2022 X-Original-To: dev-commits-src-all@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 DF7648766F6; Mon, 20 Jun 2022 09:09:07 +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 4LRP375gvGz3C0l; Mon, 20 Jun 2022 09:09:07 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1655716147; 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=aOevGAtXusTWzSJbTuC1hlK9BnTvzVSf56QelDKh0k0=; b=UF8wtqjVDUprao+a7bCkDL/PyBmDiMi6g0mu9BPiw2xJ0Tsgby8wUjSKBKK9jr2zgGwQg8 gHzcVJLZxy5stkoJOj9UAUHChwV01eM/SVtBVhSIvOjgZl6M7q7a0RneW4uOJ6RBAQHVAG fK/wkM/le/lXuSe+HYDAbrNNlK3vT6xsN180hHXogoU4LBLeUVhmguWAw46FqSxMx55v8j gaOs1uFdJofFX+n+yaxEv4OjaeeJ1ygmdlkDFZ+3kcSpikd9uFT1bH1cFdjhMbt2DkY0/2 p50CT7iG6cKSF80MHKq4qNveBnWqAZ2jcsQwkgoEgmTLWElgeuRgVxve17Ixpw== 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 A2EB31A80B; Mon, 20 Jun 2022 09:09:07 +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 25K9979b004497; Mon, 20 Jun 2022 09:09:07 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 25K997PJ004496; Mon, 20 Jun 2022 09:09:07 GMT (envelope-from git) Date: Mon, 20 Jun 2022 09:09:07 GMT Message-Id: <202206200909.25K997PJ004496@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: 1f61367f8d61 - main - pf: support matching on tags for Ethernet rules List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@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: 1f61367f8d61fd6963a47296a86f553c403b5f91 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1655716147; 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=aOevGAtXusTWzSJbTuC1hlK9BnTvzVSf56QelDKh0k0=; b=pgkTe4vMXxpfA+s5+ZzbfrrCz0grRsUBzgNUfU9e/UEfKefqEFNruXgiSvsIzpiaByFm9w sZKt2qPVbsMotO285qC92enyOVSpREfmGNpX22O93U7A4w87muGQhcfDSs25w7AkPJHD4o DOD6bictCy8Pf/FquqDrSwLYuBCqPNt4rhdWIRvCB7LFu0ruZNzWg0MgpHWIDZx58F+SPI xPafvgLZESjrAavPeEEk2cV0oVSZjoZBIVv6dv0ltDR5isE6scmzJ0hfHIKykNSWsErqof w7zJtKayFGK30MBRpsfvTlx48xUNAwM5M30DLuBCcADisRm6lYN6Cw+QgZNnTg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1655716147; a=rsa-sha256; cv=none; b=igYNYka4rz3F7Ad/y6luJCiMY6vkndmBpv7DhxSTVJ5FiwBC8XEyRCz5lozXaecAeCDUC0 Y5CxEA0T2nIJ+wDOi087z0wYwJSQ983/z9Yr2ooZHJYkbp66gxd/LswhP99CSBg1JA5+ZJ UktxZiHa5HIIlofDyhR+aPG+GqoqkpPpL+uL5jN5G+kLUAZWiZN275NW178vDkaE9+nUlf x8dcEokwMNis51XIImCIzAVa0qC1OH3EhrG8Xn7tSZQWo0S7eyI/f+TfH8NiMb2LFAGezg TwHXVNQ5PGoOu3WJtkzAmEYcRUgwroAkqllfOk2LX2URB6ZBWo56SSmYSkjbKw== 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=1f61367f8d61fd6963a47296a86f553c403b5f91 commit 1f61367f8d61fd6963a47296a86f553c403b5f91 Author: Kristof Provost AuthorDate: 2022-05-31 12:00:52 +0000 Commit: Kristof Provost CommitDate: 2022-06-20 08:16:20 +0000 pf: support matching on tags for Ethernet rules Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D35362 --- lib/libpfctl/libpfctl.c | 6 ++++++ lib/libpfctl/libpfctl.h | 3 +++ sbin/pfctl/parse.y | 33 +++++++++++++++++++++++++++++++++ sbin/pfctl/pfctl_parser.c | 5 +++++ share/man/man5/pf.conf.5 | 7 ++++++- sys/net/pfvar.h | 4 ++++ sys/netpfil/pf/pf.c | 23 +++++++++++++++++++++-- sys/netpfil/pf/pf_ioctl.c | 6 ++++++ sys/netpfil/pf/pf_nv.c | 9 +++++++++ 9 files changed, 93 insertions(+), 3 deletions(-) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index 6a883a814902..3adfb7b94af3 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -629,6 +629,10 @@ pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule) rule->ifnot = nvlist_get_bool(nvl, "ifnot"); rule->direction = nvlist_get_number(nvl, "direction"); rule->proto = nvlist_get_number(nvl, "proto"); + strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"), + PF_TAG_NAME_SIZE); + rule->match_tag = nvlist_get_number(nvl, "match_tag"); + rule->match_tag_not = nvlist_get_bool(nvl, "match_tag_not"); pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "src"), &rule->src); @@ -780,6 +784,8 @@ pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor, nvlist_add_bool(nvl, "ifnot", r->ifnot); nvlist_add_number(nvl, "direction", r->direction); nvlist_add_number(nvl, "proto", r->proto); + nvlist_add_string(nvl, "match_tagname", r->match_tagname); + nvlist_add_bool(nvl, "match_tag_not", r->match_tag_not); addr = pfctl_eth_addr_to_nveth_addr(&r->src); if (addr == NULL) { diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h index ab4b6a27c787..261913e1873d 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -94,6 +94,9 @@ struct pfctl_eth_rule { uint16_t proto; struct pfctl_eth_addr src, dst; struct pf_rule_addr ipsrc, ipdst; + char match_tagname[PF_TAG_NAME_SIZE]; + uint16_t match_tag; + bool match_tag_not; /* Stats */ uint64_t evaluations; diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 21729fc7ba4e..506716bca689 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1197,6 +1197,14 @@ etherrule : ETHER action dir quick interface etherproto etherfromto l3fromto eth r.quick = $4.quick; if ($9.tag != NULL) memcpy(&r.tagname, $9.tag, sizeof(r.tagname)); + if ($9.match_tag) + if (strlcpy(r.match_tagname, $9.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = $9.match_tag_not; if ($9.queues.qname != NULL) memcpy(&r.qname, $9.queues.qname, sizeof(r.qname)); r.dnpipe = $9.dnpipe; @@ -1320,6 +1328,10 @@ etherfilter_opt : etherqname { | TAG string { filter_opts.tag = $2; } + | not TAGGED string { + filter_opts.match_tag = $3; + filter_opts.match_tag_not = $1; + } | DNPIPE number { filter_opts.dnpipe = $2; filter_opts.free_flags |= PFRULE_DN_IS_PIPE; @@ -5772,6 +5784,18 @@ expand_eth_rule(struct pfctl_eth_rule *r, struct node_mac *srcs, struct node_mac *dsts, struct node_host *ipsrcs, struct node_host *ipdsts, const char *anchor_call) { + char tagname[PF_TAG_NAME_SIZE]; + char match_tagname[PF_TAG_NAME_SIZE]; + char qname[PF_QNAME_SIZE]; + + if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) + errx(1, "expand_eth_rule: tagname"); + if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= + sizeof(match_tagname)) + errx(1, "expand_eth_rule: match_tagname"); + if (strlcpy(qname, r->qname, sizeof(qname)) >= sizeof(qname)) + errx(1, "expand_eth_rule: qname"); + LOOP_THROUGH(struct node_if, interface, interfaces, LOOP_THROUGH(struct node_etherproto, proto, protos, LOOP_THROUGH(struct node_mac, src, srcs, @@ -5800,6 +5824,15 @@ expand_eth_rule(struct pfctl_eth_rule *r, r->dst.isset = dst->isset; r->nr = pf->eastack[pf->asd]->match++; + if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= + sizeof(r->tagname)) + errx(1, "expand_eth_rule: r->tagname"); + if (strlcpy(r->match_tagname, match_tagname, + sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) + errx(1, "expand_eth_rule: r->match_tagname"); + if (strlcpy(r->qname, qname, sizeof(r->qname)) >= sizeof(r->qname)) + errx(1, "expand_eth_rule: r->qname"); + pfctl_append_eth_rule(pf, r, anchor_call); )))))); diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 1f6a194591c0..a05683f0cbce 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -791,6 +791,11 @@ print_eth_rule(struct pfctl_eth_rule *r, const char *anchor_call, printf(" queue %s", r->qname); if (r->tagname[0]) printf(" tag %s", r->tagname); + if (r->match_tagname[0]) { + if (r->match_tag_not) + printf(" !"); + printf(" tagged %s", r->match_tagname); + } if (r->dnpipe) printf(" %s %d", r->dnflags & PFRULE_DN_IS_PIPE ? "dnpipe" : "dnqueue", diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5 index d136d9887cd5..267d84387fe9 100644 --- a/share/man/man5/pf.conf.5 +++ b/share/man/man5/pf.conf.5 @@ -744,6 +744,11 @@ is not the last matching rule. Further matching rules can replace the tag with a new one but will not remove a previously applied tag. A packet is only ever assigned one tag at a time. +.It Ar tagged Aq Ar string +Used to specify that packets must already be tagged with the given tag in order +to match the rule. +Inverse tag matching can also be done by specifying the ! operator before the +tagged keyword. .Sh TRAFFIC NORMALIZATION Traffic normalization is used to sanitize packet content in such a way that there are no ambiguities in packet interpretation on @@ -3083,7 +3088,7 @@ logopts = logopt [ "," logopts ] logopt = "all" | "user" | "to" interface-name etherfilteropt-list = etherfilteropt-list etherfilteropt | etherfilteropt -etherfilteropt = "tag" string | "queue" ( string ) +etherfilteropt = "tag" string | "tagged" string | "queue" ( string ) filteropt-list = filteropt-list filteropt | filteropt filteropt = user | group | flags | icmp-type | icmp6-type | "tos" tos | diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 4ad758fe439b..ef30058966dc 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -672,6 +672,10 @@ struct pf_keth_rule { uint16_t proto; struct pf_keth_rule_addr src, dst; struct pf_rule_addr ipsrc, ipdst; + char match_tagname[PF_TAG_NAME_SIZE]; + uint16_t match_tag; + bool match_tag_not; + /* Stats */ counter_u64_t evaluations; diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 8e3cd98879a6..172ed52dbc03 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -3835,6 +3835,16 @@ pf_match_eth_addr(const uint8_t *a, const struct pf_keth_rule_addr *r) return (match ^ r->neg); } +static int +pf_match_eth_tag(struct mbuf *m, struct pf_keth_rule *r, int *tag, int mtag) +{ + if (*tag == -1) + *tag = mtag; + + return ((!r->match_tag_not && r->match_tag == *tag) || + (r->match_tag_not && r->match_tag != *tag)); +} + static int pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) { @@ -3848,6 +3858,7 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) sa_family_t af = 0; uint16_t proto; int asd = 0, match = 0; + int tag = -1; uint8_t action; struct pf_keth_anchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; @@ -3959,7 +3970,15 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) "ip_dst"); r = TAILQ_NEXT(r, entries); } + else if (r->match_tag && !pf_match_eth_tag(m, r, &tag, + mtag ? mtag->tag : 0)) { + SDT_PROBE3(pf, eth, test_rule, mismatch, r->nr, r, + "match_tag"); + r = TAILQ_NEXT(r, entries); + } else { + if (r->tag) + tag = r->tag; if (r->anchor == NULL) { /* Rule matches */ rm = r; @@ -4001,7 +4020,7 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) return (PF_DROP); } - if (r->tag > 0) { + if (tag > 0) { if (mtag == NULL) mtag = pf_get_mtag(m); if (mtag == NULL) { @@ -4009,7 +4028,7 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1); return (PF_DROP); } - mtag->tag = r->tag; + mtag->tag = tag; } if (r->qid != 0) { diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 1ccbbd3814ac..c07df7e6c05e 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -515,6 +515,8 @@ pf_free_eth_rule(struct pf_keth_rule *rule) if (rule->tag) tag_unref(&V_pf_tags, rule->tag); + if (rule->match_tag) + tag_unref(&V_pf_tags, rule->match_tag); #ifdef ALTQ pf_qid_unref(rule->qid); #endif @@ -2891,6 +2893,10 @@ DIOCGETETHRULE_error: if (rule->tagname[0]) if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0) error = EBUSY; + if (rule->match_tagname[0]) + if ((rule->match_tag = pf_tagname2tag( + rule->match_tagname)) == 0) + error = EBUSY; if (error == 0 && rule->ipdst.addr.type == PF_ADDR_TABLE) error = pf_eth_addr_setup(ruleset, &rule->ipdst.addr); diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c index 5476b59d859f..456433ccbf70 100644 --- a/sys/netpfil/pf/pf_nv.c +++ b/sys/netpfil/pf/pf_nv.c @@ -1057,6 +1057,9 @@ pf_keth_rule_to_nveth_rule(const struct pf_keth_rule *krule) nvlist_add_bool(nvl, "ifnot", krule->ifnot); nvlist_add_number(nvl, "direction", krule->direction); nvlist_add_number(nvl, "proto", krule->proto); + nvlist_add_string(nvl, "match_tagname", krule->match_tagname); + nvlist_add_number(nvl, "match_tag", krule->match_tag); + nvlist_add_bool(nvl, "match_tag_not", krule->match_tag_not); addr = pf_keth_rule_addr_to_nveth_rule_addr(&krule->src); if (addr == NULL) { @@ -1165,6 +1168,12 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl, return (EINVAL); } + if (nvlist_exists_string(nvl, "match_tagname")) { + PFNV_CHK(pf_nvstring(nvl, "match_tagname", krule->match_tagname, + sizeof(krule->match_tagname))); + PFNV_CHK(pf_nvbool(nvl, "match_tag_not", &krule->match_tag_not)); + } + PFNV_CHK(pf_nvstring(nvl, "qname", krule->qname, sizeof(krule->qname))); PFNV_CHK(pf_nvstring(nvl, "tagname", krule->tagname, sizeof(krule->tagname)));