github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/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  	"github.com/Andyfoo/golang/x/net/internal/iana"
    14  	"github.com/Andyfoo/golang/x/net/ipv4"
    15  	"github.com/Andyfoo/golang/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  }