Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 2 Nov 2022 14:51:30 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: 8a8af9424008 - main - pf: bridge-to
Message-ID:  <202211021451.2A2EpUJo075240@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=8a8af94240084a091a1c048da027f80ee37937e7

commit 8a8af94240084a091a1c048da027f80ee37937e7
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2022-09-22 17:00:11 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2022-11-02 14:45:23 +0000

    pf: bridge-to
    
    Allow pf (l2) to be used to redirect ethernet packets to a different
    interface.
    
    The intended use case is to send 802.1x challenges out to a side
    interface, to enable AT&T links to function with pfSense as a gateway,
    rather than the AT&T provided hardware.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D37193
---
 lib/libpfctl/libpfctl.c   |  5 +++++
 lib/libpfctl/libpfctl.h   |  1 +
 sbin/pfctl/parse.y        | 48 +++++++++++++++++++++++++++++++----------------
 sbin/pfctl/pfctl_parser.c |  2 ++
 share/man/man5/pf.conf.5  | 10 +++++++---
 sys/net/pfvar.h           |  2 ++
 sys/netpfil/pf/pf.c       | 31 ++++++++++++++++++++++++++++++
 sys/netpfil/pf/pf_ioctl.c | 12 +++++++++++-
 sys/netpfil/pf/pf_nv.c    |  3 +++
 9 files changed, 94 insertions(+), 20 deletions(-)

diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 451567402470..f95f79024bf5 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -665,6 +665,9 @@ pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule)
 	rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative");
 	rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard");
 
+	strlcpy(rule->bridge_to, nvlist_get_string(nvl, "bridge_to"),
+	    IFNAMSIZ);
+
 	rule->action = nvlist_get_number(nvl, "action");
 }
 
@@ -812,6 +815,8 @@ pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor,
 	nvlist_add_number(nvl, "dnpipe", r->dnpipe);
 	nvlist_add_number(nvl, "dnflags", r->dnflags);
 
+	nvlist_add_string(nvl, "bridge_to", r->bridge_to);
+
 	nvlist_add_number(nvl, "action", r->action);
 
 	packed = nvlist_pack(nvl, &size);
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index 933a3927ac26..684e73c1815d 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -110,6 +110,7 @@ struct pfctl_eth_rule {
 	char			 tagname[PF_TAG_NAME_SIZE];
 	uint16_t		 dnpipe;
 	uint32_t		 dnflags;
+	char			 bridge_to[IFNAMSIZ];
 	uint8_t			 action;
 
 	struct pfctl_eth_anchor	*anchor;
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index eea9f89782be..1d0494e6d0b9 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -351,7 +351,8 @@ void		 expand_label_nr(const char *, char *, size_t,
 void		 expand_eth_rule(struct pfctl_eth_rule *,
 		    struct node_if *, struct node_etherproto *,
 		    struct node_mac *, struct node_mac *,
-		    struct node_host *, struct node_host *, const char *);
+		    struct node_host *, struct node_host *, const char *,
+		    const char *);
 void		 expand_rule(struct pfctl_rule *, struct node_if *,
 		    struct node_host *, struct node_proto *, struct node_os *,
 		    struct node_host *, struct node_port *, struct node_host *,
@@ -432,6 +433,7 @@ typedef struct {
 		struct {
 			struct node_mac	*mac;
 		} etheraddr;
+		char			*bridge_to;
 		struct {
 			struct node_host	*host;
 			u_int8_t		 rt;
@@ -503,7 +505,7 @@ int	parseport(char *, struct range *r, int);
 %token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
 %token	MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
 %token	TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
-%token	DIVERTTO DIVERTREPLY
+%token	DIVERTTO DIVERTREPLY BRIDGE_TO
 %token	<v.string>		STRING
 %token	<v.number>		NUMBER
 %token	<v.i>			PORTBINARY
@@ -563,6 +565,7 @@ int	parseport(char *, struct range *r, int);
 %type	<v.etherproto>		etherproto etherproto_list etherproto_item
 %type	<v.etherfromto>		etherfromto
 %type	<v.etheraddr>		etherfrom etherto
+%type	<v.bridge_to>		bridge
 %type	<v.mac>			xmac mac mac_list macspec
 %%
 
@@ -1195,7 +1198,7 @@ scrubaction	: no SCRUB {
 		}
 		;
 
-etherrule	: ETHER action dir quick interface etherproto etherfromto l3fromto etherfilter_opts
+etherrule	: ETHER action dir quick interface bridge etherproto etherfromto l3fromto etherfilter_opts
 		{
 			struct pfctl_eth_rule	r;
 
@@ -1207,23 +1210,23 @@ etherrule	: ETHER action dir quick interface etherproto etherfromto l3fromto eth
 			r.action = $2.b1;
 			r.direction = $3;
 			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,
+			if ($10.tag != NULL)
+				memcpy(&r.tagname, $10.tag, sizeof(r.tagname));
+			if ($10.match_tag)
+				if (strlcpy(r.match_tagname, $10.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;
-			r.dnflags = $9.free_flags;
+			r.match_tag_not = $10.match_tag_not;
+			if ($10.queues.qname != NULL)
+				memcpy(&r.qname, $10.queues.qname, sizeof(r.qname));
+			r.dnpipe = $10.dnpipe;
+			r.dnflags = $10.free_flags;
 
-			expand_eth_rule(&r, $5, $6, $7.src, $7.dst,
-			    $8.src.host, $8.dst.host, "");
+			expand_eth_rule(&r, $5, $7, $8.src, $8.dst,
+			    $9.src.host, $9.dst.host, $6, "");
 		}
 		;
 
@@ -1315,7 +1318,7 @@ etheranchorrule	: ETHER ANCHOR anchorname dir quick interface etherproto etherfr
 			r.quick = $5.quick;
 
 			expand_eth_rule(&r, $6, $7, $8.src, $8.dst,
-			    $9.src.host, $9.dst.host,
+			    $9.src.host, $9.dst.host, NULL,
 			    pf->eastack[pf->asd + 1] ? pf->ealast->name : $3);
 
 			free($3);
@@ -1361,6 +1364,14 @@ etherfilter_opt	: etherqname	{
 		}
 		;
 
+bridge		:	/* empty */		{
+			$$ = NULL;
+		}
+		| BRIDGE_TO STRING {
+			$$ = strdup($2);
+		}
+		;
+
 scrubrule	: scrubaction dir logquick interface af proto fromto scrub_opts
 		{
 			struct pfctl_rule	r;
@@ -5801,7 +5812,8 @@ void
 expand_eth_rule(struct pfctl_eth_rule *r,
     struct node_if *interfaces, struct node_etherproto *protos,
     struct node_mac *srcs, struct node_mac *dsts,
-    struct node_host *ipsrcs, struct node_host *ipdsts, const char *anchor_call)
+    struct node_host *ipsrcs, struct node_host *ipdsts,
+    const char *bridge_to, const char *anchor_call)
 {
 	char tagname[PF_TAG_NAME_SIZE];
 	char match_tagname[PF_TAG_NAME_SIZE];
@@ -5852,6 +5864,9 @@ expand_eth_rule(struct pfctl_eth_rule *r,
 		if (strlcpy(r->qname, qname, sizeof(r->qname)) >= sizeof(r->qname))
 			errx(1, "expand_eth_rule: r->qname");
 
+		if (bridge_to)
+			strlcpy(r->bridge_to, bridge_to, sizeof(r->bridge_to));
+
 		pfctl_append_eth_rule(pf, r, anchor_call);
 	))))));
 
@@ -6110,6 +6125,7 @@ lookup(char *s)
 		{ "bitmask",		BITMASK},
 		{ "block",		BLOCK},
 		{ "block-policy",	BLOCKPOLICY},
+		{ "bridge-to",		BRIDGE_TO},
 		{ "buckets",		BUCKETS},
 		{ "cbq",		CBQ},
 		{ "code",		CODE},
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 1ad895bede05..824e473ea2e9 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -774,6 +774,8 @@ print_eth_rule(struct pfctl_eth_rule *r, const char *anchor_call,
 		else
 			printf(" on %s", r->ifname);
 	}
+	if (r->bridge_to[0])
+		printf(" bridge-to %s", r->bridge_to);
 	if (r->proto)
 		printf(" proto 0x%04x", r->proto);
 
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index 267d84387fe9..ed57ad5b1c9f 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -28,7 +28,7 @@
 .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd March 9, 2022
+.Dd October 28, 2022
 .Dt PF.CONF 5
 .Os
 .Sh NAME
@@ -710,6 +710,9 @@ see the
 .Ic group
 keyword in
 .Xr ifconfig 8 .
+.It Ar bridge-to Aq interface
+Packets matching this rule will be sent out of the specified interface without
+futher processing.
 .It Ar proto Aq Ar protocol
 This rule applies only to packets of this protocol.
 Note that Ethernet protocol numbers are different from those used in
@@ -3076,8 +3079,9 @@ option         = "set" ( [ "timeout" ( timeout | "{" timeout-list "}" ) ] |
                  [ "keepcounters" ] )
 
 ether-rule     = "ether" etheraction [ ( "in" | "out" ) ]
-                 [ "quick" ] [ "on" ifspec ] [ etherprotospec ]
-                 etherhosts [ "l3" hosts ] [ etherfilteropt-list ]
+                 [ "quick" ] [ "on" ifspec ] [ "bridge-to" interface-name ]
+                 [ etherprotospec ] etherhosts [ "l3" hosts ]
+                 [ etherfilteropt-list ]
 
 pf-rule        = action [ ( "in" | "out" ) ]
                  [ "log" [ "(" logopts ")"] ] [ "quick" ]
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 3773a797776d..f08ef0d0bfa0 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -690,6 +690,8 @@ struct pf_keth_rule {
 	int			 qid;
 	char			 tagname[PF_TAG_NAME_SIZE];
 	uint16_t		 tag;
+	char			 bridge_to_name[IFNAMSIZ];
+	struct pfi_kkif		*bridge_to;
 	uint8_t			 action;
 	uint16_t		 dnpipe;
 	uint32_t		 dnflags;
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 698e0588c1db..c0c34fba0409 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -3833,6 +3833,32 @@ pf_match_eth_tag(struct mbuf *m, struct pf_keth_rule *r, int *tag, int mtag)
 	    (r->match_tag_not && r->match_tag != *tag));
 }
 
+static void
+pf_bridge_to(struct pfi_kkif *kif, struct mbuf *m)
+{
+	struct ifnet *ifp = kif->pfik_ifp;
+
+	/* If we don't have the interface drop the packet. */
+	if (ifp == NULL) {
+		m_freem(m);
+		return;
+	}
+
+	switch (ifp->if_type) {
+	case IFT_ETHER:
+	case IFT_XETHER:
+	case IFT_L2VLAN:
+	case IFT_BRIDGE:
+	case IFT_IEEE8023ADLAG:
+		break;
+	default:
+		m_freem(m);
+		return;
+	}
+
+	kif->pfik_ifp->if_transmit(kif->pfik_ifp, m);
+}
+
 static int
 pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
 {
@@ -4092,6 +4118,11 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
 
 	action = r->action;
 
+	if (action == PF_PASS && r->bridge_to) {
+		pf_bridge_to(r->bridge_to, *m0);
+		*m0 = NULL; /* We've eaten the packet. */
+	}
+
 	PF_RULES_RUNLOCK();
 
 	return (action);
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index c1a098ff887f..5f702f08929e 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -522,6 +522,8 @@ pf_free_eth_rule(struct pf_keth_rule *rule)
 	pf_qid_unref(rule->qid);
 #endif
 
+	if (rule->bridge_to)
+		pfi_kkif_unref(rule->bridge_to);
 	if (rule->kif)
 		pfi_kkif_unref(rule->kif);
 
@@ -2809,7 +2811,7 @@ DIOCGETETHRULE_error:
 		void			*nvlpacked = NULL;
 		struct pf_keth_rule	*rule = NULL, *tail = NULL;
 		struct pf_keth_ruleset	*ruleset = NULL;
-		struct pfi_kkif		*kif = NULL;
+		struct pfi_kkif		*kif = NULL, *bridge_to_kif = NULL;
 		const char		*anchor = "", *anchor_call = "";
 
 #define ERROUT(x)	ERROUT_IOCTL(DIOCADDETHRULE_error, x)
@@ -2861,6 +2863,8 @@ DIOCGETETHRULE_error:
 
 		if (rule->ifname[0])
 			kif = pf_kkif_create(M_WAITOK);
+		if (rule->bridge_to_name[0])
+			bridge_to_kif = pf_kkif_create(M_WAITOK);
 		rule->evaluations = counter_u64_alloc(M_WAITOK);
 		for (int i = 0; i < 2; i++) {
 			rule->packets[i] = counter_u64_alloc(M_WAITOK);
@@ -2876,6 +2880,12 @@ DIOCGETETHRULE_error:
 			pfi_kkif_ref(rule->kif);
 		} else
 			rule->kif = NULL;
+		if (rule->bridge_to_name[0]) {
+			rule->bridge_to = pfi_kkif_attach(bridge_to_kif,
+			    rule->bridge_to_name);
+			pfi_kkif_ref(rule->bridge_to);
+		} else
+			rule->bridge_to = NULL;
 
 #ifdef ALTQ
 		/* set queue IDs */
diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c
index 18495c118e75..544477407861 100644
--- a/sys/netpfil/pf/pf_nv.c
+++ b/sys/netpfil/pf/pf_nv.c
@@ -1114,6 +1114,7 @@ pf_keth_rule_to_nveth_rule(const struct pf_keth_rule *krule)
 	nvlist_add_number(nvl, "anchor_relative", krule->anchor_relative);
 	nvlist_add_number(nvl, "anchor_wildcard", krule->anchor_wildcard);
 
+	nvlist_add_string(nvl, "bridge_to", krule->bridge_to_name);
 	nvlist_add_number(nvl, "action", krule->action);
 
 	return (nvl);
@@ -1182,6 +1183,8 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl,
 
 	PFNV_CHK(pf_nvuint16_opt(nvl, "dnpipe", &krule->dnpipe, 0));
 	PFNV_CHK(pf_nvuint32_opt(nvl, "dnflags", &krule->dnflags, 0));
+	PFNV_CHK(pf_nvstring(nvl, "bridge_to", krule->bridge_to_name,
+	    sizeof(krule->bridge_to_name)));
 
 	PFNV_CHK(pf_nvuint8(nvl, "action", &krule->action));
 



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