diff options
author | Eyal Soha <eyalsoha@google.com> | 2020-04-24 15:55:11 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-04-24 15:56:27 -0700 |
commit | dfff265fe422499af3bbe7d58e8db35ba32304f5 (patch) | |
tree | 4ea81063b2f322166d1d6919d33c8a75e99e0f2a /test/packetimpact/tests | |
parent | 3d860530a904004aea5bc95e6331b3b11cec1877 (diff) |
Add ICMP6 param problem test
Tested:
When run on Linux, a correct ICMPv6 response is received. On netstack, no
ICMPv6 response is received.
PiperOrigin-RevId: 308343113
Diffstat (limited to 'test/packetimpact/tests')
-rw-r--r-- | test/packetimpact/tests/BUILD | 13 | ||||
-rw-r--r-- | test/packetimpact/tests/icmpv6_param_problem_test.go | 73 | ||||
-rwxr-xr-x | test/packetimpact/tests/test_runner.sh | 41 |
3 files changed, 125 insertions, 2 deletions
diff --git a/test/packetimpact/tests/BUILD b/test/packetimpact/tests/BUILD index 47c722ccd..42f87e3f3 100644 --- a/test/packetimpact/tests/BUILD +++ b/test/packetimpact/tests/BUILD @@ -96,6 +96,19 @@ packetimpact_go_test( ], ) +packetimpact_go_test( + name = "icmpv6_param_problem", + srcs = ["icmpv6_param_problem_test.go"], + # TODO(b/153485026): Fix netstack then remove the line below. + netstack = False, + deps = [ + "//pkg/tcpip", + "//pkg/tcpip/header", + "//test/packetimpact/testbench", + "@org_golang_x_sys//unix:go_default_library", + ], +) + sh_binary( name = "test_runner", srcs = ["test_runner.sh"], diff --git a/test/packetimpact/tests/icmpv6_param_problem_test.go b/test/packetimpact/tests/icmpv6_param_problem_test.go new file mode 100644 index 000000000..b48e55df4 --- /dev/null +++ b/test/packetimpact/tests/icmpv6_param_problem_test.go @@ -0,0 +1,73 @@ +// Copyright 2020 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package icmpv6_param_problem_test + +import ( + "encoding/binary" + "testing" + "time" + + "gvisor.dev/gvisor/pkg/tcpip/header" + tb "gvisor.dev/gvisor/test/packetimpact/testbench" +) + +// TestICMPv6ParamProblemTest sends a packet with a bad next header. The DUT +// should respond with an ICMPv6 Parameter Problem message. +func TestICMPv6ParamProblemTest(t *testing.T) { + dut := tb.NewDUT(t) + defer dut.TearDown() + conn := tb.NewIPv6Conn(t, tb.IPv6{}, tb.IPv6{}) + defer conn.Close() + ipv6 := tb.IPv6{ + // 254 is reserved and used for experimentation and testing. This should + // cause an error. + NextHeader: tb.Uint8(254), + } + icmpv6 := tb.ICMPv6{ + Type: tb.ICMPv6Type(header.ICMPv6EchoRequest), + NDPPayload: []byte("hello world"), + } + + toSend := conn.CreateFrame(ipv6, &icmpv6) + conn.SendFrame(toSend) + + // Build the expected ICMPv6 payload, which includes an index to the + // problematic byte and also the problematic packet as described in + // https://tools.ietf.org/html/rfc4443#page-12 . + ipv6Sent := toSend[1:] + expectedPayload, err := ipv6Sent.ToBytes() + if err != nil { + t.Fatalf("can't convert %s to bytes: %s", ipv6Sent, err) + } + + // The problematic field is the NextHeader. + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, header.IPv6NextHeaderOffset) + expectedPayload = append(b, expectedPayload...) + expectedICMPv6 := tb.ICMPv6{ + Type: tb.ICMPv6Type(header.ICMPv6ParamProblem), + NDPPayload: expectedPayload, + } + + paramProblem := tb.Layers{ + &tb.Ether{}, + &tb.IPv6{}, + &expectedICMPv6, + } + timeout := time.Second + if _, err := conn.ExpectFrame(paramProblem, timeout); err != nil { + t.Errorf("expected %s within %s but got none: %s", paramProblem, timeout, err) + } +} diff --git a/test/packetimpact/tests/test_runner.sh b/test/packetimpact/tests/test_runner.sh index e938de782..706441cce 100755 --- a/test/packetimpact/tests/test_runner.sh +++ b/test/packetimpact/tests/test_runner.sh @@ -192,6 +192,8 @@ docker pull "${IMAGE_TAG}" # Create the DUT container and connect to network. DUT=$(docker create ${RUNTIME_ARG} --privileged --rm \ + --cap-add NET_ADMIN \ + --sysctl net.ipv6.conf.all.disable_ipv6=0 \ --stop-timeout ${TIMEOUT} -it ${IMAGE_TAG}) docker network connect "${CTRL_NET}" \ --ip "${CTRL_NET_PREFIX}${DUT_NET_SUFFIX}" "${DUT}" \ @@ -203,6 +205,8 @@ docker start "${DUT}" # Create the test bench container and connect to network. TESTBENCH=$(docker create --privileged --rm \ + --cap-add NET_ADMIN \ + --sysctl net.ipv6.conf.all.disable_ipv6=0 \ --stop-timeout ${TIMEOUT} -it ${IMAGE_TAG}) docker network connect "${CTRL_NET}" \ --ip "${CTRL_NET_PREFIX}${TESTBENCH_NET_SUFFIX}" "${TESTBENCH}" \ @@ -237,6 +241,32 @@ declare -r REMOTE_MAC=$(docker exec -t "${DUT}" ip link show \ "${TEST_DEVICE}" | tail -1 | cut -d' ' -f6) declare -r LOCAL_MAC=$(docker exec -t "${TESTBENCH}" ip link show \ "${TEST_DEVICE}" | tail -1 | cut -d' ' -f6) +declare REMOTE_IPV6=$(docker exec -t "${DUT}" ip addr show scope link \ + "${TEST_DEVICE}" | grep inet6 | cut -d' ' -f6 | cut -d'/' -f1) +declare -r LOCAL_IPV6=$(docker exec -t "${TESTBENCH}" ip addr show scope link \ + "${TEST_DEVICE}" | grep inet6 | cut -d' ' -f6 | cut -d'/' -f1) + +# Netstack as DUT doesn't assign IPv6 addresses automatically so do it if +# needed. Convert the MAC address to an IPv6 link local address as described in +# RFC 4291 page 20: https://tools.ietf.org/html/rfc4291#page-20 +if [[ -z "${REMOTE_IPV6}" ]]; then + # Split the octets of the MAC into an array of strings. + IFS=":" read -a REMOTE_OCTETS <<< "${REMOTE_MAC}" + # Flip the global bit. + REMOTE_OCTETS[0]=$(printf '%x' "$((0x${REMOTE_OCTETS[0]} ^ 2))") + # Add the IPv6 address. + docker exec "${DUT}" \ + ip addr add $(printf 'fe80::%02x%02x:%02xff:fe%02x:%02x%02x/64' \ + "0x${REMOTE_OCTETS[0]}" "0x${REMOTE_OCTETS[1]}" "0x${REMOTE_OCTETS[2]}" \ + "0x${REMOTE_OCTETS[3]}" "0x${REMOTE_OCTETS[4]}" "0x${REMOTE_OCTETS[5]}") \ + scope link \ + dev "${TEST_DEVICE}" + # Re-extract the IPv6 address. + # TODO(eyalsoha): Add "scope link" below when netstack supports correctly + # creating link-local IPv6 addresses. + REMOTE_IPV6=$(docker exec -t "${DUT}" ip addr show \ + "${TEST_DEVICE}" | grep inet6 | cut -d' ' -f6 | cut -d'/' -f1) +fi declare -r DOCKER_TESTBENCH_BINARY="/$(basename ${TESTBENCH_BINARY})" docker cp -L "${TESTBENCH_BINARY}" "${TESTBENCH}:${DOCKER_TESTBENCH_BINARY}" @@ -245,7 +275,10 @@ if [[ -z "${TSHARK-}" ]]; then # Run tcpdump in the test bench unbuffered, without dns resolution, just on # the interface with the test packets. docker exec -t "${TESTBENCH}" \ - tcpdump -S -vvv -U -n -i "${TEST_DEVICE}" net "${TEST_NET_PREFIX}/24" & + tcpdump -S -vvv -U -n -i "${TEST_DEVICE}" \ + net "${TEST_NET_PREFIX}/24" or \ + host "${REMOTE_IPV6}" or \ + host "${LOCAL_IPV6}" & else # Run tshark in the test bench unbuffered, without dns resolution, just on the # interface with the test packets. @@ -253,7 +286,9 @@ else tshark -V -l -n -i "${TEST_DEVICE}" \ -o tcp.check_checksum:TRUE \ -o udp.check_checksum:TRUE \ - host "${TEST_NET_PREFIX}${TESTBENCH_NET_SUFFIX}" & + net "${TEST_NET_PREFIX}/24" or \ + host "${REMOTE_IPV6}" or \ + host "${LOCAL_IPV6}" & fi # tcpdump and tshark take time to startup @@ -272,6 +307,8 @@ docker exec \ --posix_server_port=${CTRL_PORT} \ --remote_ipv4=${TEST_NET_PREFIX}${DUT_NET_SUFFIX} \ --local_ipv4=${TEST_NET_PREFIX}${TESTBENCH_NET_SUFFIX} \ + --remote_ipv6=${REMOTE_IPV6} \ + --local_ipv6=${LOCAL_IPV6} \ --remote_mac=${REMOTE_MAC} \ --local_mac=${LOCAL_MAC} \ --device=${TEST_DEVICE}" && true |