From nobody Sat Jan 18 23:58:38 2025 X-Original-To: dev-commits-src-branches@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 4YbD8G3HfBz5l3nX; Sat, 18 Jan 2025 23:58:38 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4YbD8G1VgYz3XhC; Sat, 18 Jan 2025 23:58:38 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1737244718; 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=yNAuNIH15ySxmsWvzXcqWE573KMqvMVEM2jHIXgzXf8=; b=lpAdCCQ1Vs2AvW2SuQowwKSOpcABdy9eu4Oe6omQGPHjWubM1T0qMvTUmlviNjTmwE9zYh sLoLHwvS7ueZzYyA+OL2GOyZ6OuPCJwndUsslJiedvGuedWImPkAZr9l4QkjRTwA5wGrju BSLSnaGfkEF/lFcXrVZqeEizALo5gcMkhf0Sqd9jzNYq17Bbou1gbJyg0NFx53eQehtv05 UNBTr101R7saL4+FsM+iwS+fmdSosRAMaPD2KN34PVEtOiGYVbuhdGmQiu00z7SZufBrdi pI3tRmsa6zXowd1CKA2Csa9Qj8WCtg3ObLMHFMo1ZdD0p9ckFO+4mcerZ5zDPg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1737244718; 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=yNAuNIH15ySxmsWvzXcqWE573KMqvMVEM2jHIXgzXf8=; b=moX+TZLga3eSg+w/NoSrJxD9rhXmhQb0ndxdCo2NY7nGCWn3TWqgXVfpmTv9u7TFY5sw7R PMYrmX28rpqPaAHw+kFWsDYTDwfIgNdvV8JbKrT6/35oPV4sKUQTsd9JQaa7F/nei7Jt1i irQcrZhhNN5Vgt5BX3iP96X7YY4zMcAQ/Dzoflykpffp7M4yIrtlUGbEBHxo0VWeradYzC h1Zge2rOiEP5zd08q75n0X3/Ntl7uOWLvROHX29BMkHxjMz3aZJCmr7d19TrqpJFw4N46/ UBfU6fy2qtS3Dt2F+Laun38cVBrMQaVbs59pZfZj3YPfRFqic9Ersu+oqqvPTQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1737244718; a=rsa-sha256; cv=none; b=dQS5jDZ0x5NkmhVmaZzvSC4RiaUxVAvU+m60X2+EEd6VutezlcguK5Taj8W940R0CGdR7E Y8b1cwTxmZ8YiUdVpnEvjudQ7AT3/gi6N4YRuPcJS9eMlXrpWKzKhnF9Gy0gu+9trEJINq 8ImCi314m4Ky0YN36HIT6Xdwy1ZWSw8G/11s7/aYl7NAvdZQFSAg8+5F0cZs1UoxMXE7eR SaPsCF0P6MMHIjzbNmMZ+eDYf+wWghU4z7VfsYkvH1S0d6xD4hisC2Pj+vGdEVQH6H+0QR CXylOEG/2/BEQREGE1psut3u26oZhmnN8UcjfF1w/dccYi3mMR2f4NO7FzyA8A== 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 4YbD8G0tPjz8Tq; Sat, 18 Jan 2025 23:58:38 +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 50INwcxU073480; Sat, 18 Jan 2025 23:58:38 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 50INwckN073477; Sat, 18 Jan 2025 23:58:38 GMT (envelope-from git) Date: Sat, 18 Jan 2025 23:58:38 GMT Message-Id: <202501182358.50INwckN073477@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kristof Provost Subject: git: 685cafd668f5 - stable/14 - pf: allow ICMP messages related to an SCTP state to pass List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@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/stable/14 X-Git-Reftype: branch X-Git-Commit: 685cafd668f591e2a8afcd723fbb6b744ae07e31 Auto-Submitted: auto-generated The branch stable/14 has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=685cafd668f591e2a8afcd723fbb6b744ae07e31 commit 685cafd668f591e2a8afcd723fbb6b744ae07e31 Author: Kristof Provost AuthorDate: 2024-12-20 13:38:41 +0000 Commit: Kristof Provost CommitDate: 2025-01-18 21:10:22 +0000 pf: allow ICMP messages related to an SCTP state to pass Much like we already do for TCP and UDP we should also parse SCTP-in-ICMP messages to see if they apply to an SCTP connection we've already allowed. If so we should allow the ICMP packet to pass, even if we'd otherwise block it. Add a test case where we generate an 'ICMP unreachable - need to frag' packet and check that it passes through pf. MFC after: 2 weeks Sponsored by: Orange Business Services (cherry picked from commit 7d5e02b01577047290e937399accc02e6b184ce9) --- sys/netpfil/pf/pf.c | 91 +++++++++++++++++++++++++++++++++++++++++++- tests/sys/netpfil/pf/sctp.sh | 86 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+), 2 deletions(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 163eb2cedc27..18b907c45d38 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -6760,8 +6760,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif, if (pf_icmp_mapping(pd, icmptype, &icmp_dir, &multi, &virtual_id, &virtual_type) == 0) { /* - * ICMP query/reply message not related to a TCP/UDP packet. - * Search for an ICMP state. + * ICMP query/reply message not related to a TCP/UDP/SCTP + * packet. Search for an ICMP state. */ ret = pf_icmp_state_lookup(&key, pd, state, m, off, pd->dir, kif, virtual_id, virtual_type, icmp_dir, &iidx, @@ -7165,6 +7165,93 @@ pf_test_state_icmp(struct pf_kstate **state, struct pfi_kkif *kif, break; } #ifdef INET + case IPPROTO_SCTP: { + struct sctphdr sh; + struct pf_state_peer *src; + int copyback = 0; + + if (! pf_pull_hdr(m, off2, &sh, sizeof(sh), NULL, reason, + pd2.af)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message too short " + "(sctp)\n")); + return (PF_DROP); + } + + key.af = pd2.af; + key.proto = IPPROTO_SCTP; + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[pd2.sidx] = sh.src_port; + key.port[pd2.didx] = sh.dest_port; + + STATE_LOOKUP(kif, &key, *state, pd); + + if (pd->dir == (*state)->direction) { + src = &(*state)->dst; + } else { + src = &(*state)->src; + } + + if (src->scrub->pfss_v_tag != sh.v_tag) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message has incorrect " + "SCTP v_tag\n")); + return (PF_DROP); + } + + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; + + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != sh.src_port) + pf_change_icmp(pd2.src, &sh.src_port, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], NULL, + pd2.ip_sum, icmpsum, + pd->ip_sum, 0, pd2.af); + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != sh.dest_port) + pf_change_icmp(pd2.dst, &sh.dest_port, + saddr, &nk->addr[pd2.didx], + nk->port[pd2.didx], NULL, + pd2.ip_sum, icmpsum, + pd->ip_sum, 0, pd2.af); + copyback = 1; + } + + if (copyback) { + switch (pd2.af) { +#ifdef INET + case AF_INET: + m_copyback(m, off, ICMP_MINLEN, + (caddr_t )&pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t )&h2); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + m_copyback(m, off, + sizeof(struct icmp6_hdr), + (caddr_t )&pd->hdr.icmp6); + m_copyback(m, ipoff2, sizeof(h2_6), + (caddr_t )&h2_6); + break; +#endif /* INET6 */ + } + m_copyback(m, off2, sizeof(sh), (caddr_t)&sh); + } + + return (PF_PASS); + break; + } case IPPROTO_ICMP: { struct icmp *iih = &pd2.hdr.icmp; diff --git a/tests/sys/netpfil/pf/sctp.sh b/tests/sys/netpfil/pf/sctp.sh index 95a780747d82..563103827fac 100644 --- a/tests/sys/netpfil/pf/sctp.sh +++ b/tests/sys/netpfil/pf/sctp.sh @@ -745,6 +745,91 @@ timeout_cleanup() pft_cleanup } +atf_test_case "related_icmp" "cleanup" +related_icmp_head() +{ + atf_set descr 'Verify that ICMP messages related to an SCTP connection are allowed' + atf_set require.user root +} + +related_icmp_body() +{ + sctp_init + + epair_cl=$(vnet_mkepair) + epair_rtr=$(vnet_mkepair) + epair_srv=$(vnet_mkepair) + + ifconfig ${epair_cl}a 192.0.2.1/24 up + route add default 192.0.2.2 + + vnet_mkjail rtr ${epair_cl}b ${epair_rtr}a + jexec rtr ifconfig ${epair_cl}b 192.0.2.2/24 up + jexec rtr ifconfig ${epair_rtr}a 198.51.100.1/24 up + jexec rtr sysctl net.inet.ip.forwarding=1 + jexec rtr route add default 198.51.100.2 + + vnet_mkjail rtr2 ${epair_rtr}b ${epair_srv}a + jexec rtr2 ifconfig ${epair_rtr}b 198.51.100.2/24 up + jexec rtr2 ifconfig ${epair_srv}a 203.0.113.1/24 up + jexec rtr2 ifconfig ${epair_srv}a mtu 1300 + jexec rtr2 sysctl net.inet.ip.forwarding=1 + jexec rtr2 route add default 198.51.100.1 + + vnet_mkjail srv ${epair_srv}b + jexec srv ifconfig ${epair_srv}b 203.0.113.2/24 up + jexec srv ifconfig ${epair_srv}b mtu 1300 + jexec srv route add default 203.0.113.1 + + # Sanity checks + atf_check -s exit:0 -o ignore \ + ping -c 1 192.0.2.2 + atf_check -s exit:0 -o ignore \ + ping -c 1 198.51.100.1 + atf_check -s exit:0 -o ignore \ + ping -c 1 198.51.100.2 + atf_check -s exit:0 -o ignore \ + ping -c 1 203.0.113.1 + atf_check -s exit:0 -o ignore \ + ping -c 1 203.0.113.2 + + jexec rtr pfctl -e + pft_set_rules rtr \ + "block proto icmp" \ + "pass proto sctp" + + # Make sure SCTP traffic passes + echo "foo" | jexec srv nc --sctp -N -l 1234 & + sleep 1 + + out=$(nc --sctp -N -w 3 203.0.113.2 1234) + if [ "$out" != "foo" ]; then + jexec rtr pfctl -ss -vv + jexec rtr pfctl -sr -vv + atf_fail "SCTP connection failed" + fi + + # Do we see ICMP traffic if we send overly large traffic? + echo "foo" | jexec srv nc --sctp -N -l 1234 >/dev/null & + sleep 1 + + atf_check -s exit:0 -o not-match:".*destination unreachable:.*" \ + netstat -s -p icmp + + # Generate traffic that will be fragmented by rtr2, and will provoke an + # ICMP unreachable - need to frag (mtu 1300) message + dd if=/dev/random bs=1600 count=1 | nc --sctp -N -w 3 203.0.113.2 1234 + + # We'd expect to see an ICMP message + atf_check -s exit:0 -o match:".*destination unreachable: 1" \ + netstat -s -p icmp +} + +related_icmp_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { atf_add_test_case "basic_v4" @@ -757,4 +842,5 @@ atf_init_test_cases() atf_add_test_case "rdr_v4" atf_add_test_case "pfsync" atf_add_test_case "timeout" + atf_add_test_case "related_icmp" }