git: 9925aee0aaec - main - pf: carry over rule actions from route-to rules

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 02 Jun 2023 14:56:30 UTC
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=9925aee0aaeccabd26f41625694a97b64185a59d

commit 9925aee0aaeccabd26f41625694a97b64185a59d
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-05-30 19:17:54 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-06-02 14:05:30 +0000

    pf: carry over rule actions from route-to rules
    
    If we route-to (or dup-to/reply-to) we re-run pf_test(), which will also
    create states for the connection.
    This means that we may end up matching a different (i.e. not the state
    that was created by the route-to rule) state, without the attributes
    (such as dummynet pipes/queues) set by the route-to rule.
    
    Address this by inheriting the pf_rule_actions from the route-to rule
    while evaluating the connection again in pf_test(). That is, we set
    default pf_rule_actions based on the route-to rule for the new
    evaluation. The new rule may still overrule these, but if it does not
    have such actions the route-to actions are applied.
    
    Do the same for IPv6 rules in pf_test6()/pf_route6().
    
    See also:       https://redmine.pfsense.org/issues/14039
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D40340
---
 sys/net/pfvar.h           |  6 ++++--
 sys/netpfil/pf/pf.c       | 16 +++++++++++-----
 sys/netpfil/pf/pf_ioctl.c |  9 +++++----
 3 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 2f2cc1632edc..a658573cf6f1 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -2230,13 +2230,15 @@ void				pf_free_rule(struct pf_krule *);
 
 int	pf_test_eth(int, int, struct ifnet *, struct mbuf **, struct inpcb *);
 #ifdef INET
-int	pf_test(int, int, struct ifnet *, struct mbuf **, struct inpcb *);
+int	pf_test(int, int, struct ifnet *, struct mbuf **, struct inpcb *,
+	    struct pf_rule_actions *);
 int	pf_normalize_ip(struct mbuf **, int, struct pfi_kkif *, u_short *,
 	    struct pf_pdesc *);
 #endif /* INET */
 
 #ifdef INET6
-int	pf_test6(int, int, struct ifnet *, struct mbuf **, struct inpcb *);
+int	pf_test6(int, int, struct ifnet *, struct mbuf **, struct inpcb *,
+	    struct pf_rule_actions *);
 int	pf_normalize_ip6(struct mbuf **, int, struct pfi_kkif *, u_short *,
 	    struct pf_pdesc *);
 void	pf_poolmask(struct pf_addr *, struct pf_addr*,
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 75c58609318c..78bd8b1dab12 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -6546,7 +6546,7 @@ pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
 		goto bad;
 
 	if (dir == PF_IN) {
-		if (pf_test(PF_OUT, 0, ifp, &m0, inp) != PF_PASS)
+		if (pf_test(PF_OUT, 0, ifp, &m0, inp, &pd->act) != PF_PASS)
 			goto bad;
 		else if (m0 == NULL)
 			goto done;
@@ -6762,7 +6762,7 @@ pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
 		goto bad;
 
 	if (dir == PF_IN) {
-		if (pf_test6(PF_OUT, 0, ifp, &m0, inp) != PF_PASS)
+		if (pf_test6(PF_OUT, 0, ifp, &m0, inp, &pd->act) != PF_PASS)
 			goto bad;
 		else if (m0 == NULL)
 			goto done;
@@ -7120,7 +7120,8 @@ pf_dummynet_route(struct pf_pdesc *pd, int dir, struct pf_kstate *s,
 
 #ifdef INET
 int
-pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
+pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
+    struct inpcb *inp, struct pf_rule_actions *default_actions)
 {
 	struct pfi_kkif		*kif;
 	u_short			 action, reason = 0, log = 0;
@@ -7172,6 +7173,8 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *
 	}
 
 	memset(&pd, 0, sizeof(pd));
+	if (default_actions != NULL)
+		memcpy(&pd.act, default_actions, sizeof(pd.act));
 	pd.pf_mtag = pf_find_mtag(m);
 
 	if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_TAG_ROUTE_TO)) {
@@ -7312,7 +7315,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *
 					break;
 				}
 
-				action = pf_test(dir, pflags, ifp, &msyn, inp);
+				action = pf_test(dir, pflags, ifp, &msyn, inp, &pd.act);
 				m_freem(msyn);
 
 				if (action == PF_PASS) {
@@ -7682,7 +7685,8 @@ done:
 
 #ifdef INET6
 int
-pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
+pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp,
+    struct pf_rule_actions *default_actions)
 {
 	struct pfi_kkif		*kif;
 	u_short			 action, reason = 0, log = 0;
@@ -7733,6 +7737,8 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 	}
 
 	memset(&pd, 0, sizeof(pd));
+	if (default_actions != NULL)
+		memcpy(&pd.act, default_actions, sizeof(pd.act));
 	pd.pf_mtag = pf_find_mtag(m);
 
 	if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_TAG_ROUTE_TO)) {
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index db88c7d2dc0e..cb6d22885ef4 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -6534,7 +6534,7 @@ pf_check_in(struct mbuf **m, struct ifnet *ifp, int flags,
 {
 	int chk;
 
-	chk = pf_test(PF_IN, flags, ifp, m, inp);
+	chk = pf_test(PF_IN, flags, ifp, m, inp, NULL);
 
 	return (pf_check_return(chk, m));
 }
@@ -6545,7 +6545,7 @@ pf_check_out(struct mbuf **m, struct ifnet *ifp, int flags,
 {
 	int chk;
 
-	chk = pf_test(PF_OUT, flags, ifp, m, inp);
+	chk = pf_test(PF_OUT, flags, ifp, m, inp, NULL);
 
 	return (pf_check_return(chk, m));
 }
@@ -6564,7 +6564,8 @@ pf_check6_in(struct mbuf **m, struct ifnet *ifp, int flags,
 	 * filtering we have change this to lo0 as it is the case in IPv4.
 	 */
 	CURVNET_SET(ifp->if_vnet);
-	chk = pf_test6(PF_IN, flags, (*m)->m_flags & M_LOOP ? V_loif : ifp, m, inp);
+	chk = pf_test6(PF_IN, flags, (*m)->m_flags & M_LOOP ? V_loif : ifp,
+	    m, inp, NULL);
 	CURVNET_RESTORE();
 
 	return (pf_check_return(chk, m));
@@ -6577,7 +6578,7 @@ pf_check6_out(struct mbuf **m, struct ifnet *ifp, int flags,
 	int chk;
 
 	CURVNET_SET(ifp->if_vnet);
-	chk = pf_test6(PF_OUT, flags, ifp, m, inp);
+	chk = pf_test6(PF_OUT, flags, ifp, m, inp, NULL);
 	CURVNET_RESTORE();
 
 	return (pf_check_return(chk, m));