1# $FreeBSD$ 2# 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2017 Kristof Provost <kp@FreeBSD.org> 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27 28. $(atf_get_srcdir)/utils.subr 29 30atf_test_case "too_many_fragments" "cleanup" 31 32too_many_fragments_head() 33{ 34 atf_set descr 'IPv4 fragment limitation test' 35 atf_set require.user root 36} 37 38too_many_fragments_body() 39{ 40 pft_init 41 42 epair=$(vnet_mkepair) 43 vnet_mkjail alcatraz ${epair}a 44 45 ifconfig ${epair}b inet 192.0.2.1/24 up 46 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 47 48 ifconfig ${epair}b mtu 200 49 jexec alcatraz ifconfig ${epair}a mtu 200 50 51 jexec alcatraz pfctl -e 52 pft_set_rules alcatraz \ 53 "scrub all fragment reassemble" 54 55 # So we know pf is limiting things 56 jexec alcatraz sysctl net.inet.ip.maxfragsperpacket=1024 57 58 # Sanity check 59 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 60 61 # We can ping with < 64 fragments 62 atf_check -s exit:0 -o ignore ping -c 1 -s 800 192.0.2.2 63 64 # Too many fragments should fail 65 atf_check -s exit:2 -o ignore ping -c 1 -s 20000 192.0.2.2 66} 67 68too_many_fragments_cleanup() 69{ 70 pft_cleanup 71} 72 73atf_test_case "v6" "cleanup" 74v6_head() 75{ 76 atf_set descr 'IPv6 fragmentation test' 77 atf_set require.user root 78 atf_set require.progs scapy 79} 80 81v6_body() 82{ 83 pft_init 84 85 epair_send=$(vnet_mkepair) 86 epair_link=$(vnet_mkepair) 87 88 vnet_mkjail alcatraz ${epair_send}b ${epair_link}a 89 vnet_mkjail singsing ${epair_link}b 90 91 ifconfig ${epair_send}a inet6 2001:db8:42::1/64 no_dad up 92 93 jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 no_dad up 94 jexec alcatraz ifconfig ${epair_link}a inet6 2001:db8:43::2/64 no_dad up 95 jexec alcatraz sysctl net.inet6.ip6.forwarding=1 96 97 jexec singsing ifconfig ${epair_link}b inet6 2001:db8:43::3/64 no_dad up 98 jexec singsing route add -6 2001:db8:42::/64 2001:db8:43::2 99 route add -6 2001:db8:43::/64 2001:db8:42::2 100 101 jexec alcatraz ifconfig ${epair_send}b inet6 -ifdisabled 102 jexec alcatraz ifconfig ${epair_link}a inet6 -ifdisabled 103 jexec singsing ifconfig ${epair_link}b inet6 -ifdisabled 104 ifconfig ${epair_send}a inet6 -ifdisabled 105 106 ifconfig ${epair_send}a 107 jexec alcatraz ifconfig ${epair_send}b 108 lladdr=$(jexec alcatraz ifconfig ${epair_send}b | awk '/ scopeid / { print($2); }' | cut -f 1 -d %) 109 110 jexec alcatraz pfctl -e 111 pft_set_rules alcatraz \ 112 "scrub fragment reassemble" \ 113 "block in" \ 114 "pass in inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ 115 "pass in inet6 proto icmp6 icmp6-type { echoreq, echorep }" 116 117 # Host test 118 atf_check -s exit:0 -o ignore \ 119 ping -6 -c 1 2001:db8:42::2 120 121 atf_check -s exit:0 -o ignore \ 122 ping -6 -c 1 -s 4500 2001:db8:42::2 123 124 atf_check -s exit:0 -o ignore\ 125 ping -6 -c 1 -b 70000 -s 65000 2001:db8:42::2 126 127 # Force an NDP lookup 128 ping -6 -c 1 ${lladdr}%${epair_send}a 129 130 atf_check -s exit:0 -o ignore\ 131 ping -6 -c 1 -b 70000 -s 65000 ${lladdr}%${epair_send}a 132 133 # Forwarding test 134 atf_check -s exit:0 -o ignore \ 135 ping -6 -c 1 2001:db8:43::3 136 137 atf_check -s exit:0 -o ignore \ 138 ping -6 -c 1 -s 4500 2001:db8:43::3 139 140 atf_check -s exit:0 -o ignore\ 141 ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3 142 143 $(atf_get_srcdir)/CVE-2019-5597.py \ 144 ${epair_send}a \ 145 2001:db8:42::1 \ 146 2001:db8:43::3 147} 148 149v6_cleanup() 150{ 151 pft_cleanup 152} 153 154atf_test_case "mtu_diff" "cleanup" 155mtu_diff_head() 156{ 157 atf_set descr 'Test reassembly across different MTUs, PR #255432' 158 atf_set require.user root 159} 160 161mtu_diff_body() 162{ 163 pft_init 164 165 epair_small=$(vnet_mkepair) 166 epair_large=$(vnet_mkepair) 167 168 vnet_mkjail first ${epair_small}b ${epair_large}a 169 vnet_mkjail second ${epair_large}b 170 171 ifconfig ${epair_small}a 192.0.2.1/25 up 172 jexec first ifconfig ${epair_small}b 192.0.2.2/25 up 173 174 jexec first sysctl net.inet.ip.forwarding=1 175 jexec first ifconfig ${epair_large}a 192.0.2.130/25 up 176 jexec first ifconfig ${epair_large}a mtu 9000 177 jexec second ifconfig ${epair_large}b 192.0.2.131/25 up 178 jexec second ifconfig ${epair_large}b mtu 9000 179 jexec second route add default 192.0.2.130 180 181 route add 192.0.2.128/25 192.0.2.2 182 183 jexec first pfctl -e 184 pft_set_rules first \ 185 "scrub all fragment reassemble" 186 187 # Sanity checks 188 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 189 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.130 190 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.131 191 192 # Large packet that'll get reassembled and sent out in one on the large 193 # epair 194 atf_check -s exit:0 -o ignore ping -c 1 -s 8000 192.0.2.131 195} 196 197mtu_diff_cleanup() 198{ 199 pft_cleanup 200} 201 202frag_common() 203{ 204 name=$1 205 206 pft_init 207 208 epair=$(vnet_mkepair) 209 vnet_mkjail alcatraz ${epair}a 210 211 ifconfig ${epair}b inet 192.0.2.1/24 up 212 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 213 214 jexec alcatraz pfctl -e 215 pft_set_rules alcatraz \ 216 "scrub all fragment reassemble" 217 218 # Sanity check 219 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 220 221 atf_check -s exit:0 -o ignore $(atf_get_srcdir)/frag-${1}.py \ 222 --to 192.0.2.2 \ 223 --fromaddr 192.0.2.1 \ 224 --sendif ${epair}b \ 225 --recvif ${epair}b 226} 227 228atf_test_case "overreplace" "cleanup" 229overreplace_head() 230{ 231 atf_set descr 'ping fragment that overlaps fragment at index boundary and replace it' 232 atf_set require.user root 233 atf_set require.progs scapy 234} 235 236overreplace_body() 237{ 238 frag_common overreplace 239} 240 241overreplace_cleanup() 242{ 243 pft_cleanup 244} 245 246atf_test_case "overindex" "cleanup" 247overindex_head() 248{ 249 atf_set descr 'ping fragment that overlaps the first fragment at index boundary' 250 atf_set require.user root 251 atf_set require.progs scapy 252} 253 254overindex_body() 255{ 256 frag_common overindex 257} 258 259overindex_cleanup() 260{ 261 pft_cleanup 262} 263 264atf_test_case "overlimit" "cleanup" 265overlimit_head() 266{ 267 atf_set descr 'ping fragment at index boundary that cannot be requeued' 268 atf_set require.user root 269 atf_set require.progs scapy 270} 271 272overlimit_body() 273{ 274 frag_common overlimit 275} 276 277overlimit_cleanup() 278{ 279 pft_cleanup 280} 281 282atf_test_case "reassemble" "cleanup" 283reassemble_head() 284{ 285 atf_set descr 'Test reassembly' 286 atf_set require.user root 287} 288 289reassemble_body() 290{ 291 pft_init 292 293 epair=$(vnet_mkepair) 294 vnet_mkjail alcatraz ${epair}a 295 296 ifconfig ${epair}b inet 192.0.2.1/24 up 297 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 298 299 # Sanity check 300 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 301 302 jexec alcatraz pfctl -e 303 pft_set_rules alcatraz \ 304 "pass out" \ 305 "block in" \ 306 "pass in inet proto icmp all icmp-type echoreq" 307 308 # Single fragment passes 309 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 310 311 # But a fragmented ping does not 312 atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 313 314 pft_set_rules alcatraz \ 315 "scrub in" \ 316 "pass out" \ 317 "block in" \ 318 "pass in inet proto icmp all icmp-type echoreq" 319 320 # Both single packet & fragmented pass when we scrub 321 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 322 atf_check -s exit:0 -o ignore ping -c 1 -s 2000 192.0.2.2 323 324 pft_set_rules alcatraz \ 325 "scrub in fragment no reassemble" \ 326 "pass out" \ 327 "block in" \ 328 "pass in inet proto icmp all icmp-type echoreq" 329 330 # And the fragmented ping doesn't pass if we do not reassemble 331 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 332 atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 333} 334 335reassemble_cleanup() 336{ 337 pft_cleanup 338} 339 340atf_test_case "no_df" "cleanup" 341no_df_head() 342{ 343 atf_set descr 'Test removing of DF flag' 344 atf_set require.user root 345} 346 347no_df_body() 348{ 349 setup_router_server_ipv4 350 351 ifconfig ${epair_tester}a mtu 9000 352 jexec router ifconfig ${epair_tester}b mtu 9000 353 jexec router ifconfig ${epair_server}a mtu 1500 354 jexec server ifconfig ${epair_server}b mtu 1500 355 356 # Sanity check. 357 ping_server_check_reply exit:0 --ping-type=icmp 358 359 pft_set_rules router \ 360 "scrub fragment reassemble" \ 361 "pass out" \ 362 "block in" \ 363 "pass in inet proto icmp all icmp-type echoreq" 364 365 # Ping with normal, fragmentable packets. 366 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 367 368 # Ping with non-fragmentable packets, this will fail. 369 ping_server_check_reply exit:1 --ping-type=icmp --send-length=2000 --send-flags DF 370 371 pft_set_rules router \ 372 "scrub any reassemble" \ 373 "pass out" \ 374 "block in" \ 375 "pass in inet proto icmp all icmp-type echoreq" 376 377 # Ping with non-fragmentable packets again. 378 # This time pf will strip the DF flag. 379 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 --send-flags DF 380} 381 382no_df_cleanup() 383{ 384 pft_cleanup 385} 386 387atf_init_test_cases() 388{ 389 atf_add_test_case "too_many_fragments" 390 atf_add_test_case "v6" 391 atf_add_test_case "mtu_diff" 392 atf_add_test_case "overreplace" 393 atf_add_test_case "overindex" 394 atf_add_test_case "overlimit" 395 atf_add_test_case "reassemble" 396} 397