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.
14 "golang.org/x/net/icmp"
15 "golang.org/x/net/internal/iana"
16 "golang.org/x/net/ipv4"
17 "golang.org/x/net/ipv6"
20 func TestMarshalAndParseMultipartMessage(t *testing.T) {
21 fn := func(t *testing.T, proto int, tm icmp.Message) error {
22 b, err := tm.Marshal(nil)
27 case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
30 case iana.ProtocolICMP:
32 return fmt.Errorf("got %d; want 32", b[5])
34 case iana.ProtocolIPv6ICMP:
36 return fmt.Errorf("got %d; want 16", b[4])
39 return fmt.Errorf("unknown protocol: %d", proto)
42 m, err := icmp.ParseMessage(proto, b)
46 if m.Type != tm.Type || m.Code != tm.Code {
47 return fmt.Errorf("got %v; want %v", m, &tm)
50 case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
51 got, want := m.Body.(*icmp.ExtendedEchoRequest), tm.Body.(*icmp.ExtendedEchoRequest)
52 if !reflect.DeepEqual(got.Extensions, want.Extensions) {
53 return errors.New(dumpExtensions(got.Extensions, want.Extensions))
55 case ipv4.ICMPTypeDestinationUnreachable:
56 got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
57 if !reflect.DeepEqual(got.Extensions, want.Extensions) {
58 return errors.New(dumpExtensions(got.Extensions, want.Extensions))
60 if len(got.Data) != 128 {
61 return fmt.Errorf("got %d; want 128", len(got.Data))
63 case ipv4.ICMPTypeTimeExceeded:
64 got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
65 if !reflect.DeepEqual(got.Extensions, want.Extensions) {
66 return errors.New(dumpExtensions(got.Extensions, want.Extensions))
68 if len(got.Data) != 128 {
69 return fmt.Errorf("got %d; want 128", len(got.Data))
71 case ipv4.ICMPTypeParameterProblem:
72 got, want := m.Body.(*icmp.ParamProb), tm.Body.(*icmp.ParamProb)
73 if !reflect.DeepEqual(got.Extensions, want.Extensions) {
74 return errors.New(dumpExtensions(got.Extensions, want.Extensions))
76 if len(got.Data) != 128 {
77 return fmt.Errorf("got %d; want 128", len(got.Data))
79 case ipv6.ICMPTypeDestinationUnreachable:
80 got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
81 if !reflect.DeepEqual(got.Extensions, want.Extensions) {
82 return errors.New(dumpExtensions(got.Extensions, want.Extensions))
84 if len(got.Data) != 128 {
85 return fmt.Errorf("got %d; want 128", len(got.Data))
87 case ipv6.ICMPTypeTimeExceeded:
88 got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
89 if !reflect.DeepEqual(got.Extensions, want.Extensions) {
90 return errors.New(dumpExtensions(got.Extensions, want.Extensions))
92 if len(got.Data) != 128 {
93 return fmt.Errorf("got %d; want 128", len(got.Data))
96 return fmt.Errorf("unknown message type: %v", m.Type)
101 t.Run("IPv4", func(t *testing.T) {
102 for i, tm := range []icmp.Message{
104 Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
105 Body: &icmp.DstUnreach{
106 Data: []byte("ERROR-INVOKING-PACKET"),
107 Extensions: []icmp.Extension{
108 &icmp.MPLSLabelStack{
111 Labels: []icmp.MPLSLabel{
123 Interface: &net.Interface{
129 IP: net.IPv4(192, 168, 0, 1).To4(),
136 Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
137 Body: &icmp.TimeExceeded{
138 Data: []byte("ERROR-INVOKING-PACKET"),
139 Extensions: []icmp.Extension{
143 Interface: &net.Interface{
149 IP: net.IPv4(192, 168, 0, 1).To4(),
152 &icmp.MPLSLabelStack{
155 Labels: []icmp.MPLSLabel{
168 Type: ipv4.ICMPTypeParameterProblem, Code: 2,
169 Body: &icmp.ParamProb{
171 Data: []byte("ERROR-INVOKING-PACKET"),
172 Extensions: []icmp.Extension{
173 &icmp.MPLSLabelStack{
176 Labels: []icmp.MPLSLabel{
188 Interface: &net.Interface{
194 IP: net.IPv4(192, 168, 0, 1).To4(),
200 Interface: &net.Interface{
206 IP: net.IPv4(192, 168, 0, 2).To4(),
213 Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
214 Body: &icmp.ExtendedEchoRequest{
215 ID: 1, Seq: 2, Local: true,
216 Extensions: []icmp.Extension{
217 &icmp.InterfaceIdent{
226 Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
227 Body: &icmp.ExtendedEchoRequest{
228 ID: 1, Seq: 2, Local: true,
229 Extensions: []icmp.Extension{
230 &icmp.InterfaceIdent{
239 Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
240 Body: &icmp.ExtendedEchoRequest{
242 Extensions: []icmp.Extension{
243 &icmp.InterfaceIdent{
246 AFI: iana.AddrFamily48bitMAC,
247 Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
253 if err := fn(t, iana.ProtocolICMP, tm); err != nil {
254 t.Errorf("#%d: %v", i, err)
258 t.Run("IPv6", func(t *testing.T) {
259 for i, tm := range []icmp.Message{
261 Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
262 Body: &icmp.DstUnreach{
263 Data: []byte("ERROR-INVOKING-PACKET"),
264 Extensions: []icmp.Extension{
265 &icmp.MPLSLabelStack{
268 Labels: []icmp.MPLSLabel{
280 Interface: &net.Interface{
286 IP: net.ParseIP("fe80::1"),
294 Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
295 Body: &icmp.TimeExceeded{
296 Data: []byte("ERROR-INVOKING-PACKET"),
297 Extensions: []icmp.Extension{
301 Interface: &net.Interface{
307 IP: net.ParseIP("fe80::1"),
311 &icmp.MPLSLabelStack{
314 Labels: []icmp.MPLSLabel{
326 Interface: &net.Interface{
332 IP: net.ParseIP("fe80::1"),
340 Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
341 Body: &icmp.ExtendedEchoRequest{
342 ID: 1, Seq: 2, Local: true,
343 Extensions: []icmp.Extension{
344 &icmp.InterfaceIdent{
353 Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
354 Body: &icmp.ExtendedEchoRequest{
355 ID: 1, Seq: 2, Local: true,
356 Extensions: []icmp.Extension{
357 &icmp.InterfaceIdent{
366 Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
367 Body: &icmp.ExtendedEchoRequest{
369 Extensions: []icmp.Extension{
370 &icmp.InterfaceIdent{
373 AFI: iana.AddrFamilyIPv4,
374 Addr: []byte{192, 0, 2, 1},
380 if err := fn(t, iana.ProtocolIPv6ICMP, tm); err != nil {
381 t.Errorf("#%d: %v", i, err)
387 func dumpExtensions(gotExts, wantExts []icmp.Extension) string {
389 for i, got := range gotExts {
390 switch got := got.(type) {
391 case *icmp.MPLSLabelStack:
392 want := wantExts[i].(*icmp.MPLSLabelStack)
393 if !reflect.DeepEqual(got, want) {
394 s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
396 case *icmp.InterfaceInfo:
397 want := wantExts[i].(*icmp.InterfaceInfo)
398 if !reflect.DeepEqual(got, want) {
399 s += fmt.Sprintf("#%d: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, got, got.Interface, got.Addr, want, want.Interface, want.Addr)
401 case *icmp.InterfaceIdent:
402 want := wantExts[i].(*icmp.InterfaceIdent)
403 if !reflect.DeepEqual(got, want) {
404 s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
406 case *icmp.RawExtension:
407 s += fmt.Sprintf("#%d: raw extension\n", i)
411 s += "empty extension"
416 func TestMultipartMessageBodyLen(t *testing.T) {
417 for i, tt := range []struct {
425 Data: make([]byte, ipv4.HeaderLen),
427 4 + ipv4.HeaderLen, // unused and original datagram
432 Data: make([]byte, ipv4.HeaderLen),
434 4 + ipv4.HeaderLen, // unused and original datagram
439 Data: make([]byte, ipv4.HeaderLen),
441 4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
447 Data: make([]byte, ipv4.HeaderLen),
448 Extensions: []icmp.Extension{
449 &icmp.MPLSLabelStack{},
452 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
457 Data: make([]byte, 128),
458 Extensions: []icmp.Extension{
459 &icmp.MPLSLabelStack{},
462 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
467 Data: make([]byte, 129),
468 Extensions: []icmp.Extension{
469 &icmp.MPLSLabelStack{},
472 4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
476 iana.ProtocolIPv6ICMP,
478 Data: make([]byte, ipv6.HeaderLen),
480 4 + ipv6.HeaderLen, // unused and original datagram
483 iana.ProtocolIPv6ICMP,
485 Data: make([]byte, ipv6.HeaderLen),
487 4 + ipv6.HeaderLen, // mtu and original datagram
490 iana.ProtocolIPv6ICMP,
492 Data: make([]byte, ipv6.HeaderLen),
494 4 + ipv6.HeaderLen, // unused and original datagram
497 iana.ProtocolIPv6ICMP,
499 Data: make([]byte, ipv6.HeaderLen),
501 4 + ipv6.HeaderLen, // pointer and original datagram
505 iana.ProtocolIPv6ICMP,
507 Data: make([]byte, 127),
508 Extensions: []icmp.Extension{
509 &icmp.MPLSLabelStack{},
512 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
515 iana.ProtocolIPv6ICMP,
517 Data: make([]byte, 128),
518 Extensions: []icmp.Extension{
519 &icmp.MPLSLabelStack{},
522 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
525 iana.ProtocolIPv6ICMP,
527 Data: make([]byte, 129),
528 Extensions: []icmp.Extension{
529 &icmp.MPLSLabelStack{},
532 4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
537 &icmp.ExtendedEchoRequest{},
538 4, // [id, seq, l-bit]
542 &icmp.ExtendedEchoRequest{
543 Extensions: []icmp.Extension{
544 &icmp.InterfaceIdent{},
547 4 + 4 + 4, // [id, seq, l-bit], extension header, object header
550 iana.ProtocolIPv6ICMP,
551 &icmp.ExtendedEchoRequest{
552 Extensions: []icmp.Extension{
553 &icmp.InterfaceIdent{
555 AFI: iana.AddrFamilyNSAP,
556 Addr: []byte{0x49, 0x00, 0x01, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0x00},
560 4 + 4 + 4 + 16, // [id, seq, l-bit], extension header, object header, object payload
563 if out := tt.in.Len(tt.proto); out != tt.out {
564 t.Errorf("#%d: got %d; want %d", i, out, tt.out)