From nobody Tue Oct 13 16:07:25 2026 X-Original-To: dev-commits-src-main@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 4j3zkP3509z6vbyL for ; Tue, 13 Oct 2026 16:07:25 +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 "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4j3zkP1bHtz4TBT for ; Tue, 13 Oct 2026 16:07:25 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791907645; 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=DWLpi3I5W/4F+LqTZRmDEIFdQWk9TcnjJfZPtDgUba8=; b=qLKU5N63AQxBCzimhZZUyOcO+f1Mh5M2CeFpH6AGO3MtLz3BXiqXbsBulsUcZGIKw54mhD QBxItkDJ17cstLnE4qRv/ZL0IHS6ukwhHVxXLl7CXUt9fzyuKDmZeBC/2pTDTJujhsgAGt QfAo6v+lBJEnKqWX3iJ8ND/4UhybzvrTNGct+SCZ3pwjU3G13B8XmLMMtvX6PB44UAmzmp e3O6jvendvtt9Q0vwcf9GSnkqKgJXnKC8WfYpArU87ot2ppicUOLEAZbp0WFqkS2loIOle RzLBJqAaaHs8DswlFOwwz3j1o6d0HXH7G4KyLmZZoRq4OtOIz97TJuiqsLTgPQ== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1791907645; b=RG0coBOi3w7vTQ+58ykJ61j1JUbw6XAUN+qHnT7nTh9FBFyngnCZLtvvXGubuScXc9D3tJ 1E8ulyejGPLkVjkc2CRNBss3R+RQVtyJb2GZP6XQ659mY6dI1/yNHE3tpSNF25zsAt79Bp AewVdR4N9VC1fJZSAe2n0zJa0nZDufVI1z7TVxk06gbNCKH35u9beR+R17d0OWffNBIcA3 TUwN284956YYwA9stIlEWv/1M5LRv4wFWN6ORzkd5WQLRQesU3uV7587FfPZ4c7E6ei0cT 4ZViqMubfeuyyIQYRinusD41NRAJzTnYrOmEvEbsN0Oven6V0m4j2Aq5yH4+xQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791907645; 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=DWLpi3I5W/4F+LqTZRmDEIFdQWk9TcnjJfZPtDgUba8=; b=gAC9avIpsH+iQ1SlLrJ8sipur/SOCG+rOSvAxdrdwJamDDUPKEMP98wvf7sw5fHaT9JgO3 Ex/ibHZh08jyyJgyN9Yr6u1QWOdT8eMZyw2OJ7qkq6tUM9TdI9uevPCjHue2tS4nCF5I9a Mui0nxLxpvFCOdnIM8AylPYIN9UoScZ+exSxTTloQYQ159Tozw2JVgwq+VRmZl80lGFuGp /Rnp74e74uhgwcjJp2PP5r1pHvbN0NN9qYggvSvGtGdXaE1DX+ukVwUhrUt1Sd+Ky6geKf 6OnzoHyD886Ud+xE4oOZVbFwNnzM5UcfMbVzu7AyWLlSDfh2DR3rvADR2Eo1ug== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4j3zkP0gzBzLHZ for ; Tue, 13 Oct 2026 16:07:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 22566 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 13 Oct 2026 16:07:25 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: R. Christian McDonald Subject: git: a6e1dde287eb - main - pf: Do not corrupt neighbour advertisements when translating List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: Commit messages for the main branch of the src repository List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rcm X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: a6e1dde287eb3854873224200cea40996b0b5cbf Auto-Submitted: auto-generated Date: Tue, 13 Oct 2026 16:07:25 +0000 Message-Id: <6ace573d.22566.7d404c4@gitrepo.freebsd.org> The branch main has been updated by rcm: URL: https://cgit.FreeBSD.org/src/commit/?id=a6e1dde287eb3854873224200cea40996b0b5cbf commit a6e1dde287eb3854873224200cea40996b0b5cbf Author: R. Christian McDonald AuthorDate: 2026-10-13 15:58:55 +0000 Commit: R. Christian McDonald CommitDate: 2026-10-13 16:02:39 +0000 pf: Do not corrupt neighbour advertisements when translating When an ICMPv6 query or reply matches a translated state, pf_test_state_icmp() copies the state's virtual id into icmp6_id. Only echo messages have an identifier there. For all other types the virtual id is 0 and those two bytes hold something else; in a neighbour advertisement they hold the R, S and O flags. The checksum was not updated either, so icmp6_input() dropped the advertisement as a bad checksum. Unicast NUD probes to a link-local neighbour, such as the default router, are sent from the link-local address. With a nat rule that matches it (e.g. "from any"), every advertisement answering a probe was dropped: NUD failed, the neighbour cache entry was deleted, and traffic to the neighbour stalled until it was resolved again. Only rewrite the id of echo messages, as the ICMPv6 error path already does, and update the checksum, as the IPv4 path does. Add a regression test. Reviewed by: kp Fixes: f1ddd7f1dae6 ("pf: add forgotten fixup for icmp6 id's when translating") See also: https://redmine.pfsense.org/issues/16236 MFC after: 1 week Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D60542 --- sys/netpfil/pf/pf.c | 14 ++++++++- tests/sys/netpfil/pf/icmp6.sh | 73 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 817790ba0ef0..00990e17d0c8 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -8856,9 +8856,21 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, &pd->hdr.icmp6.icmp6_cksum, &nk->addr[didx], 0); - if (nk->port[iidx] != pd->hdr.icmp6.icmp6_id) + /* + * Only echo has an identifier. Other + * types use a virtual id of 0 and keep + * other fields here (e.g. the NA flags). + */ + if (virtual_type == htons(ICMP6_ECHO_REQUEST) && + nk->port[iidx] != pd->hdr.icmp6.icmp6_id) { + pd->hdr.icmp6.icmp6_cksum = + pf_cksum_fixup( + pd->hdr.icmp6.icmp6_cksum, + pd->hdr.icmp6.icmp6_id, + nk->port[iidx], 0); pd->hdr.icmp6.icmp6_id = nk->port[iidx]; + } m_copyback(pd->m, pd->off, sizeof(struct icmp6_hdr), (caddr_t )&pd->hdr.icmp6); diff --git a/tests/sys/netpfil/pf/icmp6.sh b/tests/sys/netpfil/pf/icmp6.sh index c55af906e3a6..acce09dd45c5 100644 --- a/tests/sys/netpfil/pf/icmp6.sh +++ b/tests/sys/netpfil/pf/icmp6.sh @@ -196,9 +196,82 @@ repeat_cleanup() pft_cleanup } +atf_test_case "nat_nud" "cleanup" +nat_nud_head() +{ + atf_set descr 'Test that NUD works when pf translates the probes' + atf_set require.user root +} + +nat_nud_body() +{ + pft_init + + epair=$(vnet_mkepair) + + vnet_mkjail alcatraz ${epair}a + jexec alcatraz ifconfig ${epair}a inet6 no_dad + jexec alcatraz ifconfig ${epair}a inet6 2001:db8::1/64 up + # Probe a stale neighbour one second after using it, not five. + jexec alcatraz sysctl net.inet6.icmp6.nd6_delay=1 + + vnet_mkjail singsing ${epair}b + jexec singsing ifconfig ${epair}b inet6 no_dad + jexec singsing ifconfig ${epair}b inet6 2001:db8::2/64 up + + lla=$(jexec alcatraz ifconfig ${epair}a inet6 | \ + awk '/fe80:/ { sub(/%.*/, "", $2); print $2 }') + llb=$(jexec singsing ifconfig ${epair}b inet6 | \ + awk '/fe80:/ { sub(/%.*/, "", $2); print $2 }') + + # NUD probes are sent from the link-local address, so this translates + # them, and the advertisements answering them come back to 2001:db8::1. + jexec alcatraz pfctl -e + pft_set_rules alcatraz \ + "nat on ${epair}a inet6 from fe80::/10 to any -> 2001:db8::1" \ + "pass" + + # singsing resolving alcatraz leaves it stale in alcatraz's neighbour + # cache, and alcatraz answering uses it, so alcatraz will probe it. + atf_check -s exit:0 -o ignore \ + jexec singsing ping -6 -c 1 ${lla}%${epair}b + + # The advertisement answering the probe makes the neighbour reachable. + # A corrupted one is dropped: alcatraz probes twice more, then deletes + # the entry. + state= + for i in $(seq 1 15); do + state=$(jexec alcatraz ndp -n ${llb}%${epair}a 2>/dev/null | \ + awk 'NR == 2 { print $5 }') + if [ "${state}" = "R" ]; then + break + fi + sleep 1 + done + + jexec alcatraz ndp -an + jexec alcatraz pfctl -ss -vv + + if [ "${state}" != "R" ]; then + atf_fail "NUD failed, neighbour state '${state:-no entry}'" + fi + atf_check -o match:"^[[:space:]]*0 bad checksums$" \ + jexec alcatraz netstat -s -p icmp6 + + # The probe was translated + atf_check -o match:"2001:db8::1 \(${lla}\) -> ${llb}\[135\]" \ + jexec alcatraz pfctl -ss +} + +nat_nud_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { atf_add_test_case "zero_id" atf_add_test_case "ttl_exceeded" atf_add_test_case "repeat" + atf_add_test_case "nat_nud" }