github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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  	"github.com/SagerNet/gvisor/pkg/tcpip"
    24  	"github.com/SagerNet/gvisor/pkg/tcpip/header"
    25  	"github.com/SagerNet/gvisor/test/packetimpact/testbench"
    26  )
    27  
    28  func init() {
    29  	testbench.Initialize(flag.CommandLine)
    30  }
    31  
    32  func mkHopByHopOptionsExtHdr(optType byte) testbench.Layer {
    33  	return &testbench.IPv6HopByHopOptionsExtHdr{
    34  		Options: []byte{optType, 0x04, 0x00, 0x00, 0x00, 0x00},
    35  	}
    36  }
    37  
    38  func mkDestinationOptionsExtHdr(optType byte) testbench.Layer {
    39  	return &testbench.IPv6DestinationOptionsExtHdr{
    40  		Options: []byte{optType, 0x04, 0x00, 0x00, 0x00, 0x00},
    41  	}
    42  }
    43  
    44  func optionTypeFromAction(action header.IPv6OptionUnknownAction) byte {
    45  	return byte(action << 6)
    46  }
    47  
    48  func TestIPv6UnknownOptionAction(t *testing.T) {
    49  	for _, tt := range []struct {
    50  		description  string
    51  		mkExtHdr     func(optType byte) testbench.Layer
    52  		action       header.IPv6OptionUnknownAction
    53  		multicastDst bool
    54  		wantICMPv6   bool
    55  	}{
    56  		{
    57  			description:  "0b00/hbh",
    58  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    59  			action:       header.IPv6OptionUnknownActionSkip,
    60  			multicastDst: false,
    61  			wantICMPv6:   false,
    62  		},
    63  		{
    64  			description:  "0b01/hbh",
    65  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    66  			action:       header.IPv6OptionUnknownActionDiscard,
    67  			multicastDst: false,
    68  			wantICMPv6:   false,
    69  		},
    70  		{
    71  			description:  "0b10/hbh/unicast",
    72  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    73  			action:       header.IPv6OptionUnknownActionDiscardSendICMP,
    74  			multicastDst: false,
    75  			wantICMPv6:   true,
    76  		},
    77  		{
    78  			description:  "0b10/hbh/multicast",
    79  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    80  			action:       header.IPv6OptionUnknownActionDiscardSendICMP,
    81  			multicastDst: true,
    82  			wantICMPv6:   true,
    83  		},
    84  		{
    85  			description:  "0b11/hbh/unicast",
    86  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    87  			action:       header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
    88  			multicastDst: false,
    89  			wantICMPv6:   true,
    90  		},
    91  		{
    92  			description:  "0b11/hbh/multicast",
    93  			mkExtHdr:     mkHopByHopOptionsExtHdr,
    94  			action:       header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
    95  			multicastDst: true,
    96  			wantICMPv6:   false,
    97  		},
    98  		{
    99  			description:  "0b00/destination",
   100  			mkExtHdr:     mkDestinationOptionsExtHdr,
   101  			action:       header.IPv6OptionUnknownActionSkip,
   102  			multicastDst: false,
   103  			wantICMPv6:   false,
   104  		},
   105  		{
   106  			description:  "0b01/destination",
   107  			mkExtHdr:     mkDestinationOptionsExtHdr,
   108  			action:       header.IPv6OptionUnknownActionDiscard,
   109  			multicastDst: false,
   110  			wantICMPv6:   false,
   111  		},
   112  		{
   113  			description:  "0b10/destination/unicast",
   114  			mkExtHdr:     mkDestinationOptionsExtHdr,
   115  			action:       header.IPv6OptionUnknownActionDiscardSendICMP,
   116  			multicastDst: false,
   117  			wantICMPv6:   true,
   118  		},
   119  		{
   120  			description:  "0b10/destination/multicast",
   121  			mkExtHdr:     mkDestinationOptionsExtHdr,
   122  			action:       header.IPv6OptionUnknownActionDiscardSendICMP,
   123  			multicastDst: true,
   124  			wantICMPv6:   true,
   125  		},
   126  		{
   127  			description:  "0b11/destination/unicast",
   128  			mkExtHdr:     mkDestinationOptionsExtHdr,
   129  			action:       header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
   130  			multicastDst: false,
   131  			wantICMPv6:   true,
   132  		},
   133  		{
   134  			description:  "0b11/destination/multicast",
   135  			mkExtHdr:     mkDestinationOptionsExtHdr,
   136  			action:       header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
   137  			multicastDst: true,
   138  			wantICMPv6:   false,
   139  		},
   140  	} {
   141  		t.Run(tt.description, func(t *testing.T) {
   142  			dut := testbench.NewDUT(t)
   143  			conn := dut.Net.NewIPv6Conn(t, testbench.IPv6{}, testbench.IPv6{})
   144  			defer conn.Close(t)
   145  
   146  			outgoingOverride := testbench.Layers{}
   147  			if tt.multicastDst {
   148  				outgoingOverride = testbench.Layers{&testbench.IPv6{
   149  					DstAddr: testbench.Address(tcpip.Address(net.ParseIP("ff02::1"))),
   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  }