Page MenuHomeFreeBSD

D56559.id176027.diff
No OneTemporary

D56559.id176027.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
@@ -9804,6 +9804,16 @@
ip = mtod(m0, struct ip *);
+ if ((pd->m->m_flags & (M_BCAST|M_MCAST)) ||
+ IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
+ (ifp != NULL && in_ifnet_broadcast(ip->ip_dst, ifp))) {
+ m0 = pd->m;
+ pd->m = NULL;
+ SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
+ action = PF_DROP;
+ goto bad_locked;
+ }
+
bzero(&ro, sizeof(ro));
dst = (union sockaddr_union *)&ro.ro_dst;
dst->sin.sin_family = AF_INET;
@@ -10155,6 +10165,15 @@
ip6 = mtod(m0, struct ip6_hdr *);
+ if (pd->m->m_flags & (M_BCAST|M_MCAST) ||
+ IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+ m0 = pd->m;
+ pd->m = NULL;
+ SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
+ action = PF_DROP;
+ goto bad_locked;
+ }
+
bzero(&dst, sizeof(dst));
dst.sin6_family = AF_INET6;
dst.sin6_len = sizeof(dst);
diff --git a/tests/sys/netpfil/pf/route_to.sh b/tests/sys/netpfil/pf/route_to.sh
--- a/tests/sys/netpfil/pf/route_to.sh
+++ b/tests/sys/netpfil/pf/route_to.sh
@@ -97,6 +97,66 @@
done
}
+# Setup the environment for the bcast_* tests.
+bcast_setup()
+{
+ pft_init
+
+ epair_lan=$(vnet_mkepair)
+ epair_wan=$(vnet_mkepair)
+
+ # client (lan)
+ vnet_mkjail client ${epair_lan}a
+ jexec client ifconfig ${epair_lan}a 192.0.2.2/24 up
+ jexec client route add default 192.0.2.1
+
+ # router
+ vnet_mkjail router ${epair_lan}b ${epair_wan}a
+ jexec router ifconfig ${epair_lan}b 192.0.2.1/24 up
+ jexec router ifconfig ${epair_wan}a 198.51.100.1/24 up
+ jexec router sysctl net.inet.ip.forwarding=1
+ jexec router pfctl -e
+
+ # wan
+ vnet_mkjail wan ${epair_wan}b
+ jexec wan ifconfig ${epair_wan}b 198.51.100.2/24 up
+ jexec wan pfctl -e
+ pft_set_rules wan \
+ "pass" \
+ "pass in on ${epair_wan}b inet proto udp from any to any port 5000 label bcast_leak_probe"
+
+ # Sanity check before proceeding.
+ atf_check -s exit:0 -o ignore jexec client ping -c 1 -t 1 192.0.2.1
+}
+
+# Install the router ruleset for bcast_* tests.
+bcast_install_rules()
+{
+ pft_set_rules router \
+ "block all" \
+ "pass out keep state" \
+ "pass in on ${epair_lan}b inet proto icmp all keep state" \
+ "$@"
+}
+
+# Packet count observed by the probe rule in the wan jail.
+bcast_probe_pkts()
+{
+ jexec wan pfctl -sl | awk '$1 == "bcast_leak_probe" { print $3 }'
+}
+
+# Send one UDP broadcast datagram from the client jail.
+bcast_send()
+{
+ atf_check -s exit:0 -o ignore \
+ jexec client ${common_dir}/pft_ping.py \
+ --sendif ${epair_lan}a \
+ --recvif ${epair_lan}a \
+ --to "$1" \
+ --ping-type=udp \
+ --send-dport=5000
+}
+
atf_test_case "v4" "cleanup"
v4_head()
{
@@ -1647,6 +1707,88 @@
pft_cleanup
}
+atf_test_case "bcast_baseline" "cleanup"
+bcast_baseline_head()
+{
+ atf_set descr 'Test that broadcasts are dropped without route-to'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+bcast_baseline_body()
+{
+ bcast_setup
+
+ bcast_install_rules
+
+ bcast_send 255.255.255.255
+ bcast_send 198.51.100.255
+
+ pkts=$(bcast_probe_pkts)
+ if [ "${pkts:-0}" -ne 0 ]; then
+ jexec wan pfctl -vvsr
+ atf_fail "traffic reached wan without route-to (${pkts} packet(s))"
+ fi
+}
+bcast_baseline_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "bcast_directed" "cleanup"
+bcast_directed_head()
+{
+ atf_set descr 'Test that route-to does not forward UDP subnet directed broadcasts'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+bcast_directed_body()
+{
+ bcast_setup
+
+ bcast_install_rules \
+ "pass in on ${epair_lan}b route-to (${epair_wan}a 198.51.100.2) inet proto udp from any to any keep state"
+
+ bcast_send 198.51.100.255
+
+ pkts=$(bcast_probe_pkts)
+ if [ "${pkts:-0}" -ne 0 ]; then
+ jexec wan pfctl -vvsr
+ atf_fail "directed broadcast leaked to wan (${pkts} packet(s))"
+ fi
+}
+bcast_directed_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "bcast_limited" "cleanup"
+bcast_limited_head()
+{
+ atf_set descr 'Test that route-to does not forward UDP limited broadcasts'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+bcast_limited_body()
+{
+ bcast_setup
+
+ # Install the route-to rule
+ bcast_install_rules \
+ "pass in on ${epair_lan}b route-to (${epair_wan}a 198.51.100.2) inet proto udp from any to any keep state"
+
+ bcast_send 255.255.255.255
+
+ pkts=$(bcast_probe_pkts)
+ if [ "${pkts:-0}" -ne 0 ]; then
+ jexec wan pfctl -vvsr
+ atf_fail "limited broadcast leaked to wan (${pkts} packet(s))"
+ fi
+}
+bcast_limited_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "v4"
@@ -1666,6 +1808,9 @@
atf_add_test_case "sticky"
atf_add_test_case "ttl"
atf_add_test_case "empty_pool"
+ atf_add_test_case "bcast_baseline"
+ atf_add_test_case "bcast_directed"
+ atf_add_test_case "bcast_limited"
# Tests for pf_map_addr() without prefer-ipv6-nexthop
atf_add_test_case "table_loop"
atf_add_test_case "roundrobin"

File Metadata

Mime Type
text/plain
Expires
Thu, Jun 18, 1:41 PM (3 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34051736
Default Alt Text
D56559.id176027.diff (4 KB)

Event Timeline