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