| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package icmp |
| |
| import ( |
| "fmt" |
| "net" |
| "reflect" |
| "testing" |
| |
| "golang.org/x/net/internal/iana" |
| "golang.org/x/net/ipv4" |
| "golang.org/x/net/ipv6" |
| ) |
| |
| func TestMarshalAndParseExtension(t *testing.T) { |
| fn := func(t *testing.T, proto int, typ Type, hdr, obj []byte, te Extension) error { |
| b, err := te.Marshal(proto) |
| if err != nil { |
| return err |
| } |
| if !reflect.DeepEqual(b, obj) { |
| return fmt.Errorf("got %#v; want %#v", b, obj) |
| } |
| switch typ { |
| case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest: |
| exts, l, err := parseExtensions(typ, append(hdr, obj...), 0) |
| if err != nil { |
| return err |
| } |
| if l != 0 { |
| return fmt.Errorf("got %d; want 0", l) |
| } |
| if !reflect.DeepEqual(exts, []Extension{te}) { |
| return fmt.Errorf("got %#v; want %#v", exts[0], te) |
| } |
| default: |
| for i, wire := range []struct { |
| data []byte // original datagram |
| inlattr int // length of padded original datagram, a hint |
| outlattr int // length of padded original datagram, a want |
| err error |
| }{ |
| {nil, 0, -1, errNoExtension}, |
| {make([]byte, 127), 128, -1, errNoExtension}, |
| |
| {make([]byte, 128), 127, -1, errNoExtension}, |
| {make([]byte, 128), 128, -1, errNoExtension}, |
| {make([]byte, 128), 129, -1, errNoExtension}, |
| |
| {append(make([]byte, 128), append(hdr, obj...)...), 127, 128, nil}, |
| {append(make([]byte, 128), append(hdr, obj...)...), 128, 128, nil}, |
| {append(make([]byte, 128), append(hdr, obj...)...), 129, 128, nil}, |
| |
| {append(make([]byte, 512), append(hdr, obj...)...), 511, -1, errNoExtension}, |
| {append(make([]byte, 512), append(hdr, obj...)...), 512, 512, nil}, |
| {append(make([]byte, 512), append(hdr, obj...)...), 513, -1, errNoExtension}, |
| } { |
| exts, l, err := parseExtensions(typ, wire.data, wire.inlattr) |
| if err != wire.err { |
| return fmt.Errorf("#%d: got %v; want %v", i, err, wire.err) |
| } |
| if wire.err != nil { |
| continue |
| } |
| if l != wire.outlattr { |
| return fmt.Errorf("#%d: got %d; want %d", i, l, wire.outlattr) |
| } |
| if !reflect.DeepEqual(exts, []Extension{te}) { |
| return fmt.Errorf("#%d: got %#v; want %#v", i, exts[0], te) |
| } |
| } |
| } |
| return nil |
| } |
| |
| t.Run("MPLSLabelStack", func(t *testing.T) { |
| for _, et := range []struct { |
| proto int |
| typ Type |
| hdr []byte |
| obj []byte |
| ext Extension |
| }{ |
| // MPLS label stack with no label |
| { |
| proto: iana.ProtocolICMP, |
| typ: ipv4.ICMPTypeDestinationUnreachable, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x04, 0x01, 0x01, |
| }, |
| ext: &MPLSLabelStack{ |
| Class: classMPLSLabelStack, |
| Type: typeIncomingMPLSLabelStack, |
| }, |
| }, |
| // MPLS label stack with a single label |
| { |
| proto: iana.ProtocolIPv6ICMP, |
| typ: ipv6.ICMPTypeDestinationUnreachable, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x08, 0x01, 0x01, |
| 0x03, 0xe8, 0xe9, 0xff, |
| }, |
| ext: &MPLSLabelStack{ |
| Class: classMPLSLabelStack, |
| Type: typeIncomingMPLSLabelStack, |
| Labels: []MPLSLabel{ |
| { |
| Label: 16014, |
| TC: 0x4, |
| S: true, |
| TTL: 255, |
| }, |
| }, |
| }, |
| }, |
| // MPLS label stack with multiple labels |
| { |
| proto: iana.ProtocolICMP, |
| typ: ipv4.ICMPTypeDestinationUnreachable, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x0c, 0x01, 0x01, |
| 0x03, 0xe8, 0xde, 0xfe, |
| 0x03, 0xe8, 0xe1, 0xff, |
| }, |
| ext: &MPLSLabelStack{ |
| Class: classMPLSLabelStack, |
| Type: typeIncomingMPLSLabelStack, |
| Labels: []MPLSLabel{ |
| { |
| Label: 16013, |
| TC: 0x7, |
| S: false, |
| TTL: 254, |
| }, |
| { |
| Label: 16014, |
| TC: 0, |
| S: true, |
| TTL: 255, |
| }, |
| }, |
| }, |
| }, |
| } { |
| if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil { |
| t.Error(err) |
| } |
| } |
| }) |
| t.Run("InterfaceInfo", func(t *testing.T) { |
| for _, et := range []struct { |
| proto int |
| typ Type |
| hdr []byte |
| obj []byte |
| ext Extension |
| }{ |
| // Interface information with no attribute |
| { |
| proto: iana.ProtocolICMP, |
| typ: ipv4.ICMPTypeDestinationUnreachable, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x04, 0x02, 0x00, |
| }, |
| ext: &InterfaceInfo{ |
| Class: classInterfaceInfo, |
| }, |
| }, |
| // Interface information with ifIndex and name |
| { |
| proto: iana.ProtocolICMP, |
| typ: ipv4.ICMPTypeDestinationUnreachable, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x10, 0x02, 0x0a, |
| 0x00, 0x00, 0x00, 0x10, |
| 0x08, byte('e'), byte('n'), byte('1'), |
| byte('0'), byte('1'), 0x00, 0x00, |
| }, |
| ext: &InterfaceInfo{ |
| Class: classInterfaceInfo, |
| Type: 0x0a, |
| Interface: &net.Interface{ |
| Index: 16, |
| Name: "en101", |
| }, |
| }, |
| }, |
| // Interface information with ifIndex, IPAddr, name and MTU |
| { |
| proto: iana.ProtocolIPv6ICMP, |
| typ: ipv6.ICMPTypeDestinationUnreachable, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x28, 0x02, 0x0f, |
| 0x00, 0x00, 0x00, 0x0f, |
| 0x00, 0x02, 0x00, 0x00, |
| 0xfe, 0x80, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x01, |
| 0x08, byte('e'), byte('n'), byte('1'), |
| byte('0'), byte('1'), 0x00, 0x00, |
| 0x00, 0x00, 0x20, 0x00, |
| }, |
| ext: &InterfaceInfo{ |
| Class: classInterfaceInfo, |
| Type: 0x0f, |
| Interface: &net.Interface{ |
| Index: 15, |
| Name: "en101", |
| MTU: 8192, |
| }, |
| Addr: &net.IPAddr{ |
| IP: net.ParseIP("fe80::1"), |
| Zone: "en101", |
| }, |
| }, |
| }, |
| } { |
| if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil { |
| t.Error(err) |
| } |
| } |
| }) |
| t.Run("InterfaceIdent", func(t *testing.T) { |
| for _, et := range []struct { |
| proto int |
| typ Type |
| hdr []byte |
| obj []byte |
| ext Extension |
| }{ |
| // Interface identification by name |
| { |
| proto: iana.ProtocolICMP, |
| typ: ipv4.ICMPTypeExtendedEchoRequest, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x0c, 0x03, 0x01, |
| byte('e'), byte('n'), byte('1'), byte('0'), |
| byte('1'), 0x00, 0x00, 0x00, |
| }, |
| ext: &InterfaceIdent{ |
| Class: classInterfaceIdent, |
| Type: typeInterfaceByName, |
| Name: "en101", |
| }, |
| }, |
| // Interface identification by index |
| { |
| proto: iana.ProtocolIPv6ICMP, |
| typ: ipv6.ICMPTypeExtendedEchoRequest, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x08, 0x03, 0x02, |
| 0x00, 0x00, 0x03, 0x8f, |
| }, |
| ext: &InterfaceIdent{ |
| Class: classInterfaceIdent, |
| Type: typeInterfaceByIndex, |
| Index: 911, |
| }, |
| }, |
| // Interface identification by address |
| { |
| proto: iana.ProtocolICMP, |
| typ: ipv4.ICMPTypeExtendedEchoRequest, |
| hdr: []byte{ |
| 0x20, 0x00, 0x00, 0x00, |
| }, |
| obj: []byte{ |
| 0x00, 0x10, 0x03, 0x03, |
| byte(iana.AddrFamily48bitMAC >> 8), byte(iana.AddrFamily48bitMAC & 0x0f), 0x06, 0x00, |
| 0x01, 0x23, 0x45, 0x67, |
| 0x89, 0xab, 0x00, 0x00, |
| }, |
| ext: &InterfaceIdent{ |
| Class: classInterfaceIdent, |
| Type: typeInterfaceByAddress, |
| AFI: iana.AddrFamily48bitMAC, |
| Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}, |
| }, |
| }, |
| } { |
| if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil { |
| t.Error(err) |
| } |
| } |
| }) |
| } |
| |
| func TestParseInterfaceName(t *testing.T) { |
| ifi := InterfaceInfo{Interface: &net.Interface{}} |
| for i, tt := range []struct { |
| b []byte |
| error |
| }{ |
| {[]byte{0, 'e', 'n', '0'}, errInvalidExtension}, |
| {[]byte{4, 'e', 'n', '0'}, nil}, |
| {[]byte{7, 'e', 'n', '0', 0xff, 0xff, 0xff, 0xff}, errInvalidExtension}, |
| {[]byte{8, 'e', 'n', '0', 0xff, 0xff, 0xff}, errMessageTooShort}, |
| } { |
| if _, err := ifi.parseName(tt.b); err != tt.error { |
| t.Errorf("#%d: got %v; want %v", i, err, tt.error) |
| } |
| } |
| } |