From nobody Wed Oct 1 16:10:55 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4ccKfS56cyz69sPl; Wed, 01 Oct 2025 16:10:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4ccKfS0HZtz3QDj; Wed, 01 Oct 2025 16:10:56 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759335056; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QoEoJWF9Tfl5Vjtlr0EL1CZwJi2sqlEjinj8axpcdbg=; b=WvKEh3AB8WenkWwitQnAK0cRuQOFyx/oPqbU/f1Nsvvkdqc5Ydw/RwOp5XhYqQulkATRyv KPbDmuFDvu9coM645PQGgQdM3F2c+moeM3kWXtU1jC01tmXP+O5CLHNBO6vAKhYtoeUWsS J74a0Xdu3VNMikMcJ9giveLGz24J3ljM5j0co5Ix3ZzMpWUmg9YXY2VSVStkmoSwmVWBXk /gqKjFAPypp7DGwxaRVHc/Suqu/NO/QfbZOudOFA2XR3qOLxLJRaKnojBozFWSkrdDlavU iJhyrXql4vo+ov3fy+irPQN8LZtQvovkTEtdALCU+lc+5BjyT7rZNvss2X3CFQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759335056; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QoEoJWF9Tfl5Vjtlr0EL1CZwJi2sqlEjinj8axpcdbg=; b=Q8ePfbpKYnFEQvD5L/u0le0Nsca0NVxW9kMtIPRtmZjeZOHJWmrBPymAi5xygjZebaUSaF 9HyUDIiIlLGDhRWJKtckqi5gBt7mEnyQPMknNQxSbE1G+iOMWrPLaegT0LuLYK2HjouEvQ 2H28CToOQnhZSCcZmF5FoZzLYaCvvSXgDvfytU8gbTelOw17Co7LAOS5YVw6310qIS/5L1 eyEnj/XsLludxBVw+XmzxfVEwCgy2fxcfjY/CiVcfSZgLiKf3bz0xV/AbpnyYm3xtQTMRn QLknoeMtb+uFw+44urf6FamfkQU4BXcphpyeTpeQVRxByUXOZMf88S81Qn9H7A== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1759335056; a=rsa-sha256; cv=none; b=wdadYyG+PBLxLsqp5tYZKpM3wbnoc/VmauaoD0MgRQSnaCXCEZjd7GbqADZgNsluf8Jclj rdppifQ3xc5oqBUhaCzORE8rzTDZSC6l4AY/778NcdAdZxYHWhTz6B5YO/Eh6J0Uu3+axE xcnHvz9V+K1nxLB8tuPYDtuuLoor414im3CbfYnQLwgfx79kHcRG1uBh8118bRJo0vrtpu POw+0yNhuLc1j4a/cksZS2AYTcRM5Lr0j/TjKp4gJyaOrbgvIsn48vv89FuGIh8krwMFzb QwCZK3QlT3qweaG0ByVtew5ayB1G1+PjLiXhdf9uHy0H00bV5jm63YZ9BHC8rw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4ccKfR6xkfzDTy; Wed, 01 Oct 2025 16:10:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 591GAtcI066232; Wed, 1 Oct 2025 16:10:55 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 591GAtRf066229; Wed, 1 Oct 2025 16:10:55 GMT (envelope-from git) Date: Wed, 1 Oct 2025 16:10:55 GMT Message-Id: <202510011610.591GAtRf066229@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kajetan Staszkiewicz Subject: git: ad428a318b60 - stable/15 - pf: Fix interface counters for af-to rules List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: ks X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: ad428a318b60c0278a146b04fbc7520c322e55ef Auto-Submitted: auto-generated The branch stable/15 has been updated by ks: URL: https://cgit.FreeBSD.org/src/commit/?id=ad428a318b60c0278a146b04fbc7520c322e55ef commit ad428a318b60c0278a146b04fbc7520c322e55ef Author: Kajetan Staszkiewicz AuthorDate: 2025-09-08 17:53:48 +0000 Commit: Kajetan Staszkiewicz CommitDate: 2025-10-01 16:00:47 +0000 pf: Fix interface counters for af-to rules An inbound af-to rule creates a state bypassing outbound pf_test(). In such case increase counters of the outbound interface directly in pf_route() for post-af-to address family. For outbound af-to rules ensure that post-af-to address family is used to increase interface counters. Reviewed by: kp Sponsored by: InnoGames GmbH Differential Revision: https://reviews.freebsd.org/D52448 (cherry picked from commit 7cd3854f827faaad1ecf414d20bdf6802cfa60f8) --- sys/netpfil/pf/pf.c | 151 +++++++++++++++++++++++++-------------- tests/sys/netpfil/pf/counters.sh | 18 ++++- 2 files changed, 115 insertions(+), 54 deletions(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 66096133acd4..fb13f22bf0b1 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -9203,25 +9203,38 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, if (r->rt == PF_DUPTO || (pd->af != pd->naf && s->direction == PF_IN)) skip_test = true; - if (pd->dir == PF_IN && !skip_test) { - if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp, - &pd->act) != PF_PASS) { - action = PF_DROP; - SDT_PROBE1(pf, ip, route_to, drop, __LINE__); - goto bad; - } else if (m0 == NULL) { - action = PF_DROP; - SDT_PROBE1(pf, ip, route_to, drop, __LINE__); - goto done; - } - if (m0->m_len < sizeof(struct ip)) { - DPFPRINTF(PF_DEBUG_URGENT, - "%s: m0->m_len < sizeof(struct ip)", __func__); - SDT_PROBE1(pf, ip, route_to, drop, __LINE__); - action = PF_DROP; - goto bad; + if (pd->dir == PF_IN) { + if (skip_test) { + struct pfi_kkif *out_kif = (struct pfi_kkif *)ifp->if_pf_kif; + MPASS(s != NULL); + pf_counter_u64_critical_enter(); + pf_counter_u64_add_protected( + &out_kif->pfik_bytes[pd->naf == AF_INET6][1] + [action != PF_PASS && action != PF_AFRT], pd->tot_len); + pf_counter_u64_add_protected( + &out_kif->pfik_packets[pd->naf == AF_INET6][1] + [action != PF_PASS && action != PF_AFRT], 1); + pf_counter_u64_critical_exit(); + } else { + if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp, + &pd->act) != PF_PASS) { + action = PF_DROP; + SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + goto bad; + } else if (m0 == NULL) { + action = PF_DROP; + SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + goto done; + } + if (m0->m_len < sizeof(struct ip)) { + DPFPRINTF(PF_DEBUG_URGENT, + "%s: m0->m_len < sizeof(struct ip)", __func__); + SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; + goto bad; + } + ip = mtod(m0, struct ip *); } - ip = mtod(m0, struct ip *); } if (ifp->if_flags & IFF_LOOPBACK) @@ -9520,26 +9533,39 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, if (r->rt == PF_DUPTO || (pd->af != pd->naf && s->direction == PF_IN)) skip_test = true; - if (pd->dir == PF_IN && !skip_test) { - if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT, - ifp, &m0, inp, &pd->act) != PF_PASS) { - action = PF_DROP; - SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); - goto bad; - } else if (m0 == NULL) { - action = PF_DROP; - SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); - goto done; - } - if (m0->m_len < sizeof(struct ip6_hdr)) { - DPFPRINTF(PF_DEBUG_URGENT, - "%s: m0->m_len < sizeof(struct ip6_hdr)", - __func__); - action = PF_DROP; - SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); - goto bad; + if (pd->dir == PF_IN) { + if (skip_test) { + struct pfi_kkif *out_kif = (struct pfi_kkif *)ifp->if_pf_kif; + MPASS(s != NULL); + pf_counter_u64_critical_enter(); + pf_counter_u64_add_protected( + &out_kif->pfik_bytes[pd->naf == AF_INET6][1] + [action != PF_PASS && action != PF_AFRT], pd->tot_len); + pf_counter_u64_add_protected( + &out_kif->pfik_packets[pd->naf == AF_INET6][1] + [action != PF_PASS && action != PF_AFRT], 1); + pf_counter_u64_critical_exit(); + } else { + if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT, + ifp, &m0, inp, &pd->act) != PF_PASS) { + action = PF_DROP; + SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); + goto bad; + } else if (m0 == NULL) { + action = PF_DROP; + SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); + goto done; + } + if (m0->m_len < sizeof(struct ip6_hdr)) { + DPFPRINTF(PF_DEBUG_URGENT, + "%s: m0->m_len < sizeof(struct ip6_hdr)", + __func__); + action = PF_DROP; + SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); + goto bad; + } + ip6 = mtod(m0, struct ip6_hdr *); } - ip6 = mtod(m0, struct ip6_hdr *); } if (ifp->if_flags & IFF_LOOPBACK) @@ -10665,21 +10691,32 @@ pf_counters_inc(int action, struct pf_pdesc *pd, struct pf_kstate *s, struct pf_addr *dst_host = pd->dst; struct pf_state_key *key; int dir_out = (pd->dir == PF_OUT); - int op_pass = (r->action == PF_PASS); - sa_family_t af = pd->af; + int op_r_pass = (r->action == PF_PASS); + int op_pass = (action == PF_PASS || action == PF_AFRT); int s_dir_in, s_dir_out, s_dir_rev; + sa_family_t af = pd->af; pf_counter_u64_critical_enter(); + /* + * Set AF for interface counters, it will be later overwritten for + * rule and state counters with value from proper state key. + */ + if (action == PF_AFRT) { + MPASS(s != NULL); + if (s->direction == PF_OUT && dir_out) + af = pd->naf; + } + pf_counter_u64_add_protected( - &pd->kif->pfik_bytes[pd->af == AF_INET6][dir_out][action != PF_PASS], + &pd->kif->pfik_bytes[af == AF_INET6][dir_out][!op_pass], pd->tot_len); pf_counter_u64_add_protected( - &pd->kif->pfik_packets[pd->af == AF_INET6][dir_out][action != PF_PASS], + &pd->kif->pfik_packets[af == AF_INET6][dir_out][!op_pass], 1); /* If the rule has failed to apply, don't increase its counters */ - if (!(action == PF_PASS || action == PF_AFRT || r->action == PF_DROP)) { + if (!(op_pass || r->action == PF_DROP)) { pf_counter_u64_critical_exit(); return; } @@ -10690,22 +10727,32 @@ pf_counters_inc(int action, struct pf_pdesc *pd, struct pf_kstate *s, /* * For af-to on the inbound direction we can determine - * the direction only by checking direction of AF translation, - * since the state is always "in" and so is packet's direction. + * the direction of passing packet only by checking direction + * of AF translation. The af-to in "in" direction covers both + * the inbound and the outbound side of state tracking, + * so pd->dir is always PF_IN. We set dir_out and s_dir_rev + * in a way to count packets as if the state was outbound, + * because pfctl -ss shows the state with "->", as if it was + * oubound. */ - if (pd->af != pd->naf && s->direction == PF_IN) { + if (action == PF_AFRT && s->direction == PF_IN) { dir_out = (pd->naf == s->rule->naf); s_dir_in = 1; s_dir_out = 0; - s_dir_rev = (pd->naf != s->rule->naf); - } - else { + s_dir_rev = (pd->naf == s->rule->af); + } else { dir_out = (pd->dir == PF_OUT); s_dir_in = (s->direction == PF_IN); s_dir_out = (s->direction == PF_OUT); s_dir_rev = (pd->dir != s->direction); } + /* pd->tot_len is a problematic with af-to rules. Sure, we can + * agree that it's the post-af-to packet length that was + * forwarded through a state, but what about tables which match + * on pre-af-to addresses? We don't have access the the original + * packet length anymore. + */ s->packets[s_dir_rev]++; s->bytes[s_dir_rev] += pd->tot_len; @@ -10737,7 +10784,7 @@ pf_counters_inc(int action, struct pf_pdesc *pd, struct pf_kstate *s, s->nat_rule->action == PF_BINAT) { nr = s->nat_rule; pf_rule_counters_inc(pd, s->nat_rule, dir_out, - op_pass, af, src_host, dst_host); + op_r_pass, af, src_host, dst_host); /* Use post-NAT addresses from now on */ key = s->key[s_dir_in]; src_host = &(key->addr[s_dir_out]); @@ -10748,7 +10795,7 @@ pf_counters_inc(int action, struct pf_pdesc *pd, struct pf_kstate *s, } SLIST_FOREACH(ri, mr, entry) { - pf_rule_counters_inc(pd, ri->r, dir_out, op_pass, af, + pf_rule_counters_inc(pd, ri->r, dir_out, op_r_pass, af, src_host, dst_host); if (s && s->nat_rule == ri->r) { /* Use post-NAT addresses after a match NAT rule */ @@ -10764,12 +10811,12 @@ pf_counters_inc(int action, struct pf_pdesc *pd, struct pf_kstate *s, } if (a != NULL) { - pf_rule_counters_inc(pd, a, dir_out, op_pass, af, + pf_rule_counters_inc(pd, a, dir_out, op_r_pass, af, src_host, dst_host); } if (r != nr) { - pf_rule_counters_inc(pd, r, dir_out, op_pass, af, + pf_rule_counters_inc(pd, r, dir_out, op_r_pass, af, src_host, dst_host); } diff --git a/tests/sys/netpfil/pf/counters.sh b/tests/sys/netpfil/pf/counters.sh index a0119b4710c1..20d7dc3c6d89 100644 --- a/tests/sys/netpfil/pf/counters.sh +++ b/tests/sys/netpfil/pf/counters.sh @@ -684,7 +684,7 @@ nat64_in_body() "table { 64:ff9b::${net_server1_4_host_server} }" \ "table { ${net_tester_6_host_tester} }" \ "table { 64:ff9b::${net_server1_4_host_server} }" \ - "block" \ + "block log" \ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ "match in on ${epair_tester}b inet6 proto tcp from to scrub (random-id)" \ "pass in on ${epair_tester}b inet6 proto tcp from to \ @@ -726,6 +726,13 @@ nat64_in_body() ; do grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" done + + echo " === interfaces === " + echo " === tester === " + jexec router pfctl -qvvsI -i ${epair_tester}b + echo " === server === " + jexec router pfctl -qvvsI -i ${epair_server1}a + echo " === " } nat64_in_cleanup() @@ -753,7 +760,7 @@ nat64_out_body() "table { 64:ff9b::${net_server1_4_host_server} }" \ "table { ${net_tester_6_host_tester} }" \ "table { 64:ff9b::${net_server1_4_host_server} }" \ - "block" \ + "block log " \ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ "pass in on ${epair_tester}b inet6 proto tcp keep state" \ "match out on ${epair_server1}a inet6 proto tcp from to scrub (random-id)" \ @@ -794,6 +801,13 @@ nat64_out_body() ; do grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'" done + + echo " === interfaces === " + echo " === tester === " + jexec router pfctl -qvvsI -i ${epair_tester}b + echo " === server === " + jexec router pfctl -qvvsI -i ${epair_server1}a + echo " === " } nat64_out_cleanup()