Page MenuHomeFreeBSD

D48170.diff
No OneTemporary

D48170.diff

diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -7738,8 +7738,8 @@
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, pd->dir,
virtual_id, virtual_type, icmp_dir, &iidx,
@@ -8244,6 +8244,139 @@
break;
}
#ifdef INET
+ case IPPROTO_SCTP: {
+ struct sctphdr sh;
+ struct pf_state_peer *src;
+ int copyback = 0;
+
+ if (! pf_pull_hdr(pd->m, pd2.off, &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(&key, *state, pd);
+
+ if (pd->dir == (*state)->direction) {
+ if (PF_REVERSED_KEY((*state)->key, pd->af))
+ src = &(*state)->src;
+ else
+ src = &(*state)->dst;
+ } else {
+ if (PF_REVERSED_KEY((*state)->key, pd->af))
+ 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;
+
+ if (PF_REVERSED_KEY((*state)->key, pd->af))
+ nk = (*state)->key[pd->sidx];
+ else
+ nk = (*state)->key[pd->didx];
+
+#if defined(INET) && defined(INET6)
+ int afto, sidx, didx;
+
+ afto = pd->af != nk->af;
+ sidx = afto ? pd2.didx : pd2.sidx;
+ didx = afto ? pd2.sidx : pd2.didx;
+
+ if (afto) {
+ if (pf_translate_icmp_af(nk->af,
+ &pd->hdr.icmp))
+ return (PF_DROP);
+ m_copyback(pd->m, pd->off,
+ sizeof(struct icmp6_hdr),
+ (c_caddr_t)&pd->hdr.icmp6);
+ if (pf_change_icmp_af(pd->m, ipoff2, pd,
+ &pd2, &nk->addr[sidx],
+ &nk->addr[didx], pd->af,
+ nk->af))
+ return (PF_DROP);
+ if (nk->af == AF_INET)
+ pd->proto = IPPROTO_ICMP;
+ else
+ pd->proto = IPPROTO_ICMPV6;
+ sh.src_port = nk->port[sidx];
+ sh.dest_port = nk->port[didx];
+ m_copyback(pd2.m, pd2.off, sizeof(sh), (c_caddr_t)&sh);
+ PF_ACPY(pd->src,
+ &nk->addr[pd2.sidx], nk->af);
+ PF_ACPY(pd->dst,
+ &nk->addr[pd2.didx], nk->af);
+ pd->naf = nk->af;
+ return (PF_AFRT);
+ }
+#endif
+
+ 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(pd->m, pd->off, ICMP_MINLEN,
+ (caddr_t )&pd->hdr.icmp);
+ m_copyback(pd->m, ipoff2, sizeof(h2),
+ (caddr_t )&h2);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ m_copyback(pd->m, pd->off,
+ sizeof(struct icmp6_hdr),
+ (caddr_t )&pd->hdr.icmp6);
+ m_copyback(pd->m, ipoff2, sizeof(h2_6),
+ (caddr_t )&h2_6);
+ break;
+#endif /* INET6 */
+ }
+ m_copyback(pd->m, pd2.off, 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
--- a/tests/sys/netpfil/pf/sctp.sh
+++ b/tests/sys/netpfil/pf/sctp.sh
@@ -745,6 +745,91 @@
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_add_test_case "rdr_v4"
atf_add_test_case "pfsync"
atf_add_test_case "timeout"
+ atf_add_test_case "related_icmp"
}

File Metadata

Mime Type
text/plain
Expires
Thu, Dec 26, 6:28 AM (12 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15602084
Default Alt Text
D48170.diff (6 KB)

Event Timeline