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 5package icmp_test 6 7import ( 8 "fmt" 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 19var marshalAndParseMultipartMessageForIPv4Tests = []icmp.Message{ 20 { 21 Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15, 22 Body: &icmp.DstUnreach{ 23 Data: []byte("ERROR-INVOKING-PACKET"), 24 Extensions: []icmp.Extension{ 25 &icmp.MPLSLabelStack{ 26 Class: 1, 27 Type: 1, 28 Labels: []icmp.MPLSLabel{ 29 { 30 Label: 16014, 31 TC: 0x4, 32 S: true, 33 TTL: 255, 34 }, 35 }, 36 }, 37 &icmp.InterfaceInfo{ 38 Class: 2, 39 Type: 0x0f, 40 Interface: &net.Interface{ 41 Index: 15, 42 Name: "en101", 43 MTU: 8192, 44 }, 45 Addr: &net.IPAddr{ 46 IP: net.IPv4(192, 168, 0, 1).To4(), 47 }, 48 }, 49 }, 50 }, 51 }, 52 { 53 Type: ipv4.ICMPTypeTimeExceeded, Code: 1, 54 Body: &icmp.TimeExceeded{ 55 Data: []byte("ERROR-INVOKING-PACKET"), 56 Extensions: []icmp.Extension{ 57 &icmp.InterfaceInfo{ 58 Class: 2, 59 Type: 0x0f, 60 Interface: &net.Interface{ 61 Index: 15, 62 Name: "en101", 63 MTU: 8192, 64 }, 65 Addr: &net.IPAddr{ 66 IP: net.IPv4(192, 168, 0, 1).To4(), 67 }, 68 }, 69 &icmp.MPLSLabelStack{ 70 Class: 1, 71 Type: 1, 72 Labels: []icmp.MPLSLabel{ 73 { 74 Label: 16014, 75 TC: 0x4, 76 S: true, 77 TTL: 255, 78 }, 79 }, 80 }, 81 }, 82 }, 83 }, 84 { 85 Type: ipv4.ICMPTypeParameterProblem, Code: 2, 86 Body: &icmp.ParamProb{ 87 Pointer: 8, 88 Data: []byte("ERROR-INVOKING-PACKET"), 89 Extensions: []icmp.Extension{ 90 &icmp.MPLSLabelStack{ 91 Class: 1, 92 Type: 1, 93 Labels: []icmp.MPLSLabel{ 94 { 95 Label: 16014, 96 TC: 0x4, 97 S: true, 98 TTL: 255, 99 }, 100 }, 101 }, 102 &icmp.InterfaceInfo{ 103 Class: 2, 104 Type: 0x0f, 105 Interface: &net.Interface{ 106 Index: 15, 107 Name: "en101", 108 MTU: 8192, 109 }, 110 Addr: &net.IPAddr{ 111 IP: net.IPv4(192, 168, 0, 1).To4(), 112 }, 113 }, 114 &icmp.InterfaceInfo{ 115 Class: 2, 116 Type: 0x2f, 117 Interface: &net.Interface{ 118 Index: 16, 119 Name: "en102", 120 MTU: 8192, 121 }, 122 Addr: &net.IPAddr{ 123 IP: net.IPv4(192, 168, 0, 2).To4(), 124 }, 125 }, 126 }, 127 }, 128 }, 129} 130 131func TestMarshalAndParseMultipartMessageForIPv4(t *testing.T) { 132 for i, tt := range marshalAndParseMultipartMessageForIPv4Tests { 133 b, err := tt.Marshal(nil) 134 if err != nil { 135 t.Fatal(err) 136 } 137 if b[5] != 32 { 138 t.Errorf("#%v: got %v; want 32", i, b[5]) 139 } 140 m, err := icmp.ParseMessage(iana.ProtocolICMP, b) 141 if err != nil { 142 t.Fatal(err) 143 } 144 if m.Type != tt.Type || m.Code != tt.Code { 145 t.Errorf("#%v: got %v; want %v", i, m, &tt) 146 } 147 switch m.Type { 148 case ipv4.ICMPTypeDestinationUnreachable: 149 got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach) 150 if !reflect.DeepEqual(got.Extensions, want.Extensions) { 151 t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) 152 } 153 if len(got.Data) != 128 { 154 t.Errorf("#%v: got %v; want 128", i, len(got.Data)) 155 } 156 case ipv4.ICMPTypeTimeExceeded: 157 got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded) 158 if !reflect.DeepEqual(got.Extensions, want.Extensions) { 159 t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) 160 } 161 if len(got.Data) != 128 { 162 t.Errorf("#%v: got %v; want 128", i, len(got.Data)) 163 } 164 case ipv4.ICMPTypeParameterProblem: 165 got, want := m.Body.(*icmp.ParamProb), tt.Body.(*icmp.ParamProb) 166 if !reflect.DeepEqual(got.Extensions, want.Extensions) { 167 t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) 168 } 169 if len(got.Data) != 128 { 170 t.Errorf("#%v: got %v; want 128", i, len(got.Data)) 171 } 172 } 173 } 174} 175 176var marshalAndParseMultipartMessageForIPv6Tests = []icmp.Message{ 177 { 178 Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6, 179 Body: &icmp.DstUnreach{ 180 Data: []byte("ERROR-INVOKING-PACKET"), 181 Extensions: []icmp.Extension{ 182 &icmp.MPLSLabelStack{ 183 Class: 1, 184 Type: 1, 185 Labels: []icmp.MPLSLabel{ 186 { 187 Label: 16014, 188 TC: 0x4, 189 S: true, 190 TTL: 255, 191 }, 192 }, 193 }, 194 &icmp.InterfaceInfo{ 195 Class: 2, 196 Type: 0x0f, 197 Interface: &net.Interface{ 198 Index: 15, 199 Name: "en101", 200 MTU: 8192, 201 }, 202 Addr: &net.IPAddr{ 203 IP: net.ParseIP("fe80::1"), 204 Zone: "en101", 205 }, 206 }, 207 }, 208 }, 209 }, 210 { 211 Type: ipv6.ICMPTypeTimeExceeded, Code: 1, 212 Body: &icmp.TimeExceeded{ 213 Data: []byte("ERROR-INVOKING-PACKET"), 214 Extensions: []icmp.Extension{ 215 &icmp.InterfaceInfo{ 216 Class: 2, 217 Type: 0x0f, 218 Interface: &net.Interface{ 219 Index: 15, 220 Name: "en101", 221 MTU: 8192, 222 }, 223 Addr: &net.IPAddr{ 224 IP: net.ParseIP("fe80::1"), 225 Zone: "en101", 226 }, 227 }, 228 &icmp.MPLSLabelStack{ 229 Class: 1, 230 Type: 1, 231 Labels: []icmp.MPLSLabel{ 232 { 233 Label: 16014, 234 TC: 0x4, 235 S: true, 236 TTL: 255, 237 }, 238 }, 239 }, 240 &icmp.InterfaceInfo{ 241 Class: 2, 242 Type: 0x2f, 243 Interface: &net.Interface{ 244 Index: 16, 245 Name: "en102", 246 MTU: 8192, 247 }, 248 Addr: &net.IPAddr{ 249 IP: net.ParseIP("fe80::1"), 250 Zone: "en102", 251 }, 252 }, 253 }, 254 }, 255 }, 256} 257 258func TestMarshalAndParseMultipartMessageForIPv6(t *testing.T) { 259 pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1")) 260 for i, tt := range marshalAndParseMultipartMessageForIPv6Tests { 261 for _, psh := range [][]byte{pshicmp, nil} { 262 b, err := tt.Marshal(psh) 263 if err != nil { 264 t.Fatal(err) 265 } 266 if b[4] != 16 { 267 t.Errorf("#%v: got %v; want 16", i, b[4]) 268 } 269 m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b) 270 if err != nil { 271 t.Fatal(err) 272 } 273 if m.Type != tt.Type || m.Code != tt.Code { 274 t.Errorf("#%v: got %v; want %v", i, m, &tt) 275 } 276 switch m.Type { 277 case ipv6.ICMPTypeDestinationUnreachable: 278 got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach) 279 if !reflect.DeepEqual(got.Extensions, want.Extensions) { 280 t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) 281 } 282 if len(got.Data) != 128 { 283 t.Errorf("#%v: got %v; want 128", i, len(got.Data)) 284 } 285 case ipv6.ICMPTypeTimeExceeded: 286 got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded) 287 if !reflect.DeepEqual(got.Extensions, want.Extensions) { 288 t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) 289 } 290 if len(got.Data) != 128 { 291 t.Errorf("#%v: got %v; want 128", i, len(got.Data)) 292 } 293 } 294 } 295 } 296} 297 298func dumpExtensions(i int, gotExts, wantExts []icmp.Extension) string { 299 var s string 300 for j, got := range gotExts { 301 switch got := got.(type) { 302 case *icmp.MPLSLabelStack: 303 want := wantExts[j].(*icmp.MPLSLabelStack) 304 if !reflect.DeepEqual(got, want) { 305 s += fmt.Sprintf("#%v/%v: got %#v; want %#v\n", i, j, got, want) 306 } 307 case *icmp.InterfaceInfo: 308 want := wantExts[j].(*icmp.InterfaceInfo) 309 if !reflect.DeepEqual(got, want) { 310 s += fmt.Sprintf("#%v/%v: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, j, got, got.Interface, got.Addr, want, want.Interface, want.Addr) 311 } 312 } 313 } 314 return s[:len(s)-1] 315} 316 317var multipartMessageBodyLenTests = []struct { 318 proto int 319 in icmp.MessageBody 320 out int 321}{ 322 { 323 iana.ProtocolICMP, 324 &icmp.DstUnreach{ 325 Data: make([]byte, ipv4.HeaderLen), 326 }, 327 4 + ipv4.HeaderLen, // unused and original datagram 328 }, 329 { 330 iana.ProtocolICMP, 331 &icmp.TimeExceeded{ 332 Data: make([]byte, ipv4.HeaderLen), 333 }, 334 4 + ipv4.HeaderLen, // unused and original datagram 335 }, 336 { 337 iana.ProtocolICMP, 338 &icmp.ParamProb{ 339 Data: make([]byte, ipv4.HeaderLen), 340 }, 341 4 + ipv4.HeaderLen, // [pointer, unused] and original datagram 342 }, 343 344 { 345 iana.ProtocolICMP, 346 &icmp.ParamProb{ 347 Data: make([]byte, ipv4.HeaderLen), 348 Extensions: []icmp.Extension{ 349 &icmp.MPLSLabelStack{}, 350 }, 351 }, 352 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram 353 }, 354 { 355 iana.ProtocolICMP, 356 &icmp.ParamProb{ 357 Data: make([]byte, 128), 358 Extensions: []icmp.Extension{ 359 &icmp.MPLSLabelStack{}, 360 }, 361 }, 362 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram 363 }, 364 { 365 iana.ProtocolICMP, 366 &icmp.ParamProb{ 367 Data: make([]byte, 129), 368 Extensions: []icmp.Extension{ 369 &icmp.MPLSLabelStack{}, 370 }, 371 }, 372 4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram 373 }, 374 375 { 376 iana.ProtocolIPv6ICMP, 377 &icmp.DstUnreach{ 378 Data: make([]byte, ipv6.HeaderLen), 379 }, 380 4 + ipv6.HeaderLen, // unused and original datagram 381 }, 382 { 383 iana.ProtocolIPv6ICMP, 384 &icmp.PacketTooBig{ 385 Data: make([]byte, ipv6.HeaderLen), 386 }, 387 4 + ipv6.HeaderLen, // mtu and original datagram 388 }, 389 { 390 iana.ProtocolIPv6ICMP, 391 &icmp.TimeExceeded{ 392 Data: make([]byte, ipv6.HeaderLen), 393 }, 394 4 + ipv6.HeaderLen, // unused and original datagram 395 }, 396 { 397 iana.ProtocolIPv6ICMP, 398 &icmp.ParamProb{ 399 Data: make([]byte, ipv6.HeaderLen), 400 }, 401 4 + ipv6.HeaderLen, // pointer and original datagram 402 }, 403 404 { 405 iana.ProtocolIPv6ICMP, 406 &icmp.DstUnreach{ 407 Data: make([]byte, 127), 408 Extensions: []icmp.Extension{ 409 &icmp.MPLSLabelStack{}, 410 }, 411 }, 412 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram 413 }, 414 { 415 iana.ProtocolIPv6ICMP, 416 &icmp.DstUnreach{ 417 Data: make([]byte, 128), 418 Extensions: []icmp.Extension{ 419 &icmp.MPLSLabelStack{}, 420 }, 421 }, 422 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram 423 }, 424 { 425 iana.ProtocolIPv6ICMP, 426 &icmp.DstUnreach{ 427 Data: make([]byte, 129), 428 Extensions: []icmp.Extension{ 429 &icmp.MPLSLabelStack{}, 430 }, 431 }, 432 4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram 433 }, 434} 435 436func TestMultipartMessageBodyLen(t *testing.T) { 437 for i, tt := range multipartMessageBodyLenTests { 438 if out := tt.in.Len(tt.proto); out != tt.out { 439 t.Errorf("#%d: got %d; want %d", i, out, tt.out) 440 } 441 } 442} 443