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