From nobody Thu Jun 26 13:11:45 2025 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 4bSfGV3Rs8z60YKR; Thu, 26 Jun 2025 13:11:46 +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 "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4bSfGV039kz3JZ0; Thu, 26 Jun 2025 13:11:46 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1750943506; 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=FR2LEExL6itB8QoAxLsROiWdup8iVQYRkFrHedELz9k=; b=AGXtPOa0R4XZuGiK/Td3swpDN/MRd+vRTRnl0Ds7t1/wrk8UvWkFFvDoXDTqiA0/1R5oAD VJS/o2mC+NzyYC6HY+dlSPVerkTH7lBkwD2WVbNIMGbsK8PpTpzjFV76oypPfOEuUxrrgp R5pR5wnV1KPX/c/hNnEKYXx30GYiid0JT7BJzhFDHWR8sWCZvDchySsauG9pVTM52sYkga WFRkw5qpzsIGhT7Iwho9cB0KY9mB+D2/l80YkDZlTzK3XJtPYQFXLzdk+SueWU5QKHx1m4 EWfai3d9Mx/mSAbGoUlvo0IZjMpHTaK3/g8NoEU38PpwrtJMz/TO0cAgNNPbOg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1750943506; 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=FR2LEExL6itB8QoAxLsROiWdup8iVQYRkFrHedELz9k=; b=fi7bfPEDsFhOREEXlcAQKCPDEeu3aMBk6jg0EkXrMkds5V4+hCZRS9xTPGuhB6Gz24Redk MD8Y8pelbzdguLX6bNE5Ll2fBtTjHxLcmSh4a+l3lGUBE2R1WVg6eV/MJZ9jR/izVDJxKJ aw3Ph+ecOSYmMfEx+FWyylktSdhmW0/xaTbvtOlWIGiYl2ZFUUyU+mzHuGHWP9YoFH0fPp mRHqsWI62w9edkAIxaYAZBPj7/Y4hQibVMzAmhx9sT+BM+3bzpdDuz/tBCXwajeV9V4JQl xS8YJXIa4piLmC/HlowVdJYBLrxz5AJ8ueaYl95ADmtEvxtHpMrsZhBa+zxmBA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1750943506; a=rsa-sha256; cv=none; b=D4ZC0xMx+7IGeskn1XNDbUvd6TD4T/yMVs9X5DFFJIVG5msGpja18eKdwqm/PGo0P0viMQ z7De5Y4OUxhVJtjqZgpN3KbJ4zy8iR0//2LC7thZrCNtihki5D/pm26fLBavpiUwtWWVmQ O6rGHjF/v3fHJ9TWyQKDXzp05GtIgEWmXTe+7pDkAB5UdPBzVDR30EjAovXk1cjdeplfJ9 kRviRR5YKiTbrCU/nsLk9NDmbAJG1BmWc3Rr4x604TIYyb0gv5OZz9b0dOGD2732VGCXG0 FLiEHhcMeDXjFhvS5vWFKecOO4YjESOk5gjbuOm8VTPgIpHJ8FtfYisDlRr5Dw== 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 4bSfGT6bbxz14JQ; Thu, 26 Jun 2025 13:11:45 +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 55QDBjqI022607; Thu, 26 Jun 2025 13:11:45 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 55QDBjPa022604; Thu, 26 Jun 2025 13:11:45 GMT (envelope-from git) Date: Thu, 26 Jun 2025 13:11:45 GMT Message-Id: <202506261311.55QDBjPa022604@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: ad591caf2a70 - main - pf: decrement TTL in pf_route(6)() List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: ad591caf2a70d6f3a5f1ba7aff182591afc0cc04 Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=ad591caf2a70d6f3a5f1ba7aff182591afc0cc04 commit ad591caf2a70d6f3a5f1ba7aff182591afc0cc04 Author: Kristof Provost AuthorDate: 2025-06-20 09:41:19 +0000 Commit: Kristof Provost CommitDate: 2025-06-26 13:11:01 +0000 pf: decrement TTL in pf_route(6)() When pf(4) forwards incoming packets with route-to or reply-to, decrement the time-to-live or hop-limit field to prevent routing loops. Sending an ICMP time exceeded error makes traceroute work. For outgoing packets ip_forward() has already done this. OK visa@ sashan@ Add a test case for the above, and fix the nat64 tests to account for the nat64 router now decrementing the TTL. Obtained from: OpenBSD, bluhm , 18421856bb Sponsored by: Rubicon Communications, LLC ("Netgate") --- sys/netpfil/pf/pf.c | 24 +++++++++++++++++++- tests/sys/netpfil/pf/nat64.py | 10 ++++----- tests/sys/netpfil/pf/route_to.sh | 47 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index cdf48fc4d60a..a40e1744cbc8 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -8949,7 +8949,18 @@ pf_route(struct pf_krule *r, struct ifnet *oifp, dst->sin_len = sizeof(struct sockaddr_in); dst->sin_addr.s_addr = pd->act.rt_addr.v4.s_addr; - if (s != NULL){ + if (pd->dir == PF_IN) { + if (ip->ip_ttl <= IPTTLDEC) { + if (r->rt != PF_DUPTO) + pf_send_icmp(m0, ICMP_TIMXCEED, + ICMP_TIMXCEED_INTRANS, 0, pd->af, r, + pd->act.rtableid); + goto bad_locked; + } + ip->ip_ttl -= IPTTLDEC; + } + + if (s != NULL) { if (ifp == NULL && (pd->af != pd->naf)) { /* We're in the AFTO case. Do a route lookup. */ const struct nhop_object *nh; @@ -9231,6 +9242,17 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp, dst.sin6_len = sizeof(dst); PF_ACPY((struct pf_addr *)&dst.sin6_addr, &pd->act.rt_addr, AF_INET6); + if (pd->dir == PF_IN) { + if (ip6->ip6_hlim <= IPV6_HLIMDEC) { + if (r->rt != PF_DUPTO) + pf_send_icmp(m0, ICMP6_TIME_EXCEEDED, + ICMP6_TIME_EXCEED_TRANSIT, 0, pd->af, r, + pd->act.rtableid); + goto bad_locked; + } + ip6->ip6_hlim -= IPV6_HLIMDEC; + } + if (s != NULL) { if (ifp == NULL && (pd->af != pd->naf)) { const struct nhop_object *nh; diff --git a/tests/sys/netpfil/pf/nat64.py b/tests/sys/netpfil/pf/nat64.py index 32fd8f4245a1..adae2489ce5e 100644 --- a/tests/sys/netpfil/pf/nat64.py +++ b/tests/sys/netpfil/pf/nat64.py @@ -178,7 +178,7 @@ class TestNAT64(VnetTestTemplate): # Check the hop limit ip6 = reply.getlayer(sp.IPv6) - assert ip6.hlim == 62 + assert ip6.hlim == 61 @pytest.mark.require_user("root") @pytest.mark.require_progs(["scapy"]) @@ -236,7 +236,7 @@ class TestNAT64(VnetTestTemplate): ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1") import scapy.all as sp - packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=1) \ + packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=2) \ / sp.TCP(sport=1111, dport=2222, flags="S") self.common_test_source_addr(packet) @@ -246,7 +246,7 @@ class TestNAT64(VnetTestTemplate): ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1") import scapy.all as sp - packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=1) \ + packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=2) \ / sp.UDP(sport=1111, dport=2222) / sp.Raw("foo") self.common_test_source_addr(packet) @@ -256,7 +256,7 @@ class TestNAT64(VnetTestTemplate): ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1") import scapy.all as sp - packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=1) \ + packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=2) \ / sp.SCTP(sport=1111, dport=2222) \ / sp.SCTPChunkInit(init_tag=1, n_in_streams=1, n_out_streams=1, a_rwnd=1500) self.common_test_source_addr(packet) @@ -267,7 +267,7 @@ class TestNAT64(VnetTestTemplate): ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1") import scapy.all as sp - packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=1) \ + packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=2) \ / sp.ICMPv6EchoRequest() / sp.Raw("foo") reply = self.common_test_source_addr(packet) icmp = reply.getlayer(sp.ICMPv6EchoRequest) diff --git a/tests/sys/netpfil/pf/route_to.sh b/tests/sys/netpfil/pf/route_to.sh index 0354d1f59306..5c0d355b8ea1 100644 --- a/tests/sys/netpfil/pf/route_to.sh +++ b/tests/sys/netpfil/pf/route_to.sh @@ -813,6 +813,52 @@ sticky_cleanup() pft_cleanup } +atf_test_case "ttl" "cleanup" +ttl_head() +{ + atf_set descr 'Ensure we decrement TTL on route-to' + atf_set require.user root +} + +ttl_body() +{ + pft_init + + epair_one=$(vnet_mkepair) + epair_two=$(vnet_mkepair) + ifconfig ${epair_one}b 192.0.2.2/24 up + route add default 192.0.2.1 + + vnet_mkjail alcatraz ${epair_one}a ${epair_two}a + jexec alcatraz ifconfig ${epair_one}a 192.0.2.1/24 up + jexec alcatraz ifconfig ${epair_two}a 198.51.100.1/24 up + jexec alcatraz sysctl net.inet.ip.forwarding=1 + + vnet_mkjail singsing ${epair_two}b + jexec singsing ifconfig ${epair_two}b 198.51.100.2/24 up + jexec singsing route add default 198.51.100.1 + + # Sanity check + atf_check -s exit:0 -o ignore \ + ping -c 3 198.51.100.2 + + jexec alcatraz pfctl -e + pft_set_rules alcatraz \ + "pass out" \ + "pass in route-to (${epair_two}a 198.51.100.2)" + + atf_check -s exit:0 -o ignore \ + ping -c 3 198.51.100.2 + + atf_check -s exit:2 -o ignore \ + ping -m 1 -c 3 198.51.100.2 +} + +ttl_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { atf_add_test_case "v4" @@ -830,4 +876,5 @@ atf_init_test_cases() atf_add_test_case "dummynet_frag" atf_add_test_case "dummynet_double" atf_add_test_case "sticky" + atf_add_test_case "ttl" }