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 }