git: 31828075e456 - main - pf: bind route-to states to their route-to interface
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 29 Jan 2024 13:52:42 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=31828075e456c042cabd47ff4eb127c5c19f16e0 commit 31828075e456c042cabd47ff4eb127c5c19f16e0 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2024-01-25 10:16:49 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2024-01-29 13:10:26 +0000 pf: bind route-to states to their route-to interface When we route-to the state should be bound to the route-to interface, not the default route interface. However, we should only do so for outbound traffic, because inbound traffic should bind on the arriving interface, not the one we eventually transmit on. Explicitly check for this in BOUND_IFACE(). We must also extend pf_find_state(), because subsequent packets within the established state will attempt to match the original interface, not the route-to interface. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D43589 --- sys/netpfil/pf/pf.c | 27 +++++++++++++++++++++---- tests/sys/netpfil/pf/route_to.sh | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 2dc6d02d330a..36ff0eac16ad 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -412,8 +412,27 @@ VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]); return (PF_PASS); \ } while (0) -#define BOUND_IFACE(r, k) \ - ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : V_pfi_all +static struct pfi_kkif * +BOUND_IFACE(struct pf_krule *r, struct pfi_kkif *k, struct pf_pdesc *pd) +{ + /* Floating unless otherwise specified. */ + if (! (r->rule_flag & PFRULE_IFBOUND)) + return (V_pfi_all); + + /* Don't overrule the interface for states created on incoming packets. */ + if (pd->dir == PF_IN) + return (k); + + /* No route-to, so don't overrrule. */ + if (r->rt != PF_ROUTETO) + return (k); + + if (r->rpool.cur == NULL) + return (k); + + /* Bind to the route-to interface. */ + return (r->rpool.cur->kif); +} #define STATE_INC_COUNTERS(s) \ do { \ @@ -1600,7 +1619,7 @@ pf_find_state(struct pfi_kkif *kif, struct pf_state_key_cmp *key, u_int dir) /* List is sorted, if-bound states before floating ones. */ TAILQ_FOREACH(s, &sk->states[idx], key_list[idx]) - if (s->kif == V_pfi_all || s->kif == kif) { + if (s->kif == V_pfi_all || s->kif == kif || s->orig_kif == kif) { PF_STATE_LOCK(s); PF_HASHROW_UNLOCK(kh); if (__predict_false(s->timeout >= PFTM_MAX)) { @@ -4999,7 +5018,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(r, kif), kif, + if (pf_state_insert(BOUND_IFACE(r, kif, pd), kif, (pd->dir == PF_IN) ? sk : nk, (pd->dir == PF_IN) ? nk : sk, s)) { REASON_SET(&reason, PFRES_STATEINS); diff --git a/tests/sys/netpfil/pf/route_to.sh b/tests/sys/netpfil/pf/route_to.sh index d8cfb1b22d8b..7e8310bceb30 100644 --- a/tests/sys/netpfil/pf/route_to.sh +++ b/tests/sys/netpfil/pf/route_to.sh @@ -365,6 +365,48 @@ dummynet_cleanup() pft_cleanup } +atf_test_case "ifbound" "cleanup" +ifbound_head() +{ + atf_set descr 'Test that route-to states bind the expected interface' + atf_set require.user root +} + +ifbound_body() +{ + pft_init + + j="route_to:ifbound" + + epair_one=$(vnet_mkepair) + epair_two=$(vnet_mkepair) + ifconfig ${epair_one}b up + + vnet_mkjail ${j}2 ${epair_two}b + jexec ${j}2 ifconfig ${epair_two}b inet 198.51.100.2/24 up + jexec ${j}2 ifconfig ${epair_two}b inet alias 203.0.113.1/24 + jexec ${j}2 route add default 198.51.100.1 + + vnet_mkjail $j ${epair_one}a ${epair_two}a + jexec $j ifconfig ${epair_one}a 192.0.2.1/24 up + jexec $j ifconfig ${epair_two}a 198.51.100.1/24 up + jexec $j route add default 192.0.2.2 + + jexec $j pfctl -e + pft_set_rules $j \ + "set state-policy if-bound" \ + "block" \ + "pass out route-to (${epair_two}a 198.51.100.2)" + + atf_check -s exit:0 -o ignore \ + jexec $j ping -c 3 203.0.113.1 +} + +ifbound_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { atf_add_test_case "v4" @@ -373,4 +415,5 @@ atf_init_test_cases() atf_add_test_case "multiwanlocal" atf_add_test_case "icmp_nat" atf_add_test_case "dummynet" + atf_add_test_case "ifbound" }