1
2
3
4
5 package icmp_test
6
7 import (
8 "errors"
9 "fmt"
10 "net"
11 "reflect"
12 "testing"
13
14 "golang.org/x/net/icmp"
15 "golang.org/x/net/internal/iana"
16 "golang.org/x/net/ipv4"
17 "golang.org/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,
428 },
429 {
430 iana.ProtocolICMP,
431 &icmp.TimeExceeded{
432 Data: make([]byte, ipv4.HeaderLen),
433 },
434 4 + ipv4.HeaderLen,
435 },
436 {
437 iana.ProtocolICMP,
438 &icmp.ParamProb{
439 Data: make([]byte, ipv4.HeaderLen),
440 },
441 4 + ipv4.HeaderLen,
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,
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,
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,
473 },
474
475 {
476 iana.ProtocolIPv6ICMP,
477 &icmp.DstUnreach{
478 Data: make([]byte, ipv6.HeaderLen),
479 },
480 4 + ipv6.HeaderLen,
481 },
482 {
483 iana.ProtocolIPv6ICMP,
484 &icmp.PacketTooBig{
485 Data: make([]byte, ipv6.HeaderLen),
486 },
487 4 + ipv6.HeaderLen,
488 },
489 {
490 iana.ProtocolIPv6ICMP,
491 &icmp.TimeExceeded{
492 Data: make([]byte, ipv6.HeaderLen),
493 },
494 4 + ipv6.HeaderLen,
495 },
496 {
497 iana.ProtocolIPv6ICMP,
498 &icmp.ParamProb{
499 Data: make([]byte, ipv6.HeaderLen),
500 },
501 4 + ipv6.HeaderLen,
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,
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,
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,
533 },
534
535 {
536 iana.ProtocolICMP,
537 &icmp.ExtendedEchoRequest{},
538 4,
539 },
540 {
541 iana.ProtocolICMP,
542 &icmp.ExtendedEchoRequest{
543 Extensions: []icmp.Extension{
544 &icmp.InterfaceIdent{},
545 },
546 },
547 4 + 4 + 4,
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,
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 }
568
View as plain text