1#!/bin/bash 2# 3# This test is for basic NAT functionality: snat, dnat, redirect, masquerade. 4# 5 6# Kselftest framework requirement - SKIP code is 4. 7ksft_skip=4 8ret=0 9test_inet_nat=true 10 11sfx=$(mktemp -u "XXXXXXXX") 12ns0="ns0-$sfx" 13ns1="ns1-$sfx" 14ns2="ns2-$sfx" 15 16cleanup() 17{ 18 for i in 0 1 2; do ip netns del ns$i-"$sfx";done 19} 20 21nft --version > /dev/null 2>&1 22if [ $? -ne 0 ];then 23 echo "SKIP: Could not run test without nft tool" 24 exit $ksft_skip 25fi 26 27ip -Version > /dev/null 2>&1 28if [ $? -ne 0 ];then 29 echo "SKIP: Could not run test without ip tool" 30 exit $ksft_skip 31fi 32 33ip netns add "$ns0" 34if [ $? -ne 0 ];then 35 echo "SKIP: Could not create net namespace $ns0" 36 exit $ksft_skip 37fi 38 39trap cleanup EXIT 40 41ip netns add "$ns1" 42if [ $? -ne 0 ];then 43 echo "SKIP: Could not create net namespace $ns1" 44 exit $ksft_skip 45fi 46 47ip netns add "$ns2" 48if [ $? -ne 0 ];then 49 echo "SKIP: Could not create net namespace $ns2" 50 exit $ksft_skip 51fi 52 53ip link add veth0 netns "$ns0" type veth peer name eth0 netns "$ns1" > /dev/null 2>&1 54if [ $? -ne 0 ];then 55 echo "SKIP: No virtual ethernet pair device support in kernel" 56 exit $ksft_skip 57fi 58ip link add veth1 netns "$ns0" type veth peer name eth0 netns "$ns2" 59 60ip -net "$ns0" link set lo up 61ip -net "$ns0" link set veth0 up 62ip -net "$ns0" addr add 10.0.1.1/24 dev veth0 63ip -net "$ns0" addr add dead:1::1/64 dev veth0 64 65ip -net "$ns0" link set veth1 up 66ip -net "$ns0" addr add 10.0.2.1/24 dev veth1 67ip -net "$ns0" addr add dead:2::1/64 dev veth1 68 69for i in 1 2; do 70 ip -net ns$i-$sfx link set lo up 71 ip -net ns$i-$sfx link set eth0 up 72 ip -net ns$i-$sfx addr add 10.0.$i.99/24 dev eth0 73 ip -net ns$i-$sfx route add default via 10.0.$i.1 74 ip -net ns$i-$sfx addr add dead:$i::99/64 dev eth0 75 ip -net ns$i-$sfx route add default via dead:$i::1 76done 77 78bad_counter() 79{ 80 local ns=$1 81 local counter=$2 82 local expect=$3 83 local tag=$4 84 85 echo "ERROR: $counter counter in $ns has unexpected value (expected $expect) at $tag" 1>&2 86 ip netns exec $ns nft list counter inet filter $counter 1>&2 87} 88 89check_counters() 90{ 91 ns=$1 92 local lret=0 93 94 cnt=$(ip netns exec $ns nft list counter inet filter ns0in | grep -q "packets 1 bytes 84") 95 if [ $? -ne 0 ]; then 96 bad_counter $ns ns0in "packets 1 bytes 84" "check_counters 1" 97 lret=1 98 fi 99 cnt=$(ip netns exec $ns nft list counter inet filter ns0out | grep -q "packets 1 bytes 84") 100 if [ $? -ne 0 ]; then 101 bad_counter $ns ns0out "packets 1 bytes 84" "check_counters 2" 102 lret=1 103 fi 104 105 expect="packets 1 bytes 104" 106 cnt=$(ip netns exec $ns nft list counter inet filter ns0in6 | grep -q "$expect") 107 if [ $? -ne 0 ]; then 108 bad_counter $ns ns0in6 "$expect" "check_counters 3" 109 lret=1 110 fi 111 cnt=$(ip netns exec $ns nft list counter inet filter ns0out6 | grep -q "$expect") 112 if [ $? -ne 0 ]; then 113 bad_counter $ns ns0out6 "$expect" "check_counters 4" 114 lret=1 115 fi 116 117 return $lret 118} 119 120check_ns0_counters() 121{ 122 local ns=$1 123 local lret=0 124 125 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0in | grep -q "packets 0 bytes 0") 126 if [ $? -ne 0 ]; then 127 bad_counter "$ns0" ns0in "packets 0 bytes 0" "check_ns0_counters 1" 128 lret=1 129 fi 130 131 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0in6 | grep -q "packets 0 bytes 0") 132 if [ $? -ne 0 ]; then 133 bad_counter "$ns0" ns0in6 "packets 0 bytes 0" 134 lret=1 135 fi 136 137 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0out | grep -q "packets 0 bytes 0") 138 if [ $? -ne 0 ]; then 139 bad_counter "$ns0" ns0out "packets 0 bytes 0" "check_ns0_counters 2" 140 lret=1 141 fi 142 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0out6 | grep -q "packets 0 bytes 0") 143 if [ $? -ne 0 ]; then 144 bad_counter "$ns0" ns0out6 "packets 0 bytes 0" "check_ns0_counters3 " 145 lret=1 146 fi 147 148 for dir in "in" "out" ; do 149 expect="packets 1 bytes 84" 150 cnt=$(ip netns exec "$ns0" nft list counter inet filter ${ns}${dir} | grep -q "$expect") 151 if [ $? -ne 0 ]; then 152 bad_counter "$ns0" $ns$dir "$expect" "check_ns0_counters 4" 153 lret=1 154 fi 155 156 expect="packets 1 bytes 104" 157 cnt=$(ip netns exec "$ns0" nft list counter inet filter ${ns}${dir}6 | grep -q "$expect") 158 if [ $? -ne 0 ]; then 159 bad_counter "$ns0" $ns$dir6 "$expect" "check_ns0_counters 5" 160 lret=1 161 fi 162 done 163 164 return $lret 165} 166 167reset_counters() 168{ 169 for i in 0 1 2;do 170 ip netns exec ns$i-$sfx nft reset counters inet > /dev/null 171 done 172} 173 174test_local_dnat6() 175{ 176 local family=$1 177 local lret=0 178 local IPF="" 179 180 if [ $family = "inet" ];then 181 IPF="ip6" 182 fi 183 184ip netns exec "$ns0" nft -f /dev/stdin <<EOF 185table $family nat { 186 chain output { 187 type nat hook output priority 0; policy accept; 188 ip6 daddr dead:1::99 dnat $IPF to dead:2::99 189 } 190} 191EOF 192 if [ $? -ne 0 ]; then 193 echo "SKIP: Could not add add $family dnat hook" 194 return $ksft_skip 195 fi 196 197 # ping netns1, expect rewrite to netns2 198 ip netns exec "$ns0" ping -q -c 1 dead:1::99 > /dev/null 199 if [ $? -ne 0 ]; then 200 lret=1 201 echo "ERROR: ping6 failed" 202 return $lret 203 fi 204 205 expect="packets 0 bytes 0" 206 for dir in "in6" "out6" ; do 207 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 208 if [ $? -ne 0 ]; then 209 bad_counter "$ns0" ns1$dir "$expect" "test_local_dnat6 1" 210 lret=1 211 fi 212 done 213 214 expect="packets 1 bytes 104" 215 for dir in "in6" "out6" ; do 216 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 217 if [ $? -ne 0 ]; then 218 bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat6 2" 219 lret=1 220 fi 221 done 222 223 # expect 0 count in ns1 224 expect="packets 0 bytes 0" 225 for dir in "in6" "out6" ; do 226 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 227 if [ $? -ne 0 ]; then 228 bad_counter "$ns1" ns0$dir "$expect" "test_local_dnat6 3" 229 lret=1 230 fi 231 done 232 233 # expect 1 packet in ns2 234 expect="packets 1 bytes 104" 235 for dir in "in6" "out6" ; do 236 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect") 237 if [ $? -ne 0 ]; then 238 bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat6 4" 239 lret=1 240 fi 241 done 242 243 test $lret -eq 0 && echo "PASS: ipv6 ping to $ns1 was $family NATted to $ns2" 244 ip netns exec "$ns0" nft flush chain ip6 nat output 245 246 return $lret 247} 248 249test_local_dnat() 250{ 251 local family=$1 252 local lret=0 253 local IPF="" 254 255 if [ $family = "inet" ];then 256 IPF="ip" 257 fi 258 259ip netns exec "$ns0" nft -f /dev/stdin <<EOF 2>/dev/null 260table $family nat { 261 chain output { 262 type nat hook output priority 0; policy accept; 263 ip daddr 10.0.1.99 dnat $IPF to 10.0.2.99 264 } 265} 266EOF 267 if [ $? -ne 0 ]; then 268 if [ $family = "inet" ];then 269 echo "SKIP: inet nat tests" 270 test_inet_nat=false 271 return $ksft_skip 272 fi 273 echo "SKIP: Could not add add $family dnat hook" 274 return $ksft_skip 275 fi 276 277 # ping netns1, expect rewrite to netns2 278 ip netns exec "$ns0" ping -q -c 1 10.0.1.99 > /dev/null 279 if [ $? -ne 0 ]; then 280 lret=1 281 echo "ERROR: ping failed" 282 return $lret 283 fi 284 285 expect="packets 0 bytes 0" 286 for dir in "in" "out" ; do 287 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 288 if [ $? -ne 0 ]; then 289 bad_counter "$ns0" ns1$dir "$expect" "test_local_dnat 1" 290 lret=1 291 fi 292 done 293 294 expect="packets 1 bytes 84" 295 for dir in "in" "out" ; do 296 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 297 if [ $? -ne 0 ]; then 298 bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat 2" 299 lret=1 300 fi 301 done 302 303 # expect 0 count in ns1 304 expect="packets 0 bytes 0" 305 for dir in "in" "out" ; do 306 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 307 if [ $? -ne 0 ]; then 308 bad_counter "$ns1" ns0$dir "$expect" "test_local_dnat 3" 309 lret=1 310 fi 311 done 312 313 # expect 1 packet in ns2 314 expect="packets 1 bytes 84" 315 for dir in "in" "out" ; do 316 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect") 317 if [ $? -ne 0 ]; then 318 bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat 4" 319 lret=1 320 fi 321 done 322 323 test $lret -eq 0 && echo "PASS: ping to $ns1 was $family NATted to $ns2" 324 325 ip netns exec "$ns0" nft flush chain $family nat output 326 327 reset_counters 328 ip netns exec "$ns0" ping -q -c 1 10.0.1.99 > /dev/null 329 if [ $? -ne 0 ]; then 330 lret=1 331 echo "ERROR: ping failed" 332 return $lret 333 fi 334 335 expect="packets 1 bytes 84" 336 for dir in "in" "out" ; do 337 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 338 if [ $? -ne 0 ]; then 339 bad_counter "$ns1" ns1$dir "$expect" "test_local_dnat 5" 340 lret=1 341 fi 342 done 343 expect="packets 0 bytes 0" 344 for dir in "in" "out" ; do 345 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 346 if [ $? -ne 0 ]; then 347 bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat 6" 348 lret=1 349 fi 350 done 351 352 # expect 1 count in ns1 353 expect="packets 1 bytes 84" 354 for dir in "in" "out" ; do 355 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 356 if [ $? -ne 0 ]; then 357 bad_counter "$ns0" ns0$dir "$expect" "test_local_dnat 7" 358 lret=1 359 fi 360 done 361 362 # expect 0 packet in ns2 363 expect="packets 0 bytes 0" 364 for dir in "in" "out" ; do 365 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect") 366 if [ $? -ne 0 ]; then 367 bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat 8" 368 lret=1 369 fi 370 done 371 372 test $lret -eq 0 && echo "PASS: ping to $ns1 OK after $family nat output chain flush" 373 374 return $lret 375} 376 377test_local_dnat_portonly() 378{ 379 local family=$1 380 local daddr=$2 381 local lret=0 382 local sr_s 383 local sr_r 384 385ip netns exec "$ns0" nft -f /dev/stdin <<EOF 386table $family nat { 387 chain output { 388 type nat hook output priority 0; policy accept; 389 meta l4proto tcp dnat to :2000 390 391 } 392} 393EOF 394 if [ $? -ne 0 ]; then 395 if [ $family = "inet" ];then 396 echo "SKIP: inet port test" 397 test_inet_nat=false 398 return 399 fi 400 echo "SKIP: Could not add $family dnat hook" 401 return 402 fi 403 404 echo SERVER-$family | ip netns exec "$ns1" timeout 5 socat -u STDIN TCP-LISTEN:2000 & 405 sc_s=$! 406 407 result=$(ip netns exec "$ns0" timeout 1 socat TCP:$daddr:2000 STDOUT) 408 409 if [ "$result" = "SERVER-inet" ];then 410 echo "PASS: inet port rewrite without l3 address" 411 else 412 echo "ERROR: inet port rewrite" 413 ret=1 414 fi 415} 416 417test_masquerade6() 418{ 419 local family=$1 420 local natflags=$2 421 local lret=0 422 423 ip netns exec "$ns0" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null 424 425 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 426 if [ $? -ne 0 ] ; then 427 echo "ERROR: cannot ping $ns1 from $ns2 via ipv6" 428 return 1 429 lret=1 430 fi 431 432 expect="packets 1 bytes 104" 433 for dir in "in6" "out6" ; do 434 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 435 if [ $? -ne 0 ]; then 436 bad_counter "$ns1" ns2$dir "$expect" "test_masquerade6 1" 437 lret=1 438 fi 439 440 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 441 if [ $? -ne 0 ]; then 442 bad_counter "$ns2" ns1$dir "$expect" "test_masquerade6 2" 443 lret=1 444 fi 445 done 446 447 reset_counters 448 449# add masquerading rule 450ip netns exec "$ns0" nft -f /dev/stdin <<EOF 451table $family nat { 452 chain postrouting { 453 type nat hook postrouting priority 0; policy accept; 454 meta oif veth0 masquerade $natflags 455 } 456} 457EOF 458 if [ $? -ne 0 ]; then 459 echo "SKIP: Could not add add $family masquerade hook" 460 return $ksft_skip 461 fi 462 463 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 464 if [ $? -ne 0 ] ; then 465 echo "ERROR: cannot ping $ns1 from $ns2 with active $family masquerade $natflags" 466 lret=1 467 fi 468 469 # ns1 should have seen packets from ns0, due to masquerade 470 expect="packets 1 bytes 104" 471 for dir in "in6" "out6" ; do 472 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 473 if [ $? -ne 0 ]; then 474 bad_counter "$ns1" ns0$dir "$expect" "test_masquerade6 3" 475 lret=1 476 fi 477 478 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 479 if [ $? -ne 0 ]; then 480 bad_counter "$ns2" ns1$dir "$expect" "test_masquerade6 4" 481 lret=1 482 fi 483 done 484 485 # ns1 should not have seen packets from ns2, due to masquerade 486 expect="packets 0 bytes 0" 487 for dir in "in6" "out6" ; do 488 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 489 if [ $? -ne 0 ]; then 490 bad_counter "$ns1" ns0$dir "$expect" "test_masquerade6 5" 491 lret=1 492 fi 493 494 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 495 if [ $? -ne 0 ]; then 496 bad_counter "$ns0" ns1$dir "$expect" "test_masquerade6 6" 497 lret=1 498 fi 499 done 500 501 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 502 if [ $? -ne 0 ] ; then 503 echo "ERROR: cannot ping $ns1 from $ns2 with active ipv6 masquerade $natflags (attempt 2)" 504 lret=1 505 fi 506 507 ip netns exec "$ns0" nft flush chain $family nat postrouting 508 if [ $? -ne 0 ]; then 509 echo "ERROR: Could not flush $family nat postrouting" 1>&2 510 lret=1 511 fi 512 513 test $lret -eq 0 && echo "PASS: $family IPv6 masquerade $natflags for $ns2" 514 515 return $lret 516} 517 518test_masquerade() 519{ 520 local family=$1 521 local natflags=$2 522 local lret=0 523 524 ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 525 ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 526 527 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 528 if [ $? -ne 0 ] ; then 529 echo "ERROR: cannot ping $ns1 from "$ns2" $natflags" 530 lret=1 531 fi 532 533 expect="packets 1 bytes 84" 534 for dir in "in" "out" ; do 535 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 536 if [ $? -ne 0 ]; then 537 bad_counter "$ns1" ns2$dir "$expect" "test_masquerade 1" 538 lret=1 539 fi 540 541 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 542 if [ $? -ne 0 ]; then 543 bad_counter "$ns2" ns1$dir "$expect" "test_masquerade 2" 544 lret=1 545 fi 546 done 547 548 reset_counters 549 550# add masquerading rule 551ip netns exec "$ns0" nft -f /dev/stdin <<EOF 552table $family nat { 553 chain postrouting { 554 type nat hook postrouting priority 0; policy accept; 555 meta oif veth0 masquerade $natflags 556 } 557} 558EOF 559 if [ $? -ne 0 ]; then 560 echo "SKIP: Could not add add $family masquerade hook" 561 return $ksft_skip 562 fi 563 564 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 565 if [ $? -ne 0 ] ; then 566 echo "ERROR: cannot ping $ns1 from $ns2 with active $family masquerade $natflags" 567 lret=1 568 fi 569 570 # ns1 should have seen packets from ns0, due to masquerade 571 expect="packets 1 bytes 84" 572 for dir in "in" "out" ; do 573 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect") 574 if [ $? -ne 0 ]; then 575 bad_counter "$ns1" ns0$dir "$expect" "test_masquerade 3" 576 lret=1 577 fi 578 579 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 580 if [ $? -ne 0 ]; then 581 bad_counter "$ns2" ns1$dir "$expect" "test_masquerade 4" 582 lret=1 583 fi 584 done 585 586 # ns1 should not have seen packets from ns2, due to masquerade 587 expect="packets 0 bytes 0" 588 for dir in "in" "out" ; do 589 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 590 if [ $? -ne 0 ]; then 591 bad_counter "$ns1" ns0$dir "$expect" "test_masquerade 5" 592 lret=1 593 fi 594 595 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 596 if [ $? -ne 0 ]; then 597 bad_counter "$ns0" ns1$dir "$expect" "test_masquerade 6" 598 lret=1 599 fi 600 done 601 602 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 603 if [ $? -ne 0 ] ; then 604 echo "ERROR: cannot ping $ns1 from $ns2 with active ip masquerade $natflags (attempt 2)" 605 lret=1 606 fi 607 608 ip netns exec "$ns0" nft flush chain $family nat postrouting 609 if [ $? -ne 0 ]; then 610 echo "ERROR: Could not flush $family nat postrouting" 1>&2 611 lret=1 612 fi 613 614 test $lret -eq 0 && echo "PASS: $family IP masquerade $natflags for $ns2" 615 616 return $lret 617} 618 619test_redirect6() 620{ 621 local family=$1 622 local lret=0 623 624 ip netns exec "$ns0" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null 625 626 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 627 if [ $? -ne 0 ] ; then 628 echo "ERROR: cannnot ping $ns1 from $ns2 via ipv6" 629 lret=1 630 fi 631 632 expect="packets 1 bytes 104" 633 for dir in "in6" "out6" ; do 634 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 635 if [ $? -ne 0 ]; then 636 bad_counter "$ns1" ns2$dir "$expect" "test_redirect6 1" 637 lret=1 638 fi 639 640 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 641 if [ $? -ne 0 ]; then 642 bad_counter "$ns2" ns1$dir "$expect" "test_redirect6 2" 643 lret=1 644 fi 645 done 646 647 reset_counters 648 649# add redirect rule 650ip netns exec "$ns0" nft -f /dev/stdin <<EOF 651table $family nat { 652 chain prerouting { 653 type nat hook prerouting priority 0; policy accept; 654 meta iif veth1 meta l4proto icmpv6 ip6 saddr dead:2::99 ip6 daddr dead:1::99 redirect 655 } 656} 657EOF 658 if [ $? -ne 0 ]; then 659 echo "SKIP: Could not add add $family redirect hook" 660 return $ksft_skip 661 fi 662 663 ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1 664 if [ $? -ne 0 ] ; then 665 echo "ERROR: cannot ping $ns1 from $ns2 via ipv6 with active $family redirect" 666 lret=1 667 fi 668 669 # ns1 should have seen no packets from ns2, due to redirection 670 expect="packets 0 bytes 0" 671 for dir in "in6" "out6" ; do 672 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 673 if [ $? -ne 0 ]; then 674 bad_counter "$ns1" ns0$dir "$expect" "test_redirect6 3" 675 lret=1 676 fi 677 done 678 679 # ns0 should have seen packets from ns2, due to masquerade 680 expect="packets 1 bytes 104" 681 for dir in "in6" "out6" ; do 682 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 683 if [ $? -ne 0 ]; then 684 bad_counter "$ns1" ns0$dir "$expect" "test_redirect6 4" 685 lret=1 686 fi 687 done 688 689 ip netns exec "$ns0" nft delete table $family nat 690 if [ $? -ne 0 ]; then 691 echo "ERROR: Could not delete $family nat table" 1>&2 692 lret=1 693 fi 694 695 test $lret -eq 0 && echo "PASS: $family IPv6 redirection for $ns2" 696 697 return $lret 698} 699 700test_redirect() 701{ 702 local family=$1 703 local lret=0 704 705 ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 706 ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 707 708 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 709 if [ $? -ne 0 ] ; then 710 echo "ERROR: cannot ping $ns1 from $ns2" 711 lret=1 712 fi 713 714 expect="packets 1 bytes 84" 715 for dir in "in" "out" ; do 716 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 717 if [ $? -ne 0 ]; then 718 bad_counter "$ns1" $ns2$dir "$expect" "test_redirect 1" 719 lret=1 720 fi 721 722 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 723 if [ $? -ne 0 ]; then 724 bad_counter "$ns2" ns1$dir "$expect" "test_redirect 2" 725 lret=1 726 fi 727 done 728 729 reset_counters 730 731# add redirect rule 732ip netns exec "$ns0" nft -f /dev/stdin <<EOF 733table $family nat { 734 chain prerouting { 735 type nat hook prerouting priority 0; policy accept; 736 meta iif veth1 ip protocol icmp ip saddr 10.0.2.99 ip daddr 10.0.1.99 redirect 737 } 738} 739EOF 740 if [ $? -ne 0 ]; then 741 echo "SKIP: Could not add add $family redirect hook" 742 return $ksft_skip 743 fi 744 745 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 746 if [ $? -ne 0 ] ; then 747 echo "ERROR: cannot ping $ns1 from $ns2 with active $family ip redirect" 748 lret=1 749 fi 750 751 # ns1 should have seen no packets from ns2, due to redirection 752 expect="packets 0 bytes 0" 753 for dir in "in" "out" ; do 754 755 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 756 if [ $? -ne 0 ]; then 757 bad_counter "$ns1" ns0$dir "$expect" "test_redirect 3" 758 lret=1 759 fi 760 done 761 762 # ns0 should have seen packets from ns2, due to masquerade 763 expect="packets 1 bytes 84" 764 for dir in "in" "out" ; do 765 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect") 766 if [ $? -ne 0 ]; then 767 bad_counter "$ns0" ns0$dir "$expect" "test_redirect 4" 768 lret=1 769 fi 770 done 771 772 ip netns exec "$ns0" nft delete table $family nat 773 if [ $? -ne 0 ]; then 774 echo "ERROR: Could not delete $family nat table" 1>&2 775 lret=1 776 fi 777 778 test $lret -eq 0 && echo "PASS: $family IP redirection for $ns2" 779 780 return $lret 781} 782 783# test port shadowing. 784# create two listening services, one on router (ns0), one 785# on client (ns2), which is masqueraded from ns1 point of view. 786# ns2 sends udp packet coming from service port to ns1, on a highport. 787# Later, if n1 uses same highport to connect to ns0:service, packet 788# might be port-forwarded to ns2 instead. 789 790# second argument tells if we expect the 'fake-entry' to take effect 791# (CLIENT) or not (ROUTER). 792test_port_shadow() 793{ 794 local test=$1 795 local expect=$2 796 local daddrc="10.0.1.99" 797 local daddrs="10.0.1.1" 798 local result="" 799 local logmsg="" 800 801 # make shadow entry, from client (ns2), going to (ns1), port 41404, sport 1405. 802 echo "fake-entry" | ip netns exec "$ns2" timeout 1 socat -u STDIN UDP:"$daddrc":41404,sourceport=1405 803 804 echo ROUTER | ip netns exec "$ns0" timeout 5 socat -u STDIN UDP4-LISTEN:1405 & 805 sc_r=$! 806 807 echo CLIENT | ip netns exec "$ns2" timeout 5 socat -u STDIN UDP4-LISTEN:1405,reuseport & 808 sc_c=$! 809 810 sleep 0.3 811 812 # ns1 tries to connect to ns0:1405. With default settings this should connect 813 # to client, it matches the conntrack entry created above. 814 815 result=$(echo "data" | ip netns exec "$ns1" timeout 1 socat - UDP:"$daddrs":1405,sourceport=41404) 816 817 if [ "$result" = "$expect" ] ;then 818 echo "PASS: portshadow test $test: got reply from ${expect}${logmsg}" 819 else 820 echo "ERROR: portshadow test $test: got reply from \"$result\", not $expect as intended" 821 ret=1 822 fi 823 824 kill $sc_r $sc_c 2>/dev/null 825 826 # flush udp entries for next test round, if any 827 ip netns exec "$ns0" conntrack -F >/dev/null 2>&1 828} 829 830# This prevents port shadow of router service via packet filter, 831# packets claiming to originate from service port from internal 832# network are dropped. 833test_port_shadow_filter() 834{ 835 local family=$1 836 837ip netns exec "$ns0" nft -f /dev/stdin <<EOF 838table $family filter { 839 chain forward { 840 type filter hook forward priority 0; policy accept; 841 meta iif veth1 udp sport 1405 drop 842 } 843} 844EOF 845 test_port_shadow "port-filter" "ROUTER" 846 847 ip netns exec "$ns0" nft delete table $family filter 848} 849 850# This prevents port shadow of router service via notrack. 851test_port_shadow_notrack() 852{ 853 local family=$1 854 855ip netns exec "$ns0" nft -f /dev/stdin <<EOF 856table $family raw { 857 chain prerouting { 858 type filter hook prerouting priority -300; policy accept; 859 meta iif veth0 udp dport 1405 notrack 860 } 861 chain output { 862 type filter hook output priority -300; policy accept; 863 meta oif veth0 udp sport 1405 notrack 864 } 865} 866EOF 867 test_port_shadow "port-notrack" "ROUTER" 868 869 ip netns exec "$ns0" nft delete table $family raw 870} 871 872# This prevents port shadow of router service via sport remap. 873test_port_shadow_pat() 874{ 875 local family=$1 876 877ip netns exec "$ns0" nft -f /dev/stdin <<EOF 878table $family pat { 879 chain postrouting { 880 type nat hook postrouting priority -1; policy accept; 881 meta iif veth1 udp sport <= 1405 masquerade to : 1406-65535 random 882 } 883} 884EOF 885 test_port_shadow "pat" "ROUTER" 886 887 ip netns exec "$ns0" nft delete table $family pat 888} 889 890test_port_shadowing() 891{ 892 local family="ip" 893 894 conntrack -h >/dev/null 2>&1 895 if [ $? -ne 0 ];then 896 echo "SKIP: Could not run nat port shadowing test without conntrack tool" 897 return 898 fi 899 900 socat -h > /dev/null 2>&1 901 if [ $? -ne 0 ];then 902 echo "SKIP: Could not run nat port shadowing test without socat tool" 903 return 904 fi 905 906 ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 907 ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 908 909 ip netns exec "$ns0" nft -f /dev/stdin <<EOF 910table $family nat { 911 chain postrouting { 912 type nat hook postrouting priority 0; policy accept; 913 meta oif veth0 masquerade 914 } 915} 916EOF 917 if [ $? -ne 0 ]; then 918 echo "SKIP: Could not add add $family masquerade hook" 919 return $ksft_skip 920 fi 921 922 # test default behaviour. Packet from ns1 to ns0 is redirected to ns2. 923 test_port_shadow "default" "CLIENT" 924 925 # test packet filter based mitigation: prevent forwarding of 926 # packets claiming to come from the service port. 927 test_port_shadow_filter "$family" 928 929 # test conntrack based mitigation: connections going or coming 930 # from router:service bypass connection tracking. 931 test_port_shadow_notrack "$family" 932 933 # test nat based mitigation: fowarded packets coming from service port 934 # are masqueraded with random highport. 935 test_port_shadow_pat "$family" 936 937 ip netns exec "$ns0" nft delete table $family nat 938} 939 940test_stateless_nat_ip() 941{ 942 local lret=0 943 944 ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 945 ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 946 947 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 948 if [ $? -ne 0 ] ; then 949 echo "ERROR: cannot ping $ns1 from $ns2 before loading stateless rules" 950 return 1 951 fi 952 953ip netns exec "$ns0" nft -f /dev/stdin <<EOF 954table ip stateless { 955 map xlate_in { 956 typeof meta iifname . ip saddr . ip daddr : ip daddr 957 elements = { 958 "veth1" . 10.0.2.99 . 10.0.1.99 : 10.0.2.2, 959 } 960 } 961 map xlate_out { 962 typeof meta iifname . ip saddr . ip daddr : ip daddr 963 elements = { 964 "veth0" . 10.0.1.99 . 10.0.2.2 : 10.0.2.99 965 } 966 } 967 968 chain prerouting { 969 type filter hook prerouting priority -400; policy accept; 970 ip saddr set meta iifname . ip saddr . ip daddr map @xlate_in 971 ip daddr set meta iifname . ip saddr . ip daddr map @xlate_out 972 } 973} 974EOF 975 if [ $? -ne 0 ]; then 976 echo "SKIP: Could not add ip statless rules" 977 return $ksft_skip 978 fi 979 980 reset_counters 981 982 ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1 983 if [ $? -ne 0 ] ; then 984 echo "ERROR: cannot ping $ns1 from $ns2 with stateless rules" 985 lret=1 986 fi 987 988 # ns1 should have seen packets from .2.2, due to stateless rewrite. 989 expect="packets 1 bytes 84" 990 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect") 991 if [ $? -ne 0 ]; then 992 bad_counter "$ns1" ns0insl "$expect" "test_stateless 1" 993 lret=1 994 fi 995 996 for dir in "in" "out" ; do 997 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect") 998 if [ $? -ne 0 ]; then 999 bad_counter "$ns2" ns1$dir "$expect" "test_stateless 2" 1000 lret=1 1001 fi 1002 done 1003 1004 # ns1 should not have seen packets from ns2, due to masquerade 1005 expect="packets 0 bytes 0" 1006 for dir in "in" "out" ; do 1007 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect") 1008 if [ $? -ne 0 ]; then 1009 bad_counter "$ns1" ns0$dir "$expect" "test_stateless 3" 1010 lret=1 1011 fi 1012 1013 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect") 1014 if [ $? -ne 0 ]; then 1015 bad_counter "$ns0" ns1$dir "$expect" "test_stateless 4" 1016 lret=1 1017 fi 1018 done 1019 1020 reset_counters 1021 1022 socat -h > /dev/null 2>&1 1023 if [ $? -ne 0 ];then 1024 echo "SKIP: Could not run stateless nat frag test without socat tool" 1025 if [ $lret -eq 0 ]; then 1026 return $ksft_skip 1027 fi 1028 1029 ip netns exec "$ns0" nft delete table ip stateless 1030 return $lret 1031 fi 1032 1033 local tmpfile=$(mktemp) 1034 dd if=/dev/urandom of=$tmpfile bs=4096 count=1 2>/dev/null 1035 1036 local outfile=$(mktemp) 1037 ip netns exec "$ns1" timeout 3 socat -u UDP4-RECV:4233 OPEN:$outfile < /dev/null & 1038 sc_r=$! 1039 1040 sleep 1 1041 # re-do with large ping -> ip fragmentation 1042 ip netns exec "$ns2" timeout 3 socat - UDP4-SENDTO:"10.0.1.99:4233" < "$tmpfile" > /dev/null 1043 if [ $? -ne 0 ] ; then 1044 echo "ERROR: failed to test udp $ns1 to $ns2 with stateless ip nat" 1>&2 1045 lret=1 1046 fi 1047 1048 wait 1049 1050 cmp "$tmpfile" "$outfile" 1051 if [ $? -ne 0 ]; then 1052 ls -l "$tmpfile" "$outfile" 1053 echo "ERROR: in and output file mismatch when checking udp with stateless nat" 1>&2 1054 lret=1 1055 fi 1056 1057 rm -f "$tmpfile" "$outfile" 1058 1059 # ns1 should have seen packets from 2.2, due to stateless rewrite. 1060 expect="packets 3 bytes 4164" 1061 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect") 1062 if [ $? -ne 0 ]; then 1063 bad_counter "$ns1" ns0insl "$expect" "test_stateless 5" 1064 lret=1 1065 fi 1066 1067 ip netns exec "$ns0" nft delete table ip stateless 1068 if [ $? -ne 0 ]; then 1069 echo "ERROR: Could not delete table ip stateless" 1>&2 1070 lret=1 1071 fi 1072 1073 test $lret -eq 0 && echo "PASS: IP statless for $ns2" 1074 1075 return $lret 1076} 1077 1078# ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99 1079for i in 0 1 2; do 1080ip netns exec ns$i-$sfx nft -f /dev/stdin <<EOF 1081table inet filter { 1082 counter ns0in {} 1083 counter ns1in {} 1084 counter ns2in {} 1085 1086 counter ns0out {} 1087 counter ns1out {} 1088 counter ns2out {} 1089 1090 counter ns0in6 {} 1091 counter ns1in6 {} 1092 counter ns2in6 {} 1093 1094 counter ns0out6 {} 1095 counter ns1out6 {} 1096 counter ns2out6 {} 1097 1098 map nsincounter { 1099 type ipv4_addr : counter 1100 elements = { 10.0.1.1 : "ns0in", 1101 10.0.2.1 : "ns0in", 1102 10.0.1.99 : "ns1in", 1103 10.0.2.99 : "ns2in" } 1104 } 1105 1106 map nsincounter6 { 1107 type ipv6_addr : counter 1108 elements = { dead:1::1 : "ns0in6", 1109 dead:2::1 : "ns0in6", 1110 dead:1::99 : "ns1in6", 1111 dead:2::99 : "ns2in6" } 1112 } 1113 1114 map nsoutcounter { 1115 type ipv4_addr : counter 1116 elements = { 10.0.1.1 : "ns0out", 1117 10.0.2.1 : "ns0out", 1118 10.0.1.99: "ns1out", 1119 10.0.2.99: "ns2out" } 1120 } 1121 1122 map nsoutcounter6 { 1123 type ipv6_addr : counter 1124 elements = { dead:1::1 : "ns0out6", 1125 dead:2::1 : "ns0out6", 1126 dead:1::99 : "ns1out6", 1127 dead:2::99 : "ns2out6" } 1128 } 1129 1130 chain input { 1131 type filter hook input priority 0; policy accept; 1132 counter name ip saddr map @nsincounter 1133 icmpv6 type { "echo-request", "echo-reply" } counter name ip6 saddr map @nsincounter6 1134 } 1135 chain output { 1136 type filter hook output priority 0; policy accept; 1137 counter name ip daddr map @nsoutcounter 1138 icmpv6 type { "echo-request", "echo-reply" } counter name ip6 daddr map @nsoutcounter6 1139 } 1140} 1141EOF 1142done 1143 1144# special case for stateless nat check, counter needs to 1145# be done before (input) ip defragmentation 1146ip netns exec ns1-$sfx nft -f /dev/stdin <<EOF 1147table inet filter { 1148 counter ns0insl {} 1149 1150 chain pre { 1151 type filter hook prerouting priority -400; policy accept; 1152 ip saddr 10.0.2.2 counter name "ns0insl" 1153 } 1154} 1155EOF 1156 1157sleep 3 1158# test basic connectivity 1159for i in 1 2; do 1160 ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99 > /dev/null 1161 if [ $? -ne 0 ];then 1162 echo "ERROR: Could not reach other namespace(s)" 1>&2 1163 ret=1 1164 fi 1165 1166 ip netns exec "$ns0" ping -c 1 -q dead:$i::99 > /dev/null 1167 if [ $? -ne 0 ];then 1168 echo "ERROR: Could not reach other namespace(s) via ipv6" 1>&2 1169 ret=1 1170 fi 1171 check_counters ns$i-$sfx 1172 if [ $? -ne 0 ]; then 1173 ret=1 1174 fi 1175 1176 check_ns0_counters ns$i 1177 if [ $? -ne 0 ]; then 1178 ret=1 1179 fi 1180 reset_counters 1181done 1182 1183if [ $ret -eq 0 ];then 1184 echo "PASS: netns routing/connectivity: $ns0 can reach $ns1 and $ns2" 1185fi 1186 1187reset_counters 1188test_local_dnat ip 1189test_local_dnat6 ip6 1190 1191reset_counters 1192test_local_dnat_portonly inet 10.0.1.99 1193 1194reset_counters 1195$test_inet_nat && test_local_dnat inet 1196$test_inet_nat && test_local_dnat6 inet 1197 1198for flags in "" "fully-random"; do 1199reset_counters 1200test_masquerade ip $flags 1201test_masquerade6 ip6 $flags 1202reset_counters 1203$test_inet_nat && test_masquerade inet $flags 1204$test_inet_nat && test_masquerade6 inet $flags 1205done 1206 1207reset_counters 1208test_redirect ip 1209test_redirect6 ip6 1210reset_counters 1211$test_inet_nat && test_redirect inet 1212$test_inet_nat && test_redirect6 inet 1213 1214test_port_shadowing 1215test_stateless_nat_ip 1216 1217if [ $ret -ne 0 ];then 1218 echo -n "FAIL: " 1219 nft --version 1220fi 1221 1222exit $ret 1223