The branch main has been updated by kp:

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

commit f88019e8a35c05b61b5722e4b98cd7b5cca167f7
Author:     Kristof Provost <k...@freebsd.org>
AuthorDate: 2025-01-07 11:12:12 +0000
Commit:     Kristof Provost <k...@freebsd.org>
CommitDate: 2025-01-14 08:54:17 +0000

    pf: fixup af-to regression with match rules
    
    pfctl should not infer the af-to behavior from the af/naf difference.
    instead, we should be clear that this is an af-to rule.  essentially
    this change converts FOM_AFTO marker into a rule flag PFRULE_AFTO so
    that we don't rely on ambiguous checks (like r->af != r->naf) when
    setting things up.
    
    positive review and comments from claudio, ok henning, sperreault
    
    Obtained from:  OpenBSD, mikeb <mi...@openbsd.org>, fc302162c0
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sbin/pfctl/parse.y        | 36 +++++++++++++++++++++---------------
 sbin/pfctl/pfctl_parser.c |  2 +-
 sys/netpfil/pf/pf.c       |  4 ++--
 sys/netpfil/pf/pf.h       |  1 +
 4 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 63bee3ab6a1c..3c34b0237895 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -382,7 +382,7 @@ void                 expand_eth_rule(struct pfctl_eth_rule 
*,
                    struct node_host *, struct node_host *, const char *,
                    const char *);
 void            expand_rule(struct pfctl_rule *, struct node_if *,
-                   struct node_host *,
+                   struct redirspec *, struct redirspec *, struct node_host *,
                    struct node_host *, struct node_proto *, struct node_os *,
                    struct node_host *, struct node_port *, struct node_host *,
                    struct node_port *, struct node_uid *, struct node_gid *,
@@ -1079,9 +1079,8 @@ anchorrule        : ANCHOR anchorname dir quick interface 
af proto fromto
 
                        decide_address_family($8.src.host, &r.af);
                        decide_address_family($8.dst.host, &r.af);
-                       r.naf = r.af;
 
-                       expand_rule(&r, $5, NULL, NULL, $7, $8.src_os,
+                       expand_rule(&r, $5, NULL, NULL, NULL, NULL, $7, 
$8.src_os,
                            $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
                            $9.uid, $9.gid, $9.rcv, $9.icmpspec,
                            pf->astack[pf->asd + 1] ? pf->alast->name : $2);
@@ -1104,7 +1103,7 @@ anchorrule        : ANCHOR anchorname dir quick interface 
af proto fromto
                        decide_address_family($6.src.host, &r.af);
                        decide_address_family($6.dst.host, &r.af);
 
-                       expand_rule(&r, $3, NULL, NULL, $5, $6.src_os,
+                       expand_rule(&r, $3, NULL, NULL, NULL, NULL, $5, 
$6.src_os,
                            $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
                            0, 0, 0, 0, $2);
                        free($2);
@@ -1146,7 +1145,7 @@ anchorrule        : ANCHOR anchorname dir quick interface 
af proto fromto
                                r.dst.port_op = $6.dst.port->op;
                        }
 
-                       expand_rule(&r, $3, NULL, NULL, $5, $6.src_os,
+                       expand_rule(&r, $3, NULL, NULL, NULL, NULL, $5, 
$6.src_os,
                            $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
                            0, 0, 0, 0, $2);
                        free($2);
@@ -1469,7 +1468,7 @@ scrubrule : scrubaction dir logquick interface af proto 
fromto scrub_opts
                        r.match_tag_not = $8.match_tag_not;
                        r.rtableid = $8.rtableid;
 
-                       expand_rule(&r, $4, NULL, NULL, $6, $7.src_os,
+                       expand_rule(&r, $4, NULL, NULL, NULL, NULL, $6, 
$7.src_os,
                            $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
                            NULL, NULL, NULL, NULL, "");
                }
@@ -1634,7 +1633,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af 
antispoof_opts {
                                }
 
                                if (h != NULL)
-                                       expand_rule(&r, j, NULL, NULL, NULL, 
NULL, h,
+                                       expand_rule(&r, j, NULL, NULL, NULL, 
NULL, NULL, NULL, h,
                                            NULL, NULL, NULL, NULL, NULL,
                                            NULL, NULL, "");
 
@@ -1656,7 +1655,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af 
antispoof_opts {
                                        else
                                                h = ifa_lookup(i->ifname, 0);
                                        if (h != NULL)
-                                               expand_rule(&r, NULL, NULL, 
NULL,
+                                               expand_rule(&r, NULL, NULL, 
NULL, NULL, NULL,
                                                    NULL, NULL, h, NULL, NULL,
                                                    NULL, NULL, NULL, NULL, 
NULL, "");
                                } else
@@ -2434,6 +2433,7 @@ pfrule            : action dir logquick interface route 
af proto fromto
                                            "translation");
                                        YYERROR;
                                }
+                               r.rule_flag |= PFRULE_AFTO;
                        }
 
                        r.af = $6;
@@ -2721,7 +2721,6 @@ pfrule            : action dir logquick interface route 
af proto fromto
 
                        decide_address_family($8.src.host, &r.af);
                        decide_address_family($8.dst.host, &r.af);
-                       r.naf = r.af;
 
                        if ($5.rt) {
                                if (!r.direction) {
@@ -2837,7 +2836,7 @@ pfrule            : action dir logquick interface route 
af proto fromto
                                        YYERROR;
                        }
 
-                       expand_rule(&r, $4, $5.host, $9.nat.rdr ? 
$9.nat.rdr->host : NULL,
+                       expand_rule(&r, $4, &$9.nat, &$9.rdr, $5.host, 
$9.nat.rdr ? $9.nat.rdr->host : NULL,
                            $7, $8.src_os, $8.src.host, $8.src.port, 
$8.dst.host,
                            $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec, 
"");
                }
@@ -4985,8 +4984,8 @@ natrule           : nataction interface af proto fromto 
tag tagged rtable
                                o = o->next;
                        }
 
-                       expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, NULL, 
$4,
-                           $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
+                       expand_rule(&r, $2, NULL, NULL, $9 == NULL ? NULL : 
$9->host,
+                           NULL, $4, $5.src_os, $5.src.host, $5.src.port, 
$5.dst.host,
                            $5.dst.port, 0, 0, 0, 0, "");
                        free($9);
                }
@@ -5501,7 +5500,7 @@ filter_consistent(struct pfctl_rule *r, int anchor_call)
                           "must not be used on match rules");
                        problems++;
                }
-               if (r->naf != r->af) {
+               if (r->rule_flag & PFRULE_AFTO) {
                        yyerror("af-to is not supported on match rules");
                        problems++;
                }
@@ -6139,7 +6138,8 @@ expand_eth_rule(struct pfctl_eth_rule *r,
 
 void
 expand_rule(struct pfctl_rule *r,
-    struct node_if *interfaces, struct node_host *rdr_hosts,
+    struct node_if *interfaces, struct redirspec *nat,
+    struct redirspec *rdr, struct node_host *rdr_hosts,
     struct node_host *nat_hosts,
     struct node_proto *protos, struct node_os *src_oses,
     struct node_host *src_hosts, struct node_port *src_ports,
@@ -6179,7 +6179,13 @@ expand_rule(struct pfctl_rule *r,
        LOOP_THROUGH(struct node_uid, uid, uids,
        LOOP_THROUGH(struct node_gid, gid, gids,
 
-               r->af = af;
+               r->naf = r->af = af;
+
+               if (r->rule_flag & PFRULE_AFTO) {
+                       assert(nat != NULL);
+                       r->naf = nat->af;
+               }
+
                /* for link-local IPv6 address, interface must match up */
                if ((r->af && src_host->af && r->af != src_host->af) ||
                    (r->af && dst_host->af && r->af != dst_host->af) ||
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 741915d41b0d..af10bdcf7e4b 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1238,7 +1238,7 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, 
int verbose, int numer
 #endif
        }
        if (!anchor_call[0] && ! TAILQ_EMPTY(&r->nat.list) &&
-           r->naf != r->af) {
+           r->rule_flag & PFRULE_AFTO) {
                printf(" af-to %s from ", r->naf == AF_INET ? "inet" : "inet6");
                print_pool(&r->nat, r->nat.proxy_port[0], r->nat.proxy_port[1],
                    r->naf ? r->naf : r->af, PF_NAT);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 335b192d454d..dd337c0aef93 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -5802,7 +5802,7 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
                                pf_counter_u64_add_protected(&r->bytes[pd->dir 
== PF_OUT], pd->tot_len);
                                pf_counter_u64_critical_exit();
                                pf_rule_to_actions(r, &pd->act);
-                               if (r->naf)
+                               if (r->rule_flag & PFRULE_AFTO)
                                        pd->naf = r->naf;
                                if (pd->af != pd->naf) {
                                        if (pf_get_transaddr_af(r, pd) == -1) {
@@ -5842,7 +5842,7 @@ nextrule:
 
        /* apply actions for last matching pass/block rule */
        pf_rule_to_actions(r, &pd->act);
-       if (r->naf)
+       if (r->rule_flag & PFRULE_AFTO)
                pd->naf = r->naf;
        if (pd->af != pd->naf) {
                if (pf_get_transaddr_af(r, pd) == -1) {
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index 0d4d0a6a6f32..10431d9b77d9 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -617,6 +617,7 @@ struct pf_rule {
 #define        PFRULE_IFBOUND          0x00010000 /* if-bound */
 #define        PFRULE_STATESLOPPY      0x00020000 /* sloppy state tracking */
 #define        PFRULE_PFLOW            0x00040000
+#define        PFRULE_AFTO             0x00200000  /* af-to rule */
 
 #ifdef _KERNEL
 #define        PFRULE_REFS             0x0080  /* rule has references */

Reply via email to