diff options
author | Kristof Provost <kp@FreeBSD.org> | 2024-11-15 15:29:54 +0000 |
---|---|---|
committer | Kristof Provost <kp@FreeBSD.org> | 2024-12-17 10:07:16 +0000 |
commit | c6210cfd58f6a570786106f35ebbe1c49f48287c (patch) | |
tree | 86778d93d4d881c6d74fcce9341731448aa57ee3 | |
parent | d7e9df4fc67f2ffaeafe0f130d67eb0f112a0858 (diff) |
pf: fix if-bound with nat64
Just as with reply-to rules we don't know what interface we will send this out
of until we create the state. Create new nat64 rules as floating, but bind them
to the appropriate interface on the first pf_route(), when we do know.
Set state policy if-bound for the nat64 tests to validate this.
See also: 6460322a0
Sponsored by: Rubicon Communications, LLC ("Netgate")
Differential Revision: https://reviews.freebsd.org/D47801
-rw-r--r-- | sys/netpfil/pf/pf.c | 28 | ||||
-rw-r--r-- | tests/sys/netpfil/pf/nat64.sh | 1 |
2 files changed, 26 insertions, 3 deletions
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 445aef881fe8..08486d5d1467 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -438,8 +438,10 @@ enum { PF_ICMP_MULTI_NONE, PF_ICMP_MULTI_LINK }; } while (0) static struct pfi_kkif * -BOUND_IFACE(struct pf_kstate *st, struct pfi_kkif *k) +BOUND_IFACE(struct pf_kstate *st, struct pf_pdesc *pd) { + struct pfi_kkif *k = pd->kif; + SDT_PROBE2(pf, ip, , bound_iface, st, k); /* Floating unless otherwise specified. */ @@ -450,7 +452,7 @@ BOUND_IFACE(struct pf_kstate *st, struct pfi_kkif *k) * Initially set to all, because we don't know what interface we'll be * sending this out when we create the state. */ - if (st->rule->rt == PF_REPLYTO) + if (st->rule->rt == PF_REPLYTO || (pd->af != pd->naf)) return (V_pfi_all); /* Don't overrule the interface for states created on incoming packets. */ @@ -6125,7 +6127,7 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a, __func__, nr, sk, nk)); /* Swap sk/nk for PF_OUT. */ - if (pf_state_insert(BOUND_IFACE(s, pd->kif), pd->kif, + if (pf_state_insert(BOUND_IFACE(s, pd), pd->kif, (pd->dir == PF_IN) ? sk : nk, (pd->dir == PF_IN) ? nk : sk, s)) { REASON_SET(&reason, PFRES_STATEINS); @@ -8800,6 +8802,16 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, dst.sin_addr = nh->gw4_sa.sin_addr; else dst.sin_addr = ip->ip_dst; + + /* + * Bind to the correct interface if we're + * if-bound. We don't know which interface + * that will be until here, so we've inserted + * the state on V_pf_all. Fix that now. + */ + if (s->kif == V_pfi_all && ifp != NULL && + r->rule_flag & PFRULE_IFBOUND) + s->kif = ifp->if_pf_kif; } } @@ -9050,6 +9062,16 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, sizeof(dst.sin6_addr)); else dst.sin6_addr = ip6->ip6_dst; + + /* + * Bind to the correct interface if we're + * if-bound. We don't know which interface + * that will be until here, so we've inserted + * the state on V_pf_all. Fix that now. + */ + if (s->kif == V_pfi_all && ifp != NULL && + r->rule_flag & PFRULE_IFBOUND) + s->kif = ifp->if_pf_kif; } } diff --git a/tests/sys/netpfil/pf/nat64.sh b/tests/sys/netpfil/pf/nat64.sh index 3e04dc6e7bc0..0ae2c0399daf 100644 --- a/tests/sys/netpfil/pf/nat64.sh +++ b/tests/sys/netpfil/pf/nat64.sh @@ -52,6 +52,7 @@ nat64_setup() jexec rtr pfctl -e pft_set_rules rtr \ + "set state-policy if-bound" \ "pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from (${epair_link}a)" } |