golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/icmp/message_test.go (about)

     1  // Copyright 2014 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  	"bytes"
     9  	"net"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"golang.org/x/net/icmp"
    14  	"golang.org/x/net/internal/iana"
    15  	"golang.org/x/net/ipv4"
    16  	"golang.org/x/net/ipv6"
    17  )
    18  
    19  func TestMarshalAndParseMessage(t *testing.T) {
    20  	fn := func(t *testing.T, proto int, tms []icmp.Message) {
    21  		var pshs [][]byte
    22  		switch proto {
    23  		case iana.ProtocolICMP:
    24  			pshs = [][]byte{nil}
    25  		case iana.ProtocolIPv6ICMP:
    26  			pshs = [][]byte{
    27  				icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1")),
    28  				nil,
    29  			}
    30  		}
    31  		for i, tm := range tms {
    32  			for _, psh := range pshs {
    33  				b, err := tm.Marshal(psh)
    34  				if err != nil {
    35  					t.Fatalf("#%d: %v", i, err)
    36  				}
    37  				m, err := icmp.ParseMessage(proto, b)
    38  				if err != nil {
    39  					t.Fatalf("#%d: %v", i, err)
    40  				}
    41  				if m.Type != tm.Type || m.Code != tm.Code {
    42  					t.Errorf("#%d: got %#v; want %#v", i, m, &tm)
    43  					continue
    44  				}
    45  				if !reflect.DeepEqual(m.Body, tm.Body) {
    46  					t.Errorf("#%d: got %#v; want %#v", i, m.Body, tm.Body)
    47  					continue
    48  				}
    49  			}
    50  		}
    51  	}
    52  
    53  	t.Run("IPv4", func(t *testing.T) {
    54  		fn(t, iana.ProtocolICMP,
    55  			[]icmp.Message{
    56  				{
    57  					Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
    58  					Body: &icmp.DstUnreach{
    59  						Data: []byte("ERROR-INVOKING-PACKET"),
    60  					},
    61  				},
    62  				{
    63  					Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
    64  					Body: &icmp.TimeExceeded{
    65  						Data: []byte("ERROR-INVOKING-PACKET"),
    66  					},
    67  				},
    68  				{
    69  					Type: ipv4.ICMPTypeParameterProblem, Code: 2,
    70  					Body: &icmp.ParamProb{
    71  						Pointer: 8,
    72  						Data:    []byte("ERROR-INVOKING-PACKET"),
    73  					},
    74  				},
    75  				{
    76  					Type: ipv4.ICMPTypeEcho, Code: 0,
    77  					Body: &icmp.Echo{
    78  						ID: 1, Seq: 2,
    79  						Data: []byte("HELLO-R-U-THERE"),
    80  					},
    81  				},
    82  				{
    83  					Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
    84  					Body: &icmp.ExtendedEchoRequest{
    85  						ID: 1, Seq: 2,
    86  						Extensions: []icmp.Extension{
    87  							&icmp.InterfaceIdent{
    88  								Class: 3,
    89  								Type:  1,
    90  								Name:  "en101",
    91  							},
    92  						},
    93  					},
    94  				},
    95  				{
    96  					Type: ipv4.ICMPTypeExtendedEchoReply, Code: 0,
    97  					Body: &icmp.ExtendedEchoReply{
    98  						State: 4 /* Delay */, Active: true, IPv4: true,
    99  					},
   100  				},
   101  			})
   102  	})
   103  	t.Run("IPv6", func(t *testing.T) {
   104  		fn(t, iana.ProtocolIPv6ICMP,
   105  			[]icmp.Message{
   106  				{
   107  					Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
   108  					Body: &icmp.DstUnreach{
   109  						Data: []byte("ERROR-INVOKING-PACKET"),
   110  					},
   111  				},
   112  				{
   113  					Type: ipv6.ICMPTypePacketTooBig, Code: 0,
   114  					Body: &icmp.PacketTooBig{
   115  						MTU:  1<<16 - 1,
   116  						Data: []byte("ERROR-INVOKING-PACKET"),
   117  					},
   118  				},
   119  				{
   120  					Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
   121  					Body: &icmp.TimeExceeded{
   122  						Data: []byte("ERROR-INVOKING-PACKET"),
   123  					},
   124  				},
   125  				{
   126  					Type: ipv6.ICMPTypeParameterProblem, Code: 2,
   127  					Body: &icmp.ParamProb{
   128  						Pointer: 8,
   129  						Data:    []byte("ERROR-INVOKING-PACKET"),
   130  					},
   131  				},
   132  				{
   133  					Type: ipv6.ICMPTypeEchoRequest, Code: 0,
   134  					Body: &icmp.Echo{
   135  						ID: 1, Seq: 2,
   136  						Data: []byte("HELLO-R-U-THERE"),
   137  					},
   138  				},
   139  				{
   140  					Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
   141  					Body: &icmp.ExtendedEchoRequest{
   142  						ID: 1, Seq: 2,
   143  						Extensions: []icmp.Extension{
   144  							&icmp.InterfaceIdent{
   145  								Class: 3,
   146  								Type:  2,
   147  								Index: 911,
   148  							},
   149  						},
   150  					},
   151  				},
   152  				{
   153  					Type: ipv6.ICMPTypeExtendedEchoReply, Code: 0,
   154  					Body: &icmp.ExtendedEchoReply{
   155  						State: 5 /* Probe */, Active: true, IPv6: true,
   156  					},
   157  				},
   158  			})
   159  	})
   160  }
   161  
   162  func TestMarshalAndParseRawMessage(t *testing.T) {
   163  	t.Run("RawBody", func(t *testing.T) {
   164  		for i, tt := range []struct {
   165  			m               icmp.Message
   166  			wire            []byte
   167  			parseShouldFail bool
   168  		}{
   169  			{ // Nil body
   170  				m: icmp.Message{
   171  					Type: ipv4.ICMPTypeDestinationUnreachable, Code: 127,
   172  				},
   173  				wire: []byte{
   174  					0x03, 0x7f, 0xfc, 0x80,
   175  				},
   176  				parseShouldFail: true,
   177  			},
   178  			{ // Empty body
   179  				m: icmp.Message{
   180  					Type: ipv6.ICMPTypeDestinationUnreachable, Code: 128,
   181  					Body: &icmp.RawBody{},
   182  				},
   183  				wire: []byte{
   184  					0x01, 0x80, 0x00, 0x00,
   185  				},
   186  				parseShouldFail: true,
   187  			},
   188  			{ // Crafted body
   189  				m: icmp.Message{
   190  					Type: ipv6.ICMPTypeDuplicateAddressConfirmation, Code: 129,
   191  					Body: &icmp.RawBody{
   192  						Data: []byte{0xca, 0xfe},
   193  					},
   194  				},
   195  				wire: []byte{
   196  					0x9e, 0x81, 0x00, 0x00,
   197  					0xca, 0xfe,
   198  				},
   199  				parseShouldFail: false,
   200  			},
   201  		} {
   202  			b, err := tt.m.Marshal(nil)
   203  			if err != nil {
   204  				t.Errorf("#%d: %v", i, err)
   205  				continue
   206  			}
   207  			if !bytes.Equal(b, tt.wire) {
   208  				t.Errorf("#%d: got %#v; want %#v", i, b, tt.wire)
   209  				continue
   210  			}
   211  			m, err := icmp.ParseMessage(tt.m.Type.Protocol(), b)
   212  			if err != nil != tt.parseShouldFail {
   213  				t.Errorf("#%d: got %v, %v", i, m, err)
   214  				continue
   215  			}
   216  			if tt.parseShouldFail {
   217  				continue
   218  			}
   219  			if m.Type != tt.m.Type || m.Code != tt.m.Code {
   220  				t.Errorf("#%d: got %v; want %v", i, m, tt.m)
   221  				continue
   222  			}
   223  			if !bytes.Equal(m.Body.(*icmp.RawBody).Data, tt.m.Body.(*icmp.RawBody).Data) {
   224  				t.Errorf("#%d: got %#v; want %#v", i, m.Body, tt.m.Body)
   225  				continue
   226  			}
   227  		}
   228  	})
   229  	t.Run("RawExtension", func(t *testing.T) {
   230  		for i, tt := range []struct {
   231  			m    icmp.Message
   232  			wire []byte
   233  		}{
   234  			{ // Unaligned data and nil extension
   235  				m: icmp.Message{
   236  					Type: ipv6.ICMPTypeDestinationUnreachable, Code: 130,
   237  					Body: &icmp.DstUnreach{
   238  						Data: []byte("ERROR-INVOKING-PACKET"),
   239  					},
   240  				},
   241  				wire: []byte{
   242  					0x01, 0x82, 0x00, 0x00,
   243  					0x00, 0x00, 0x00, 0x00,
   244  					'E', 'R', 'R', 'O',
   245  					'R', '-', 'I', 'N',
   246  					'V', 'O', 'K', 'I',
   247  					'N', 'G', '-', 'P',
   248  					'A', 'C', 'K', 'E',
   249  					'T',
   250  				},
   251  			},
   252  			{ // Unaligned data and empty extension
   253  				m: icmp.Message{
   254  					Type: ipv6.ICMPTypeDestinationUnreachable, Code: 131,
   255  					Body: &icmp.DstUnreach{
   256  						Data: []byte("ERROR-INVOKING-PACKET"),
   257  						Extensions: []icmp.Extension{
   258  							&icmp.RawExtension{},
   259  						},
   260  					},
   261  				},
   262  				wire: []byte{
   263  					0x01, 0x83, 0x00, 0x00,
   264  					0x02, 0x00, 0x00, 0x00,
   265  					'E', 'R', 'R', 'O',
   266  					'R', '-', 'I', 'N',
   267  					'V', 'O', 'K', 'I',
   268  					'N', 'G', '-', 'P',
   269  					'A', 'C', 'K', 'E',
   270  					'T',
   271  					0x20, 0x00, 0xdf, 0xff,
   272  				},
   273  			},
   274  			{ // Nil extension
   275  				m: icmp.Message{
   276  					Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 132,
   277  					Body: &icmp.ExtendedEchoRequest{
   278  						ID: 1, Seq: 2, Local: true,
   279  					},
   280  				},
   281  				wire: []byte{
   282  					0xa0, 0x84, 0x00, 0x00,
   283  					0x00, 0x01, 0x02, 0x01,
   284  				},
   285  			},
   286  			{ // Empty extension
   287  				m: icmp.Message{
   288  					Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 133,
   289  					Body: &icmp.ExtendedEchoRequest{
   290  						ID: 1, Seq: 2, Local: true,
   291  						Extensions: []icmp.Extension{
   292  							&icmp.RawExtension{},
   293  						},
   294  					},
   295  				},
   296  				wire: []byte{
   297  					0xa0, 0x85, 0x00, 0x00,
   298  					0x00, 0x01, 0x02, 0x01,
   299  					0x20, 0x00, 0xdf, 0xff,
   300  				},
   301  			},
   302  			{ // Crafted extension
   303  				m: icmp.Message{
   304  					Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 134,
   305  					Body: &icmp.ExtendedEchoRequest{
   306  						ID: 1, Seq: 2, Local: true,
   307  						Extensions: []icmp.Extension{
   308  							&icmp.RawExtension{
   309  								Data: []byte("CRAFTED"),
   310  							},
   311  						},
   312  					},
   313  				},
   314  				wire: []byte{
   315  					0xa0, 0x86, 0x00, 0x00,
   316  					0x00, 0x01, 0x02, 0x01,
   317  					0x20, 0x00, 0xc3, 0x21,
   318  					'C', 'R', 'A', 'F',
   319  					'T', 'E', 'D',
   320  				},
   321  			},
   322  		} {
   323  			b, err := tt.m.Marshal(nil)
   324  			if err != nil {
   325  				t.Errorf("#%d: %v", i, err)
   326  				continue
   327  			}
   328  			if !bytes.Equal(b, tt.wire) {
   329  				t.Errorf("#%d: got %#v; want %#v", i, b, tt.wire)
   330  				continue
   331  			}
   332  			m, err := icmp.ParseMessage(tt.m.Type.Protocol(), b)
   333  			if err != nil {
   334  				t.Errorf("#%d: %v", i, err)
   335  				continue
   336  			}
   337  			if m.Type != tt.m.Type || m.Code != tt.m.Code {
   338  				t.Errorf("#%d: got %v; want %v", i, m, tt.m)
   339  				continue
   340  			}
   341  		}
   342  	})
   343  }