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 "set skip on lo" 117 118 # Host test 119 atf_check -s exit:0 -o ignore \ 120 ping -6 -c 1 2001:db8:42::2 121 122 atf_check -s exit:0 -o ignore \ 123 ping -6 -c 1 -s 4500 2001:db8:42::2 124 125 atf_check -s exit:0 -o ignore\ 126 ping -6 -c 1 -b 70000 -s 65000 2001:db8:42::2 127 128 # Force an NDP lookup 129 ping -6 -c 1 ${lladdr}%${epair_send}a 130 131 atf_check -s exit:0 -o ignore\ 132 ping -6 -c 1 -b 70000 -s 65000 ${lladdr}%${epair_send}a 133 134 # Forwarding test 135 atf_check -s exit:0 -o ignore \ 136 ping -6 -c 1 2001:db8:43::3 137 138 atf_check -s exit:0 -o ignore \ 139 ping -6 -c 1 -s 4500 2001:db8:43::3 140 141 atf_check -s exit:0 -o ignore\ 142 ping -6 -c 1 -b 70000 -s 65000 2001:db8:43::3 143 144 $(atf_get_srcdir)/CVE-2019-5597.py \ 145 ${epair_send}a \ 146 2001:db8:42::1 \ 147 2001:db8:43::3 148} 149 150v6_cleanup() 151{ 152 pft_cleanup 153} 154 155atf_test_case "mtu_diff" "cleanup" 156mtu_diff_head() 157{ 158 atf_set descr 'Test reassembly across different MTUs, PR #255432' 159 atf_set require.user root 160} 161 162mtu_diff_body() 163{ 164 pft_init 165 166 epair_small=$(vnet_mkepair) 167 epair_large=$(vnet_mkepair) 168 169 vnet_mkjail first ${epair_small}b ${epair_large}a 170 vnet_mkjail second ${epair_large}b 171 172 ifconfig ${epair_small}a 192.0.2.1/25 up 173 jexec first ifconfig ${epair_small}b 192.0.2.2/25 up 174 175 jexec first sysctl net.inet.ip.forwarding=1 176 jexec first ifconfig ${epair_large}a 192.0.2.130/25 up 177 jexec first ifconfig ${epair_large}a mtu 9000 178 jexec second ifconfig ${epair_large}b 192.0.2.131/25 up 179 jexec second ifconfig ${epair_large}b mtu 9000 180 jexec second route add default 192.0.2.130 181 182 route add 192.0.2.128/25 192.0.2.2 183 184 jexec first pfctl -e 185 pft_set_rules first \ 186 "scrub all fragment reassemble" 187 188 # Sanity checks 189 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 190 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.130 191 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.131 192 193 # Large packet that'll get reassembled and sent out in one on the large 194 # epair 195 atf_check -s exit:0 -o ignore ping -c 1 -s 8000 192.0.2.131 196} 197 198mtu_diff_cleanup() 199{ 200 pft_cleanup 201} 202 203frag_common() 204{ 205 name=$1 206 207 pft_init 208 209 epair=$(vnet_mkepair) 210 vnet_mkjail alcatraz ${epair}a 211 212 ifconfig ${epair}b inet 192.0.2.1/24 up 213 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 214 215 jexec alcatraz pfctl -e 216 pft_set_rules alcatraz \ 217 "scrub all fragment reassemble" 218 219 # Sanity check 220 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 221 222 atf_check -s exit:0 -o ignore $(atf_get_srcdir)/frag-${1}.py \ 223 --to 192.0.2.2 \ 224 --fromaddr 192.0.2.1 \ 225 --sendif ${epair}b \ 226 --recvif ${epair}b 227} 228 229atf_test_case "overreplace" "cleanup" 230overreplace_head() 231{ 232 atf_set descr 'ping fragment that overlaps fragment at index boundary and replace it' 233 atf_set require.user root 234 atf_set require.progs scapy 235} 236 237overreplace_body() 238{ 239 frag_common overreplace 240} 241 242overreplace_cleanup() 243{ 244 pft_cleanup 245} 246 247atf_test_case "overindex" "cleanup" 248overindex_head() 249{ 250 atf_set descr 'ping fragment that overlaps the first fragment at index boundary' 251 atf_set require.user root 252 atf_set require.progs scapy 253} 254 255overindex_body() 256{ 257 frag_common overindex 258} 259 260overindex_cleanup() 261{ 262 pft_cleanup 263} 264 265atf_test_case "overlimit" "cleanup" 266overlimit_head() 267{ 268 atf_set descr 'ping fragment at index boundary that cannot be requeued' 269 atf_set require.user root 270 atf_set require.progs scapy 271} 272 273overlimit_body() 274{ 275 frag_common overlimit 276} 277 278overlimit_cleanup() 279{ 280 pft_cleanup 281} 282 283atf_test_case "reassemble" "cleanup" 284reassemble_head() 285{ 286 atf_set descr 'Test reassembly' 287 atf_set require.user root 288} 289 290reassemble_body() 291{ 292 pft_init 293 294 epair=$(vnet_mkepair) 295 vnet_mkjail alcatraz ${epair}a 296 297 ifconfig ${epair}b inet 192.0.2.1/24 up 298 jexec alcatraz ifconfig ${epair}a 192.0.2.2/24 up 299 300 # Sanity check 301 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 302 303 jexec alcatraz pfctl -e 304 pft_set_rules alcatraz \ 305 "pass out" \ 306 "block in" \ 307 "pass in inet proto icmp all icmp-type echoreq" 308 309 # Single fragment passes 310 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 311 312 # But a fragmented ping does not 313 atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 314 315 pft_set_rules alcatraz \ 316 "scrub in" \ 317 "pass out" \ 318 "block in" \ 319 "pass in inet proto icmp all icmp-type echoreq" 320 321 # Both single packet & fragmented pass when we scrub 322 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 323 atf_check -s exit:0 -o ignore ping -c 1 -s 2000 192.0.2.2 324 325 pft_set_rules alcatraz \ 326 "scrub in fragment no reassemble" \ 327 "pass out" \ 328 "block in" \ 329 "pass in inet proto icmp all icmp-type echoreq" 330 331 # And the fragmented ping doesn't pass if we do not reassemble 332 atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2 333 atf_check -s exit:2 -o ignore ping -c 1 -s 2000 192.0.2.2 334} 335 336reassemble_cleanup() 337{ 338 pft_cleanup 339} 340 341atf_test_case "no_df" "cleanup" 342no_df_head() 343{ 344 atf_set descr 'Test removing of DF flag' 345 atf_set require.user root 346} 347 348no_df_body() 349{ 350 setup_router_server_ipv4 351 352 ifconfig ${epair_tester}a mtu 9000 353 jexec router ifconfig ${epair_tester}b mtu 9000 354 jexec router ifconfig ${epair_server}a mtu 1500 355 jexec server ifconfig ${epair_server}b mtu 1500 356 357 # Sanity check. 358 ping_server_check_reply exit:0 --ping-type=icmp 359 360 pft_set_rules router \ 361 "scrub fragment reassemble" \ 362 "pass out" \ 363 "block in" \ 364 "pass in inet proto icmp all icmp-type echoreq" 365 366 # Ping with normal, fragmentable packets. 367 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 368 369 # Ping with non-fragmentable packets, this will fail. 370 ping_server_check_reply exit:1 --ping-type=icmp --send-length=2000 --send-flags DF 371 372 pft_set_rules router \ 373 "scrub any reassemble" \ 374 "pass out" \ 375 "block in" \ 376 "pass in inet proto icmp all icmp-type echoreq" 377 378 # Ping with non-fragmentable packets again. 379 # This time pf will strip the DF flag. 380 ping_server_check_reply exit:0 --ping-type=icmp --send-length=2000 --send-flags DF 381} 382 383no_df_cleanup() 384{ 385 pft_cleanup 386} 387 388atf_init_test_cases() 389{ 390 atf_add_test_case "too_many_fragments" 391 atf_add_test_case "v6" 392 atf_add_test_case "mtu_diff" 393 atf_add_test_case "overreplace" 394 atf_add_test_case "overindex" 395 atf_add_test_case "overlimit" 396 atf_add_test_case "reassemble" 397} 398