github.com/lianghucheng/zrddz@v0.0.0-20200923083010-c71f680932e2/src/golang.org/x/net/icmp/extension.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 6 7 import ( 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. 15 type 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 27 const extensionVersion = 2 28 29 func 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. 48 func 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 default: 107 ext := &RawExtension{Data: make([]byte, ol)} 108 copy(ext.Data, b[:ol]) 109 exts = append(exts, ext) 110 } 111 b = b[ol:] 112 } 113 return exts, l, nil 114 } 115 116 func validExtensions(typ Type, exts []Extension) bool { 117 switch typ { 118 case ipv4.ICMPTypeDestinationUnreachable, ipv4.ICMPTypeTimeExceeded, ipv4.ICMPTypeParameterProblem, 119 ipv6.ICMPTypeDestinationUnreachable, ipv6.ICMPTypeTimeExceeded: 120 for i := range exts { 121 switch exts[i].(type) { 122 case *MPLSLabelStack, *InterfaceInfo, *RawExtension: 123 default: 124 return false 125 } 126 } 127 return true 128 case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest: 129 var n int 130 for i := range exts { 131 switch exts[i].(type) { 132 case *InterfaceIdent: 133 n++ 134 case *RawExtension: 135 default: 136 return false 137 } 138 } 139 // Not a single InterfaceIdent object or a combo of 140 // RawExtension and InterfaceIdent objects is not 141 // allowed. 142 if n == 1 && len(exts) > 1 { 143 return false 144 } 145 return true 146 default: 147 return false 148 } 149 } 150 151 // A RawExtension represents a raw extension. 152 // 153 // A raw extension is excluded from message processing and can be used 154 // to construct applications such as protocol conformance testing. 155 type RawExtension struct { 156 Data []byte // data 157 } 158 159 // Len implements the Len method of Extension interface. 160 func (p *RawExtension) Len(proto int) int { 161 if p == nil { 162 return 0 163 } 164 return len(p.Data) 165 } 166 167 // Marshal implements the Marshal method of Extension interface. 168 func (p *RawExtension) Marshal(proto int) ([]byte, error) { 169 return p.Data, nil 170 }