diff options
author | Sam Balana <sbalana@google.com> | 2021-05-26 14:14:07 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-05-26 14:16:40 -0700 |
commit | 522ae2dd1f3c0d5aea52a9883cc1319e3b1ebce4 (patch) | |
tree | d0f6681e6e6d2fd500e04360c225c6d2af198d04 /test/packetimpact/tests | |
parent | b6f9158424c9f5b8a141e468e22fd12bc4dfc447 (diff) |
Specify subsequent layers as ICMP payloads and add ICMPv6.Pointer
Moves specification of subsequent layers to the Payload field of the ICMP and
ICMPv6 layers.
Removes the need to manually encode type-specific ICMP or ICMPv6 headers, such
as the "pointer" header of parameter problem messages, in the payload. This is
necessary prework to enable matching of more type-specific headers, such as
"ident" of echo requests.
Fixes a bug where the "reserved" header defined by ICMPv6 RFC 4443 was being
incorrectly encoded by ToBytes. This change fixes the implementation by copying
the payload into Payload, instead of the MessageBody.
PiperOrigin-RevId: 376026420
Diffstat (limited to 'test/packetimpact/tests')
5 files changed, 60 insertions, 72 deletions
diff --git a/test/packetimpact/tests/icmpv6_param_problem_test.go b/test/packetimpact/tests/icmpv6_param_problem_test.go index 1beccb6cf..fdabcf1ad 100644 --- a/test/packetimpact/tests/icmpv6_param_problem_test.go +++ b/test/packetimpact/tests/icmpv6_param_problem_test.go @@ -15,7 +15,6 @@ package icmpv6_param_problem_test import ( - "encoding/binary" "flag" "testing" "time" @@ -56,13 +55,11 @@ func TestICMPv6ParamProblemTest(t *testing.T) { 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 := testbench.ICMPv6{ Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem), Payload: expectedPayload, + // The problematic field is the NextHeader. + Pointer: testbench.Uint32(header.IPv6NextHeaderOffset), } paramProblem := testbench.Layers{ diff --git a/test/packetimpact/tests/ipv6_unknown_options_action_test.go b/test/packetimpact/tests/ipv6_unknown_options_action_test.go index f999d13d2..d762c43a7 100644 --- a/test/packetimpact/tests/ipv6_unknown_options_action_test.go +++ b/test/packetimpact/tests/ipv6_unknown_options_action_test.go @@ -15,7 +15,6 @@ package ipv6_unknown_options_action_test import ( - "encoding/binary" "flag" "net" "testing" @@ -154,23 +153,22 @@ func TestIPv6UnknownOptionAction(t *testing.T) { outgoing := conn.CreateFrame(t, outgoingOverride, tt.mkExtHdr(optionTypeFromAction(tt.action))) conn.SendFrame(t, outgoing) ipv6Sent := outgoing[1:] - invokingPacket, err := ipv6Sent.ToBytes() + icmpv6Payload, err := ipv6Sent.ToBytes() if err != nil { t.Fatalf("failed to serialize the outgoing packet: %s", err) } - icmpv6Payload := make([]byte, 4) - // The pointer in the ICMPv6 parameter problem message should point to - // the option type of the unknown option. In our test case, it is the - // first option in the extension header whose option type is 2 bytes - // after the IPv6 header (after NextHeader and ExtHdrLen). - binary.BigEndian.PutUint32(icmpv6Payload, header.IPv6MinimumSize+2) - icmpv6Payload = append(icmpv6Payload, invokingPacket...) gotICMPv6, err := conn.ExpectFrame(t, testbench.Layers{ &testbench.Ether{}, &testbench.IPv6{}, &testbench.ICMPv6{ - Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem), - Code: testbench.ICMPv6Code(header.ICMPv6UnknownOption), + Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem), + Code: testbench.ICMPv6Code(header.ICMPv6UnknownOption), + // The pointer in the ICMPv6 parameter problem message + // should point to the option type of the unknown option. In + // our test case, it is the first option in the extension + // header whose option type is 2 bytes after the IPv6 header + // (after NextHeader and ExtHdrLen). + Pointer: testbench.Uint32(header.IPv6MinimumSize + 2), Payload: icmpv6Payload, }, }, time.Second) diff --git a/test/packetimpact/tests/tcp_connect_icmp_error_test.go b/test/packetimpact/tests/tcp_connect_icmp_error_test.go index 79bfe9eb7..3b4c4cd63 100644 --- a/test/packetimpact/tests/tcp_connect_icmp_error_test.go +++ b/test/packetimpact/tests/tcp_connect_icmp_error_test.go @@ -33,17 +33,18 @@ func init() { func sendICMPError(t *testing.T, conn *testbench.TCPIPv4, tcp *testbench.TCP) { t.Helper() - layers := conn.CreateFrame(t, nil) - layers = layers[:len(layers)-1] - ip, ok := tcp.Prev().(*testbench.IPv4) - if !ok { - t.Fatalf("expected %s to be IPv4", tcp.Prev()) + icmpPayload := testbench.Layers{tcp.Prev(), tcp} + bytes, err := icmpPayload.ToBytes() + if err != nil { + t.Fatalf("got icmpPayload.ToBytes() = (_, %s), want = (_, nil)", err) } - icmpErr := &testbench.ICMPv4{ - Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), - Code: testbench.ICMPv4Code(header.ICMPv4HostUnreachable)} - layers = append(layers, icmpErr, ip, tcp) + layers := conn.CreateFrame(t, nil) + layers[len(layers)-1] = &testbench.ICMPv4{ + Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), + Code: testbench.ICMPv4Code(header.ICMPv4HostUnreachable), + Payload: bytes, + } conn.SendFrameStateless(t, layers) } diff --git a/test/packetimpact/tests/tcp_network_unreachable_test.go b/test/packetimpact/tests/tcp_network_unreachable_test.go index 5168450ad..60a2dbf3d 100644 --- a/test/packetimpact/tests/tcp_network_unreachable_test.go +++ b/test/packetimpact/tests/tcp_network_unreachable_test.go @@ -50,30 +50,24 @@ func TestTCPSynSentUnreachable(t *testing.T) { } // Get the SYN. - tcpLayers, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, nil, time.Second) + tcp, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, time.Second) if err != nil { t.Fatalf("expected SYN: %s", err) } // Send a host unreachable message. - layers := conn.CreateFrame(t, nil) - layers = layers[:len(layers)-1] - const ipLayer = 1 - const tcpLayer = ipLayer + 1 - ip, ok := tcpLayers[ipLayer].(*testbench.IPv4) - if !ok { - t.Fatalf("expected %s to be IPv4", tcpLayers[ipLayer]) - } - tcp, ok := tcpLayers[tcpLayer].(*testbench.TCP) - if !ok { - t.Fatalf("expected %s to be TCP", tcpLayers[tcpLayer]) - } - var icmpv4 testbench.ICMPv4 = testbench.ICMPv4{ - Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), - Code: testbench.ICMPv4Code(header.ICMPv4HostUnreachable), + icmpPayload := testbench.Layers{tcp.Prev(), tcp} + bytes, err := icmpPayload.ToBytes() + if err != nil { + t.Fatalf("got icmpPayload.ToBytes() = (_, %s), want = (_, nil)", err) } - layers = append(layers, &icmpv4, ip, tcp) + layers := conn.CreateFrame(t, nil) + layers[len(layers)-1] = &testbench.ICMPv4{ + Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), + Code: testbench.ICMPv4Code(header.ICMPv4HostUnreachable), + Payload: bytes, + } conn.SendFrameStateless(t, layers) if err := getConnectError(t, &dut, clientFD); err != unix.EHOSTUNREACH { @@ -104,31 +98,24 @@ func TestTCPSynSentUnreachable6(t *testing.T) { } // Get the SYN. - tcpLayers, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, nil, time.Second) + tcp, err := conn.Expect(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, time.Second) if err != nil { t.Fatalf("expected SYN: %s", err) } // Send a host unreachable message. - layers := conn.CreateFrame(t, nil) - layers = layers[:len(layers)-1] - const ipLayer = 1 - const tcpLayer = ipLayer + 1 - ip, ok := tcpLayers[ipLayer].(*testbench.IPv6) - if !ok { - t.Fatalf("expected %s to be IPv6", tcpLayers[ipLayer]) - } - tcp, ok := tcpLayers[tcpLayer].(*testbench.TCP) - if !ok { - t.Fatalf("expected %s to be TCP", tcpLayers[tcpLayer]) + icmpPayload := testbench.Layers{tcp.Prev(), tcp} + bytes, err := icmpPayload.ToBytes() + if err != nil { + t.Fatalf("got icmpPayload.ToBytes() = (_, %s), want = (_, nil)", err) } - var icmpv6 testbench.ICMPv6 = testbench.ICMPv6{ - Type: testbench.ICMPv6Type(header.ICMPv6DstUnreachable), - Code: testbench.ICMPv6Code(header.ICMPv6NetworkUnreachable), - // Per RFC 4443 3.1, the payload contains 4 zeroed bytes. - Payload: []byte{0, 0, 0, 0}, + + layers := conn.CreateFrame(t, nil) + layers[len(layers)-1] = &testbench.ICMPv6{ + Type: testbench.ICMPv6Type(header.ICMPv6DstUnreachable), + Code: testbench.ICMPv6Code(header.ICMPv6NetworkUnreachable), + Payload: bytes, } - layers = append(layers, &icmpv6, ip, tcp) conn.SendFrameStateless(t, layers) if err := getConnectError(t, &dut, clientFD); err != unix.ENETUNREACH { diff --git a/test/packetimpact/tests/udp_icmp_error_propagation_test.go b/test/packetimpact/tests/udp_icmp_error_propagation_test.go index 3159d5b89..087aeb66e 100644 --- a/test/packetimpact/tests/udp_icmp_error_propagation_test.go +++ b/test/packetimpact/tests/udp_icmp_error_propagation_test.go @@ -58,16 +58,20 @@ func (e icmpError) String() string { return "Unknown ICMP error" } -func (e icmpError) ToICMPv4() *testbench.ICMPv4 { +func (e icmpError) ToICMPv4(payload []byte) *testbench.ICMPv4 { switch e { case portUnreachable: return &testbench.ICMPv4{ - Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), - Code: testbench.ICMPv4Code(header.ICMPv4PortUnreachable)} + Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), + Code: testbench.ICMPv4Code(header.ICMPv4PortUnreachable), + Payload: payload, + } case timeToLiveExceeded: return &testbench.ICMPv4{ - Type: testbench.ICMPv4Type(header.ICMPv4TimeExceeded), - Code: testbench.ICMPv4Code(header.ICMPv4TTLExceeded)} + Type: testbench.ICMPv4Type(header.ICMPv4TimeExceeded), + Code: testbench.ICMPv4Code(header.ICMPv4TTLExceeded), + Payload: payload, + } } return nil } @@ -101,8 +105,6 @@ func wantErrno(c connectionMode, icmpErr icmpError) unix.Errno { func sendICMPError(t *testing.T, conn *testbench.UDPIPv4, icmpErr icmpError, udp *testbench.UDP) { t.Helper() - layers := conn.CreateFrame(t, nil) - layers = layers[:len(layers)-1] ip, ok := udp.Prev().(*testbench.IPv4) if !ok { t.Fatalf("expected %s to be IPv4", udp.Prev()) @@ -113,12 +115,15 @@ func sendICMPError(t *testing.T, conn *testbench.UDPIPv4, icmpErr icmpError, udp // to 1. ip.Checksum = nil } - // Note that the ICMP payload is valid in this case because the UDP - // payload is empty. If the UDP payload were not empty, the packet - // length during serialization may not be calculated correctly, - // resulting in a mal-formed packet. - layers = append(layers, icmpErr.ToICMPv4(), ip, udp) + icmpPayload := testbench.Layers{ip, udp} + bytes, err := icmpPayload.ToBytes() + if err != nil { + t.Fatalf("got icmpPayload.ToBytes() = (_, %s), want = (_, nil)", err) + } + + layers := conn.CreateFrame(t, nil) + layers[len(layers)-1] = icmpErr.ToICMPv4(bytes) conn.SendFrameStateless(t, layers) } |