github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/icmp/interface.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 "net" 10 "strings" 11 12 "github.com/Andyfoo/golang/x/net/internal/iana" 13 ) 14 15 const ( 16 classInterfaceInfo = 2 17 ) 18 19 const ( 20 attrMTU = 1 << iota 21 attrName 22 attrIPAddr 23 attrIfIndex 24 ) 25 26 // An InterfaceInfo represents interface and next-hop identification. 27 type InterfaceInfo struct { 28 Class int // extension object class number 29 Type int // extension object sub-type 30 Interface *net.Interface 31 Addr *net.IPAddr 32 } 33 34 func (ifi *InterfaceInfo) nameLen() int { 35 if len(ifi.Interface.Name) > 63 { 36 return 64 37 } 38 l := 1 + len(ifi.Interface.Name) 39 return (l + 3) &^ 3 40 } 41 42 func (ifi *InterfaceInfo) attrsAndLen(proto int) (attrs, l int) { 43 l = 4 44 if ifi.Interface != nil && ifi.Interface.Index > 0 { 45 attrs |= attrIfIndex 46 l += 4 47 if len(ifi.Interface.Name) > 0 { 48 attrs |= attrName 49 l += ifi.nameLen() 50 } 51 if ifi.Interface.MTU > 0 { 52 attrs |= attrMTU 53 l += 4 54 } 55 } 56 if ifi.Addr != nil { 57 switch proto { 58 case iana.ProtocolICMP: 59 if ifi.Addr.IP.To4() != nil { 60 attrs |= attrIPAddr 61 l += 4 + net.IPv4len 62 } 63 case iana.ProtocolIPv6ICMP: 64 if ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil { 65 attrs |= attrIPAddr 66 l += 4 + net.IPv6len 67 } 68 } 69 } 70 return 71 } 72 73 // Len implements the Len method of Extension interface. 74 func (ifi *InterfaceInfo) Len(proto int) int { 75 _, l := ifi.attrsAndLen(proto) 76 return l 77 } 78 79 // Marshal implements the Marshal method of Extension interface. 80 func (ifi *InterfaceInfo) Marshal(proto int) ([]byte, error) { 81 attrs, l := ifi.attrsAndLen(proto) 82 b := make([]byte, l) 83 if err := ifi.marshal(proto, b, attrs, l); err != nil { 84 return nil, err 85 } 86 return b, nil 87 } 88 89 func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error { 90 binary.BigEndian.PutUint16(b[:2], uint16(l)) 91 b[2], b[3] = classInterfaceInfo, byte(ifi.Type) 92 for b = b[4:]; len(b) > 0 && attrs != 0; { 93 switch { 94 case attrs&attrIfIndex != 0: 95 b = ifi.marshalIfIndex(proto, b) 96 attrs &^= attrIfIndex 97 case attrs&attrIPAddr != 0: 98 b = ifi.marshalIPAddr(proto, b) 99 attrs &^= attrIPAddr 100 case attrs&attrName != 0: 101 b = ifi.marshalName(proto, b) 102 attrs &^= attrName 103 case attrs&attrMTU != 0: 104 b = ifi.marshalMTU(proto, b) 105 attrs &^= attrMTU 106 } 107 } 108 return nil 109 } 110 111 func (ifi *InterfaceInfo) marshalIfIndex(proto int, b []byte) []byte { 112 binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.Index)) 113 return b[4:] 114 } 115 116 func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) { 117 if len(b) < 4 { 118 return nil, errMessageTooShort 119 } 120 ifi.Interface.Index = int(binary.BigEndian.Uint32(b[:4])) 121 return b[4:], nil 122 } 123 124 func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte { 125 switch proto { 126 case iana.ProtocolICMP: 127 binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv4)) 128 copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4()) 129 b = b[4+net.IPv4len:] 130 case iana.ProtocolIPv6ICMP: 131 binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv6)) 132 copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16()) 133 b = b[4+net.IPv6len:] 134 } 135 return b 136 } 137 138 func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) { 139 if len(b) < 4 { 140 return nil, errMessageTooShort 141 } 142 afi := int(binary.BigEndian.Uint16(b[:2])) 143 b = b[4:] 144 switch afi { 145 case iana.AddrFamilyIPv4: 146 if len(b) < net.IPv4len { 147 return nil, errMessageTooShort 148 } 149 ifi.Addr.IP = make(net.IP, net.IPv4len) 150 copy(ifi.Addr.IP, b[:net.IPv4len]) 151 b = b[net.IPv4len:] 152 case iana.AddrFamilyIPv6: 153 if len(b) < net.IPv6len { 154 return nil, errMessageTooShort 155 } 156 ifi.Addr.IP = make(net.IP, net.IPv6len) 157 copy(ifi.Addr.IP, b[:net.IPv6len]) 158 b = b[net.IPv6len:] 159 } 160 return b, nil 161 } 162 163 func (ifi *InterfaceInfo) marshalName(proto int, b []byte) []byte { 164 l := byte(ifi.nameLen()) 165 b[0] = l 166 copy(b[1:], []byte(ifi.Interface.Name)) 167 return b[l:] 168 } 169 170 func (ifi *InterfaceInfo) parseName(b []byte) ([]byte, error) { 171 if 4 > len(b) || len(b) < int(b[0]) { 172 return nil, errMessageTooShort 173 } 174 l := int(b[0]) 175 if l%4 != 0 || 4 > l || l > 64 { 176 return nil, errInvalidExtension 177 } 178 var name [63]byte 179 copy(name[:], b[1:l]) 180 ifi.Interface.Name = strings.Trim(string(name[:]), "\000") 181 return b[l:], nil 182 } 183 184 func (ifi *InterfaceInfo) marshalMTU(proto int, b []byte) []byte { 185 binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.MTU)) 186 return b[4:] 187 } 188 189 func (ifi *InterfaceInfo) parseMTU(b []byte) ([]byte, error) { 190 if len(b) < 4 { 191 return nil, errMessageTooShort 192 } 193 ifi.Interface.MTU = int(binary.BigEndian.Uint32(b[:4])) 194 return b[4:], nil 195 } 196 197 func parseInterfaceInfo(b []byte) (Extension, error) { 198 ifi := &InterfaceInfo{ 199 Class: int(b[2]), 200 Type: int(b[3]), 201 } 202 if ifi.Type&(attrIfIndex|attrName|attrMTU) != 0 { 203 ifi.Interface = &net.Interface{} 204 } 205 if ifi.Type&attrIPAddr != 0 { 206 ifi.Addr = &net.IPAddr{} 207 } 208 attrs := ifi.Type & (attrIfIndex | attrIPAddr | attrName | attrMTU) 209 for b = b[4:]; len(b) > 0 && attrs != 0; { 210 var err error 211 switch { 212 case attrs&attrIfIndex != 0: 213 b, err = ifi.parseIfIndex(b) 214 attrs &^= attrIfIndex 215 case attrs&attrIPAddr != 0: 216 b, err = ifi.parseIPAddr(b) 217 attrs &^= attrIPAddr 218 case attrs&attrName != 0: 219 b, err = ifi.parseName(b) 220 attrs &^= attrName 221 case attrs&attrMTU != 0: 222 b, err = ifi.parseMTU(b) 223 attrs &^= attrMTU 224 } 225 if err != nil { 226 return nil, err 227 } 228 } 229 if ifi.Interface != nil && ifi.Interface.Name != "" && ifi.Addr != nil && ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil { 230 ifi.Addr.Zone = ifi.Interface.Name 231 } 232 return ifi, nil 233 } 234 235 const ( 236 classInterfaceIdent = 3 237 typeInterfaceByName = 1 238 typeInterfaceByIndex = 2 239 typeInterfaceByAddress = 3 240 ) 241 242 // An InterfaceIdent represents interface identification. 243 type InterfaceIdent struct { 244 Class int // extension object class number 245 Type int // extension object sub-type 246 Name string // interface name 247 Index int // interface index 248 AFI int // address family identifier; see address family numbers in IANA registry 249 Addr []byte // address 250 } 251 252 // Len implements the Len method of Extension interface. 253 func (ifi *InterfaceIdent) Len(_ int) int { 254 switch ifi.Type { 255 case typeInterfaceByName: 256 l := len(ifi.Name) 257 if l > 255 { 258 l = 255 259 } 260 return 4 + (l+3)&^3 261 case typeInterfaceByIndex: 262 return 4 + 4 263 case typeInterfaceByAddress: 264 return 4 + 4 + (len(ifi.Addr)+3)&^3 265 default: 266 return 4 267 } 268 } 269 270 // Marshal implements the Marshal method of Extension interface. 271 func (ifi *InterfaceIdent) Marshal(proto int) ([]byte, error) { 272 b := make([]byte, ifi.Len(proto)) 273 if err := ifi.marshal(proto, b); err != nil { 274 return nil, err 275 } 276 return b, nil 277 } 278 279 func (ifi *InterfaceIdent) marshal(proto int, b []byte) error { 280 l := ifi.Len(proto) 281 binary.BigEndian.PutUint16(b[:2], uint16(l)) 282 b[2], b[3] = classInterfaceIdent, byte(ifi.Type) 283 switch ifi.Type { 284 case typeInterfaceByName: 285 copy(b[4:], ifi.Name) 286 case typeInterfaceByIndex: 287 binary.BigEndian.PutUint32(b[4:4+4], uint32(ifi.Index)) 288 case typeInterfaceByAddress: 289 binary.BigEndian.PutUint16(b[4:4+2], uint16(ifi.AFI)) 290 b[4+2] = byte(len(ifi.Addr)) 291 copy(b[4+4:], ifi.Addr) 292 } 293 return nil 294 } 295 296 func parseInterfaceIdent(b []byte) (Extension, error) { 297 ifi := &InterfaceIdent{ 298 Class: int(b[2]), 299 Type: int(b[3]), 300 } 301 switch ifi.Type { 302 case typeInterfaceByName: 303 ifi.Name = strings.Trim(string(b[4:]), string(0)) 304 case typeInterfaceByIndex: 305 if len(b[4:]) < 4 { 306 return nil, errInvalidExtension 307 } 308 ifi.Index = int(binary.BigEndian.Uint32(b[4 : 4+4])) 309 case typeInterfaceByAddress: 310 if len(b[4:]) < 4 { 311 return nil, errInvalidExtension 312 } 313 ifi.AFI = int(binary.BigEndian.Uint16(b[4 : 4+2])) 314 l := int(b[4+2]) 315 if len(b[4+4:]) < l { 316 return nil, errInvalidExtension 317 } 318 ifi.Addr = make([]byte, l) 319 copy(ifi.Addr, b[4+4:]) 320 } 321 return ifi, nil 322 }