github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/icmp/multipart_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_test
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"net"
    11  	"reflect"
    12  	"testing"
    13  
    14  	"github.com/hxx258456/ccgo/net/icmp"
    15  	"github.com/hxx258456/ccgo/net/internal/iana"
    16  	"github.com/hxx258456/ccgo/net/ipv4"
    17  	"github.com/hxx258456/ccgo/net/ipv6"
    18  )
    19  
    20  func TestMarshalAndParseMultipartMessage(t *testing.T) {
    21  	fn := func(t *testing.T, proto int, tm icmp.Message) error {
    22  		b, err := tm.Marshal(nil)
    23  		if err != nil {
    24  			return err
    25  		}
    26  		switch tm.Type {
    27  		case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
    28  		default:
    29  			switch proto {
    30  			case iana.ProtocolICMP:
    31  				if b[5] != 32 {
    32  					return fmt.Errorf("got %d; want 32", b[5])
    33  				}
    34  			case iana.ProtocolIPv6ICMP:
    35  				if b[4] != 16 {
    36  					return fmt.Errorf("got %d; want 16", b[4])
    37  				}
    38  			default:
    39  				return fmt.Errorf("unknown protocol: %d", proto)
    40  			}
    41  		}
    42  		m, err := icmp.ParseMessage(proto, b)
    43  		if err != nil {
    44  			return err
    45  		}
    46  		if m.Type != tm.Type || m.Code != tm.Code {
    47  			return fmt.Errorf("got %v; want %v", m, &tm)
    48  		}
    49  		switch m.Type {
    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))
    54  			}
    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))
    59  			}
    60  			if len(got.Data) != 128 {
    61  				return fmt.Errorf("got %d; want 128", len(got.Data))
    62  			}
    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))
    67  			}
    68  			if len(got.Data) != 128 {
    69  				return fmt.Errorf("got %d; want 128", len(got.Data))
    70  			}
    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))
    75  			}
    76  			if len(got.Data) != 128 {
    77  				return fmt.Errorf("got %d; want 128", len(got.Data))
    78  			}
    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))
    83  			}
    84  			if len(got.Data) != 128 {
    85  				return fmt.Errorf("got %d; want 128", len(got.Data))
    86  			}
    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))
    91  			}
    92  			if len(got.Data) != 128 {
    93  				return fmt.Errorf("got %d; want 128", len(got.Data))
    94  			}
    95  		default:
    96  			return fmt.Errorf("unknown message type: %v", m.Type)
    97  		}
    98  		return nil
    99  	}
   100  
   101  	t.Run("IPv4", func(t *testing.T) {
   102  		for i, tm := range []icmp.Message{
   103  			{
   104  				Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
   105  				Body: &icmp.DstUnreach{
   106  					Data: []byte("ERROR-INVOKING-PACKET"),
   107  					Extensions: []icmp.Extension{
   108  						&icmp.MPLSLabelStack{
   109  							Class: 1,
   110  							Type:  1,
   111  							Labels: []icmp.MPLSLabel{
   112  								{
   113  									Label: 16014,
   114  									TC:    0x4,
   115  									S:     true,
   116  									TTL:   255,
   117  								},
   118  							},
   119  						},
   120  						&icmp.InterfaceInfo{
   121  							Class: 2,
   122  							Type:  0x0f,
   123  							Interface: &net.Interface{
   124  								Index: 15,
   125  								Name:  "en101",
   126  								MTU:   8192,
   127  							},
   128  							Addr: &net.IPAddr{
   129  								IP: net.IPv4(192, 168, 0, 1).To4(),
   130  							},
   131  						},
   132  					},
   133  				},
   134  			},
   135  			{
   136  				Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
   137  				Body: &icmp.TimeExceeded{
   138  					Data: []byte("ERROR-INVOKING-PACKET"),
   139  					Extensions: []icmp.Extension{
   140  						&icmp.InterfaceInfo{
   141  							Class: 2,
   142  							Type:  0x0f,
   143  							Interface: &net.Interface{
   144  								Index: 15,
   145  								Name:  "en101",
   146  								MTU:   8192,
   147  							},
   148  							Addr: &net.IPAddr{
   149  								IP: net.IPv4(192, 168, 0, 1).To4(),
   150  							},
   151  						},
   152  						&icmp.MPLSLabelStack{
   153  							Class: 1,
   154  							Type:  1,
   155  							Labels: []icmp.MPLSLabel{
   156  								{
   157  									Label: 16014,
   158  									TC:    0x4,
   159  									S:     true,
   160  									TTL:   255,
   161  								},
   162  							},
   163  						},
   164  					},
   165  				},
   166  			},
   167  			{
   168  				Type: ipv4.ICMPTypeParameterProblem, Code: 2,
   169  				Body: &icmp.ParamProb{
   170  					Pointer: 8,
   171  					Data:    []byte("ERROR-INVOKING-PACKET"),
   172  					Extensions: []icmp.Extension{
   173  						&icmp.MPLSLabelStack{
   174  							Class: 1,
   175  							Type:  1,
   176  							Labels: []icmp.MPLSLabel{
   177  								{
   178  									Label: 16014,
   179  									TC:    0x4,
   180  									S:     true,
   181  									TTL:   255,
   182  								},
   183  							},
   184  						},
   185  						&icmp.InterfaceInfo{
   186  							Class: 2,
   187  							Type:  0x0f,
   188  							Interface: &net.Interface{
   189  								Index: 15,
   190  								Name:  "en101",
   191  								MTU:   8192,
   192  							},
   193  							Addr: &net.IPAddr{
   194  								IP: net.IPv4(192, 168, 0, 1).To4(),
   195  							},
   196  						},
   197  						&icmp.InterfaceInfo{
   198  							Class: 2,
   199  							Type:  0x2f,
   200  							Interface: &net.Interface{
   201  								Index: 16,
   202  								Name:  "en102",
   203  								MTU:   8192,
   204  							},
   205  							Addr: &net.IPAddr{
   206  								IP: net.IPv4(192, 168, 0, 2).To4(),
   207  							},
   208  						},
   209  					},
   210  				},
   211  			},
   212  			{
   213  				Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
   214  				Body: &icmp.ExtendedEchoRequest{
   215  					ID: 1, Seq: 2, Local: true,
   216  					Extensions: []icmp.Extension{
   217  						&icmp.InterfaceIdent{
   218  							Class: 3,
   219  							Type:  1,
   220  							Name:  "en101",
   221  						},
   222  					},
   223  				},
   224  			},
   225  			{
   226  				Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
   227  				Body: &icmp.ExtendedEchoRequest{
   228  					ID: 1, Seq: 2, Local: true,
   229  					Extensions: []icmp.Extension{
   230  						&icmp.InterfaceIdent{
   231  							Class: 3,
   232  							Type:  2,
   233  							Index: 911,
   234  						},
   235  					},
   236  				},
   237  			},
   238  			{
   239  				Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
   240  				Body: &icmp.ExtendedEchoRequest{
   241  					ID: 1, Seq: 2,
   242  					Extensions: []icmp.Extension{
   243  						&icmp.InterfaceIdent{
   244  							Class: 3,
   245  							Type:  3,
   246  							AFI:   iana.AddrFamily48bitMAC,
   247  							Addr:  []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
   248  						},
   249  					},
   250  				},
   251  			},
   252  		} {
   253  			if err := fn(t, iana.ProtocolICMP, tm); err != nil {
   254  				t.Errorf("#%d: %v", i, err)
   255  			}
   256  		}
   257  	})
   258  	t.Run("IPv6", func(t *testing.T) {
   259  		for i, tm := range []icmp.Message{
   260  			{
   261  				Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
   262  				Body: &icmp.DstUnreach{
   263  					Data: []byte("ERROR-INVOKING-PACKET"),
   264  					Extensions: []icmp.Extension{
   265  						&icmp.MPLSLabelStack{
   266  							Class: 1,
   267  							Type:  1,
   268  							Labels: []icmp.MPLSLabel{
   269  								{
   270  									Label: 16014,
   271  									TC:    0x4,
   272  									S:     true,
   273  									TTL:   255,
   274  								},
   275  							},
   276  						},
   277  						&icmp.InterfaceInfo{
   278  							Class: 2,
   279  							Type:  0x0f,
   280  							Interface: &net.Interface{
   281  								Index: 15,
   282  								Name:  "en101",
   283  								MTU:   8192,
   284  							},
   285  							Addr: &net.IPAddr{
   286  								IP:   net.ParseIP("fe80::1"),
   287  								Zone: "en101",
   288  							},
   289  						},
   290  					},
   291  				},
   292  			},
   293  			{
   294  				Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
   295  				Body: &icmp.TimeExceeded{
   296  					Data: []byte("ERROR-INVOKING-PACKET"),
   297  					Extensions: []icmp.Extension{
   298  						&icmp.InterfaceInfo{
   299  							Class: 2,
   300  							Type:  0x0f,
   301  							Interface: &net.Interface{
   302  								Index: 15,
   303  								Name:  "en101",
   304  								MTU:   8192,
   305  							},
   306  							Addr: &net.IPAddr{
   307  								IP:   net.ParseIP("fe80::1"),
   308  								Zone: "en101",
   309  							},
   310  						},
   311  						&icmp.MPLSLabelStack{
   312  							Class: 1,
   313  							Type:  1,
   314  							Labels: []icmp.MPLSLabel{
   315  								{
   316  									Label: 16014,
   317  									TC:    0x4,
   318  									S:     true,
   319  									TTL:   255,
   320  								},
   321  							},
   322  						},
   323  						&icmp.InterfaceInfo{
   324  							Class: 2,
   325  							Type:  0x2f,
   326  							Interface: &net.Interface{
   327  								Index: 16,
   328  								Name:  "en102",
   329  								MTU:   8192,
   330  							},
   331  							Addr: &net.IPAddr{
   332  								IP:   net.ParseIP("fe80::1"),
   333  								Zone: "en102",
   334  							},
   335  						},
   336  					},
   337  				},
   338  			},
   339  			{
   340  				Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
   341  				Body: &icmp.ExtendedEchoRequest{
   342  					ID: 1, Seq: 2, Local: true,
   343  					Extensions: []icmp.Extension{
   344  						&icmp.InterfaceIdent{
   345  							Class: 3,
   346  							Type:  1,
   347  							Name:  "en101",
   348  						},
   349  					},
   350  				},
   351  			},
   352  			{
   353  				Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
   354  				Body: &icmp.ExtendedEchoRequest{
   355  					ID: 1, Seq: 2, Local: true,
   356  					Extensions: []icmp.Extension{
   357  						&icmp.InterfaceIdent{
   358  							Class: 3,
   359  							Type:  2,
   360  							Index: 911,
   361  						},
   362  					},
   363  				},
   364  			},
   365  			{
   366  				Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
   367  				Body: &icmp.ExtendedEchoRequest{
   368  					ID: 1, Seq: 2,
   369  					Extensions: []icmp.Extension{
   370  						&icmp.InterfaceIdent{
   371  							Class: 3,
   372  							Type:  3,
   373  							AFI:   iana.AddrFamilyIPv4,
   374  							Addr:  []byte{192, 0, 2, 1},
   375  						},
   376  					},
   377  				},
   378  			},
   379  		} {
   380  			if err := fn(t, iana.ProtocolIPv6ICMP, tm); err != nil {
   381  				t.Errorf("#%d: %v", i, err)
   382  			}
   383  		}
   384  	})
   385  }
   386  
   387  func dumpExtensions(gotExts, wantExts []icmp.Extension) string {
   388  	var s 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)
   395  			}
   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)
   400  			}
   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)
   405  			}
   406  		case *icmp.RawExtension:
   407  			s += fmt.Sprintf("#%d: raw extension\n", i)
   408  		}
   409  	}
   410  	if len(s) == 0 {
   411  		s += "empty extension"
   412  	}
   413  	return s[:len(s)-1]
   414  }
   415  
   416  func TestMultipartMessageBodyLen(t *testing.T) {
   417  	for i, tt := range []struct {
   418  		proto int
   419  		in    icmp.MessageBody
   420  		out   int
   421  	}{
   422  		{
   423  			iana.ProtocolICMP,
   424  			&icmp.DstUnreach{
   425  				Data: make([]byte, ipv4.HeaderLen),
   426  			},
   427  			4 + ipv4.HeaderLen, // unused and original datagram
   428  		},
   429  		{
   430  			iana.ProtocolICMP,
   431  			&icmp.TimeExceeded{
   432  				Data: make([]byte, ipv4.HeaderLen),
   433  			},
   434  			4 + ipv4.HeaderLen, // unused and original datagram
   435  		},
   436  		{
   437  			iana.ProtocolICMP,
   438  			&icmp.ParamProb{
   439  				Data: make([]byte, ipv4.HeaderLen),
   440  			},
   441  			4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
   442  		},
   443  
   444  		{
   445  			iana.ProtocolICMP,
   446  			&icmp.ParamProb{
   447  				Data: make([]byte, ipv4.HeaderLen),
   448  				Extensions: []icmp.Extension{
   449  					&icmp.MPLSLabelStack{},
   450  				},
   451  			},
   452  			4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
   453  		},
   454  		{
   455  			iana.ProtocolICMP,
   456  			&icmp.ParamProb{
   457  				Data: make([]byte, 128),
   458  				Extensions: []icmp.Extension{
   459  					&icmp.MPLSLabelStack{},
   460  				},
   461  			},
   462  			4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
   463  		},
   464  		{
   465  			iana.ProtocolICMP,
   466  			&icmp.ParamProb{
   467  				Data: make([]byte, 129),
   468  				Extensions: []icmp.Extension{
   469  					&icmp.MPLSLabelStack{},
   470  				},
   471  			},
   472  			4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
   473  		},
   474  
   475  		{
   476  			iana.ProtocolIPv6ICMP,
   477  			&icmp.DstUnreach{
   478  				Data: make([]byte, ipv6.HeaderLen),
   479  			},
   480  			4 + ipv6.HeaderLen, // unused and original datagram
   481  		},
   482  		{
   483  			iana.ProtocolIPv6ICMP,
   484  			&icmp.PacketTooBig{
   485  				Data: make([]byte, ipv6.HeaderLen),
   486  			},
   487  			4 + ipv6.HeaderLen, // mtu and original datagram
   488  		},
   489  		{
   490  			iana.ProtocolIPv6ICMP,
   491  			&icmp.TimeExceeded{
   492  				Data: make([]byte, ipv6.HeaderLen),
   493  			},
   494  			4 + ipv6.HeaderLen, // unused and original datagram
   495  		},
   496  		{
   497  			iana.ProtocolIPv6ICMP,
   498  			&icmp.ParamProb{
   499  				Data: make([]byte, ipv6.HeaderLen),
   500  			},
   501  			4 + ipv6.HeaderLen, // pointer and original datagram
   502  		},
   503  
   504  		{
   505  			iana.ProtocolIPv6ICMP,
   506  			&icmp.DstUnreach{
   507  				Data: make([]byte, 127),
   508  				Extensions: []icmp.Extension{
   509  					&icmp.MPLSLabelStack{},
   510  				},
   511  			},
   512  			4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
   513  		},
   514  		{
   515  			iana.ProtocolIPv6ICMP,
   516  			&icmp.DstUnreach{
   517  				Data: make([]byte, 128),
   518  				Extensions: []icmp.Extension{
   519  					&icmp.MPLSLabelStack{},
   520  				},
   521  			},
   522  			4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
   523  		},
   524  		{
   525  			iana.ProtocolIPv6ICMP,
   526  			&icmp.DstUnreach{
   527  				Data: make([]byte, 129),
   528  				Extensions: []icmp.Extension{
   529  					&icmp.MPLSLabelStack{},
   530  				},
   531  			},
   532  			4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
   533  		},
   534  
   535  		{
   536  			iana.ProtocolICMP,
   537  			&icmp.ExtendedEchoRequest{},
   538  			4, // [id, seq, l-bit]
   539  		},
   540  		{
   541  			iana.ProtocolICMP,
   542  			&icmp.ExtendedEchoRequest{
   543  				Extensions: []icmp.Extension{
   544  					&icmp.InterfaceIdent{},
   545  				},
   546  			},
   547  			4 + 4 + 4, // [id, seq, l-bit], extension header, object header
   548  		},
   549  		{
   550  			iana.ProtocolIPv6ICMP,
   551  			&icmp.ExtendedEchoRequest{
   552  				Extensions: []icmp.Extension{
   553  					&icmp.InterfaceIdent{
   554  						Type: 3,
   555  						AFI:  iana.AddrFamilyNSAP,
   556  						Addr: []byte{0x49, 0x00, 0x01, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0x00},
   557  					},
   558  				},
   559  			},
   560  			4 + 4 + 4 + 16, // [id, seq, l-bit], extension header, object header, object payload
   561  		},
   562  	} {
   563  		if out := tt.in.Len(tt.proto); out != tt.out {
   564  			t.Errorf("#%d: got %d; want %d", i, out, tt.out)
   565  		}
   566  	}
   567  }