golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/icmp/extension_test.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package icmp 6 7 import ( 8 "fmt" 9 "net" 10 "reflect" 11 "testing" 12 13 "golang.org/x/net/internal/iana" 14 "golang.org/x/net/ipv4" 15 "golang.org/x/net/ipv6" 16 ) 17 18 func TestMarshalAndParseExtension(t *testing.T) { 19 fn := func(t *testing.T, proto int, typ Type, hdr, obj []byte, te Extension) error { 20 b, err := te.Marshal(proto) 21 if err != nil { 22 return err 23 } 24 if !reflect.DeepEqual(b, obj) { 25 return fmt.Errorf("got %#v; want %#v", b, obj) 26 } 27 switch typ { 28 case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest: 29 exts, l, err := parseExtensions(typ, append(hdr, obj...), 0) 30 if err != nil { 31 return err 32 } 33 if l != 0 { 34 return fmt.Errorf("got %d; want 0", l) 35 } 36 if !reflect.DeepEqual(exts, []Extension{te}) { 37 return fmt.Errorf("got %#v; want %#v", exts[0], te) 38 } 39 default: 40 for i, wire := range []struct { 41 data []byte // original datagram 42 inlattr int // length of padded original datagram, a hint 43 outlattr int // length of padded original datagram, a want 44 err error 45 }{ 46 {nil, 0, -1, errNoExtension}, 47 {make([]byte, 127), 128, -1, errNoExtension}, 48 49 {make([]byte, 128), 127, -1, errNoExtension}, 50 {make([]byte, 128), 128, -1, errNoExtension}, 51 {make([]byte, 128), 129, -1, errNoExtension}, 52 53 {append(make([]byte, 128), append(hdr, obj...)...), 127, 128, nil}, 54 {append(make([]byte, 128), append(hdr, obj...)...), 128, 128, nil}, 55 {append(make([]byte, 128), append(hdr, obj...)...), 129, 128, nil}, 56 57 {append(make([]byte, 512), append(hdr, obj...)...), 511, -1, errNoExtension}, 58 {append(make([]byte, 512), append(hdr, obj...)...), 512, 512, nil}, 59 {append(make([]byte, 512), append(hdr, obj...)...), 513, -1, errNoExtension}, 60 } { 61 exts, l, err := parseExtensions(typ, wire.data, wire.inlattr) 62 if err != wire.err { 63 return fmt.Errorf("#%d: got %v; want %v", i, err, wire.err) 64 } 65 if wire.err != nil { 66 continue 67 } 68 if l != wire.outlattr { 69 return fmt.Errorf("#%d: got %d; want %d", i, l, wire.outlattr) 70 } 71 if !reflect.DeepEqual(exts, []Extension{te}) { 72 return fmt.Errorf("#%d: got %#v; want %#v", i, exts[0], te) 73 } 74 } 75 } 76 return nil 77 } 78 79 t.Run("MPLSLabelStack", func(t *testing.T) { 80 for _, et := range []struct { 81 proto int 82 typ Type 83 hdr []byte 84 obj []byte 85 ext Extension 86 }{ 87 // MPLS label stack with no label 88 { 89 proto: iana.ProtocolICMP, 90 typ: ipv4.ICMPTypeDestinationUnreachable, 91 hdr: []byte{ 92 0x20, 0x00, 0x00, 0x00, 93 }, 94 obj: []byte{ 95 0x00, 0x04, 0x01, 0x01, 96 }, 97 ext: &MPLSLabelStack{ 98 Class: classMPLSLabelStack, 99 Type: typeIncomingMPLSLabelStack, 100 }, 101 }, 102 // MPLS label stack with a single label 103 { 104 proto: iana.ProtocolIPv6ICMP, 105 typ: ipv6.ICMPTypeDestinationUnreachable, 106 hdr: []byte{ 107 0x20, 0x00, 0x00, 0x00, 108 }, 109 obj: []byte{ 110 0x00, 0x08, 0x01, 0x01, 111 0x03, 0xe8, 0xe9, 0xff, 112 }, 113 ext: &MPLSLabelStack{ 114 Class: classMPLSLabelStack, 115 Type: typeIncomingMPLSLabelStack, 116 Labels: []MPLSLabel{ 117 { 118 Label: 16014, 119 TC: 0x4, 120 S: true, 121 TTL: 255, 122 }, 123 }, 124 }, 125 }, 126 // MPLS label stack with multiple labels 127 { 128 proto: iana.ProtocolICMP, 129 typ: ipv4.ICMPTypeDestinationUnreachable, 130 hdr: []byte{ 131 0x20, 0x00, 0x00, 0x00, 132 }, 133 obj: []byte{ 134 0x00, 0x0c, 0x01, 0x01, 135 0x03, 0xe8, 0xde, 0xfe, 136 0x03, 0xe8, 0xe1, 0xff, 137 }, 138 ext: &MPLSLabelStack{ 139 Class: classMPLSLabelStack, 140 Type: typeIncomingMPLSLabelStack, 141 Labels: []MPLSLabel{ 142 { 143 Label: 16013, 144 TC: 0x7, 145 S: false, 146 TTL: 254, 147 }, 148 { 149 Label: 16014, 150 TC: 0, 151 S: true, 152 TTL: 255, 153 }, 154 }, 155 }, 156 }, 157 } { 158 if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil { 159 t.Error(err) 160 } 161 } 162 }) 163 t.Run("InterfaceInfo", func(t *testing.T) { 164 for _, et := range []struct { 165 proto int 166 typ Type 167 hdr []byte 168 obj []byte 169 ext Extension 170 }{ 171 // Interface information with no attribute 172 { 173 proto: iana.ProtocolICMP, 174 typ: ipv4.ICMPTypeDestinationUnreachable, 175 hdr: []byte{ 176 0x20, 0x00, 0x00, 0x00, 177 }, 178 obj: []byte{ 179 0x00, 0x04, 0x02, 0x00, 180 }, 181 ext: &InterfaceInfo{ 182 Class: classInterfaceInfo, 183 }, 184 }, 185 // Interface information with ifIndex and name 186 { 187 proto: iana.ProtocolICMP, 188 typ: ipv4.ICMPTypeDestinationUnreachable, 189 hdr: []byte{ 190 0x20, 0x00, 0x00, 0x00, 191 }, 192 obj: []byte{ 193 0x00, 0x10, 0x02, 0x0a, 194 0x00, 0x00, 0x00, 0x10, 195 0x08, byte('e'), byte('n'), byte('1'), 196 byte('0'), byte('1'), 0x00, 0x00, 197 }, 198 ext: &InterfaceInfo{ 199 Class: classInterfaceInfo, 200 Type: 0x0a, 201 Interface: &net.Interface{ 202 Index: 16, 203 Name: "en101", 204 }, 205 }, 206 }, 207 // Interface information with ifIndex, IPAddr, name and MTU 208 { 209 proto: iana.ProtocolIPv6ICMP, 210 typ: ipv6.ICMPTypeDestinationUnreachable, 211 hdr: []byte{ 212 0x20, 0x00, 0x00, 0x00, 213 }, 214 obj: []byte{ 215 0x00, 0x28, 0x02, 0x0f, 216 0x00, 0x00, 0x00, 0x0f, 217 0x00, 0x02, 0x00, 0x00, 218 0xfe, 0x80, 0x00, 0x00, 219 0x00, 0x00, 0x00, 0x00, 220 0x00, 0x00, 0x00, 0x00, 221 0x00, 0x00, 0x00, 0x01, 222 0x08, byte('e'), byte('n'), byte('1'), 223 byte('0'), byte('1'), 0x00, 0x00, 224 0x00, 0x00, 0x20, 0x00, 225 }, 226 ext: &InterfaceInfo{ 227 Class: classInterfaceInfo, 228 Type: 0x0f, 229 Interface: &net.Interface{ 230 Index: 15, 231 Name: "en101", 232 MTU: 8192, 233 }, 234 Addr: &net.IPAddr{ 235 IP: net.ParseIP("fe80::1"), 236 Zone: "en101", 237 }, 238 }, 239 }, 240 } { 241 if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil { 242 t.Error(err) 243 } 244 } 245 }) 246 t.Run("InterfaceIdent", func(t *testing.T) { 247 for _, et := range []struct { 248 proto int 249 typ Type 250 hdr []byte 251 obj []byte 252 ext Extension 253 }{ 254 // Interface identification by name 255 { 256 proto: iana.ProtocolICMP, 257 typ: ipv4.ICMPTypeExtendedEchoRequest, 258 hdr: []byte{ 259 0x20, 0x00, 0x00, 0x00, 260 }, 261 obj: []byte{ 262 0x00, 0x0c, 0x03, 0x01, 263 byte('e'), byte('n'), byte('1'), byte('0'), 264 byte('1'), 0x00, 0x00, 0x00, 265 }, 266 ext: &InterfaceIdent{ 267 Class: classInterfaceIdent, 268 Type: typeInterfaceByName, 269 Name: "en101", 270 }, 271 }, 272 // Interface identification by index 273 { 274 proto: iana.ProtocolIPv6ICMP, 275 typ: ipv6.ICMPTypeExtendedEchoRequest, 276 hdr: []byte{ 277 0x20, 0x00, 0x00, 0x00, 278 }, 279 obj: []byte{ 280 0x00, 0x08, 0x03, 0x02, 281 0x00, 0x00, 0x03, 0x8f, 282 }, 283 ext: &InterfaceIdent{ 284 Class: classInterfaceIdent, 285 Type: typeInterfaceByIndex, 286 Index: 911, 287 }, 288 }, 289 // Interface identification by address 290 { 291 proto: iana.ProtocolICMP, 292 typ: ipv4.ICMPTypeExtendedEchoRequest, 293 hdr: []byte{ 294 0x20, 0x00, 0x00, 0x00, 295 }, 296 obj: []byte{ 297 0x00, 0x10, 0x03, 0x03, 298 byte(iana.AddrFamily48bitMAC >> 8), byte(iana.AddrFamily48bitMAC & 0x0f), 0x06, 0x00, 299 0x01, 0x23, 0x45, 0x67, 300 0x89, 0xab, 0x00, 0x00, 301 }, 302 ext: &InterfaceIdent{ 303 Class: classInterfaceIdent, 304 Type: typeInterfaceByAddress, 305 AFI: iana.AddrFamily48bitMAC, 306 Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}, 307 }, 308 }, 309 } { 310 if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil { 311 t.Error(err) 312 } 313 } 314 }) 315 } 316 317 func TestParseInterfaceName(t *testing.T) { 318 ifi := InterfaceInfo{Interface: &net.Interface{}} 319 for i, tt := range []struct { 320 b []byte 321 error 322 }{ 323 {[]byte{0, 'e', 'n', '0'}, errInvalidExtension}, 324 {[]byte{4, 'e', 'n', '0'}, nil}, 325 {[]byte{7, 'e', 'n', '0', 0xff, 0xff, 0xff, 0xff}, errInvalidExtension}, 326 {[]byte{8, 'e', 'n', '0', 0xff, 0xff, 0xff}, errMessageTooShort}, 327 } { 328 if _, err := ifi.parseName(tt.b); err != tt.error { 329 t.Errorf("#%d: got %v; want %v", i, err, tt.error) 330 } 331 } 332 }