blob: 402a7514b0538f1764266ceb13059efc9760d694 [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// 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
6
7import "encoding/binary"
8
9// An Extension represents an ICMP extension.
10type Extension interface {
11 // Len returns the length of ICMP extension.
12 // Proto must be either the ICMPv4 or ICMPv6 protocol number.
13 Len(proto int) int
14
15 // Marshal returns the binary encoding of ICMP extension.
16 // Proto must be either the ICMPv4 or ICMPv6 protocol number.
17 Marshal(proto int) ([]byte, error)
18}
19
20const extensionVersion = 2
21
22func validExtensionHeader(b []byte) bool {
23 v := int(b[0]&0xf0) >> 4
24 s := binary.BigEndian.Uint16(b[2:4])
25 if s != 0 {
26 s = checksum(b)
27 }
28 if v != extensionVersion || s != 0 {
29 return false
30 }
31 return true
32}
33
34// parseExtensions parses b as a list of ICMP extensions.
35// The length attribute l must be the length attribute field in
36// received icmp messages.
37//
38// It will return a list of ICMP extensions and an adjusted length
39// attribute that represents the length of the padded original
40// datagram field. Otherwise, it returns an error.
41func parseExtensions(b []byte, l int) ([]Extension, int, error) {
42 // Still a lot of non-RFC 4884 compliant implementations are
43 // out there. Set the length attribute l to 128 when it looks
44 // inappropriate for backwards compatibility.
45 //
46 // A minimal extension at least requires 8 octets; 4 octets
47 // for an extension header, and 4 octets for a single object
48 // header.
49 //
50 // See RFC 4884 for further information.
51 if 128 > l || l+8 > len(b) {
52 l = 128
53 }
54 if l+8 > len(b) {
55 return nil, -1, errNoExtension
56 }
57 if !validExtensionHeader(b[l:]) {
58 if l == 128 {
59 return nil, -1, errNoExtension
60 }
61 l = 128
62 if !validExtensionHeader(b[l:]) {
63 return nil, -1, errNoExtension
64 }
65 }
66 var exts []Extension
67 for b = b[l+4:]; len(b) >= 4; {
68 ol := int(binary.BigEndian.Uint16(b[:2]))
69 if 4 > ol || ol > len(b) {
70 break
71 }
72 switch b[2] {
73 case classMPLSLabelStack:
74 ext, err := parseMPLSLabelStack(b[:ol])
75 if err != nil {
76 return nil, -1, err
77 }
78 exts = append(exts, ext)
79 case classInterfaceInfo:
80 ext, err := parseInterfaceInfo(b[:ol])
81 if err != nil {
82 return nil, -1, err
83 }
84 exts = append(exts, ext)
85 }
86 b = b[ol:]
87 }
88 return exts, l, nil
89}