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