gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/packetimpact/tests/ipv6_unknown_options_action_test.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ipv6_unknown_options_action_test
    16  
    17  import (
    18  	"flag"
    19  	"net"
    20  	"testing"
    21  	"time"
    22  
    23  	"gvisor.dev/gvisor/pkg/tcpip/header"
    24  	"gvisor.dev/gvisor/test/packetimpact/testbench"
    25  )
    26  
    27  func init() {
    28  	testbench.Initialize(flag.CommandLine)
    29  }
    30  
    31  func mkHopByHopOptionsExtHdr(optType byte) testbench.Layer {
    32  	return &testbench.IPv6HopByHopOptionsExtHdr{
    33  		Options: []byte{optType, 0x04, 0x00, 0x00, 0x00, 0x00},
    34  	}
    35  }
    36  
    37  func mkDestinationOptionsExtHdr(optType byte) testbench.Layer {
    38  	return &testbench.IPv6DestinationOptionsExtHdr{
    39  		Options: []byte{optType, 0x04, 0x00, 0x00, 0x00, 0x00},
    40  	}
    41  }
    42  
    43  func optionTypeFromAction(action header.IPv6OptionUnknownAction) byte {
    44  	return byte(action << 6)
    45  }
    46  
    47  func TestIPv6UnknownOptionAction(t *testing.T) {
    48  	for _, tt := range []struct {
    49  		description  string
    50  		mkExtHdr     func(optType byte) testbench.Layer
    51  		action       header.IPv6OptionUnknownAction
    52  		multicastDst bool
    53  		wantICMPv6   bool
    54  	}{
    55  		{
    56  			description:  "0b00/hbh",
    57  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    58  			action:       header.IPv6OptionUnknownActionSkip,
    59  			multicastDst: false,
    60  			wantICMPv6:   false,
    61  		},
    62  		{
    63  			description:  "0b01/hbh",
    64  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    65  			action:       header.IPv6OptionUnknownActionDiscard,
    66  			multicastDst: false,
    67  			wantICMPv6:   false,
    68  		},
    69  		{
    70  			description:  "0b10/hbh/unicast",
    71  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    72  			action:       header.IPv6OptionUnknownActionDiscardSendICMP,
    73  			multicastDst: false,
    74  			wantICMPv6:   true,
    75  		},
    76  		{
    77  			description:  "0b10/hbh/multicast",
    78  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    79  			action:       header.IPv6OptionUnknownActionDiscardSendICMP,
    80  			multicastDst: true,
    81  			wantICMPv6:   true,
    82  		},
    83  		{
    84  			description:  "0b11/hbh/unicast",
    85  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    86  			action:       header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
    87  			multicastDst: false,
    88  			wantICMPv6:   true,
    89  		},
    90  		{
    91  			description:  "0b11/hbh/multicast",
    92  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    93  			action:       header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
    94  			multicastDst: true,
    95  			wantICMPv6:   false,
    96  		},
    97  		{
    98  			description:  "0b00/destination",
    99  			mkExtHdr:     mkDestinationOptionsExtHdr,
   100  			action:       header.IPv6OptionUnknownActionSkip,
   101  			multicastDst: false,
   102  			wantICMPv6:   false,
   103  		},
   104  		{
   105  			description:  "0b01/destination",
   106  			mkExtHdr:     mkDestinationOptionsExtHdr,
   107  			action:       header.IPv6OptionUnknownActionDiscard,
   108  			multicastDst: false,
   109  			wantICMPv6:   false,
   110  		},
   111  		{
   112  			description:  "0b10/destination/unicast",
   113  			mkExtHdr:     mkDestinationOptionsExtHdr,
   114  			action:       header.IPv6OptionUnknownActionDiscardSendICMP,
   115  			multicastDst: false,
   116  			wantICMPv6:   true,
   117  		},
   118  		{
   119  			description:  "0b10/destination/multicast",
   120  			mkExtHdr:     mkDestinationOptionsExtHdr,
   121  			action:       header.IPv6OptionUnknownActionDiscardSendICMP,
   122  			multicastDst: true,
   123  			wantICMPv6:   true,
   124  		},
   125  		{
   126  			description:  "0b11/destination/unicast",
   127  			mkExtHdr:     mkDestinationOptionsExtHdr,
   128  			action:       header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
   129  			multicastDst: false,
   130  			wantICMPv6:   true,
   131  		},
   132  		{
   133  			description:  "0b11/destination/multicast",
   134  			mkExtHdr:     mkDestinationOptionsExtHdr,
   135  			action:       header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
   136  			multicastDst: true,
   137  			wantICMPv6:   false,
   138  		},
   139  	} {
   140  		t.Run(tt.description, func(t *testing.T) {
   141  			dut := testbench.NewDUT(t)
   142  			conn := dut.Net.NewIPv6Conn(t, testbench.IPv6{}, testbench.IPv6{})
   143  			defer conn.Close(t)
   144  
   145  			outgoingOverride := testbench.Layers{}
   146  			if tt.multicastDst {
   147  				ip := net.ParseIP("ff02::1")
   148  				outgoingOverride = testbench.Layers{&testbench.IPv6{
   149  					DstAddr: &ip,
   150  				}}
   151  			}
   152  
   153  			outgoing := conn.CreateFrame(t, outgoingOverride, tt.mkExtHdr(optionTypeFromAction(tt.action)))
   154  			conn.SendFrame(t, outgoing)
   155  			ipv6Sent := outgoing[1:]
   156  			icmpv6Payload, err := ipv6Sent.ToBytes()
   157  			if err != nil {
   158  				t.Fatalf("failed to serialize the outgoing packet: %s", err)
   159  			}
   160  			gotICMPv6, err := conn.ExpectFrame(t, testbench.Layers{
   161  				&testbench.Ether{},
   162  				&testbench.IPv6{},
   163  				&testbench.ICMPv6{
   164  					Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem),
   165  					Code: testbench.ICMPv6Code(header.ICMPv6UnknownOption),
   166  					// The pointer in the ICMPv6 parameter problem message
   167  					// should point to the option type of the unknown option. In
   168  					// our test case, it is the first option in the extension
   169  					// header whose option type is 2 bytes after the IPv6 header
   170  					// (after NextHeader and ExtHdrLen).
   171  					Pointer: testbench.Uint32(header.IPv6MinimumSize + 2),
   172  					Payload: icmpv6Payload,
   173  				},
   174  			}, time.Second)
   175  			if tt.wantICMPv6 && err != nil {
   176  				t.Fatalf("expected ICMPv6 Parameter Problem but got none: %s", err)
   177  			}
   178  			if !tt.wantICMPv6 && gotICMPv6 != nil {
   179  				t.Fatalf("expected no ICMPv6 Parameter Problem but got one: %s", gotICMPv6)
   180  			}
   181  		})
   182  	}
   183  }