github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/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 "net" 9 "strings" 10 11 "golang.org/x/net/internal/iana" 12 ) 13 14 const ( 15 classInterfaceInfo = 2 16 17 afiIPv4 = 1 18 afiIPv6 = 2 19 ) 20 21 const ( 22 attrMTU = 1 << iota 23 attrName 24 attrIPAddr 25 attrIfIndex 26 ) 27 28 // An InterfaceInfo represents interface and next-hop identification. 29 type InterfaceInfo struct { 30 Class int // extension object class number 31 Type int // extension object sub-type 32 Interface *net.Interface 33 Addr *net.IPAddr 34 } 35 36 func (ifi *InterfaceInfo) nameLen() int { 37 if len(ifi.Interface.Name) > 63 { 38 return 64 39 } 40 l := 1 + len(ifi.Interface.Name) 41 return (l + 3) &^ 3 42 } 43 44 func (ifi *InterfaceInfo) attrsAndLen(proto int) (attrs, l int) { 45 l = 4 46 if ifi.Interface != nil && ifi.Interface.Index > 0 { 47 attrs |= attrIfIndex 48 l += 4 49 if len(ifi.Interface.Name) > 0 { 50 attrs |= attrName 51 l += ifi.nameLen() 52 } 53 if ifi.Interface.MTU > 0 { 54 attrs |= attrMTU 55 l += 4 56 } 57 } 58 if ifi.Addr != nil { 59 switch proto { 60 case iana.ProtocolICMP: 61 if ifi.Addr.IP.To4() != nil { 62 attrs |= attrIPAddr 63 l += 4 + net.IPv4len 64 } 65 case iana.ProtocolIPv6ICMP: 66 if ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil { 67 attrs |= attrIPAddr 68 l += 4 + net.IPv6len 69 } 70 } 71 } 72 return 73 } 74 75 // Len implements the Len method of Extension interface. 76 func (ifi *InterfaceInfo) Len(proto int) int { 77 _, l := ifi.attrsAndLen(proto) 78 return l 79 } 80 81 // Marshal implements the Marshal method of Extension interface. 82 func (ifi *InterfaceInfo) Marshal(proto int) ([]byte, error) { 83 attrs, l := ifi.attrsAndLen(proto) 84 b := make([]byte, l) 85 if err := ifi.marshal(proto, b, attrs, l); err != nil { 86 return nil, err 87 } 88 return b, nil 89 } 90 91 func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error { 92 b[0], b[1] = byte(l>>8), byte(l) 93 b[2], b[3] = classInterfaceInfo, byte(ifi.Type) 94 for b = b[4:]; len(b) > 0 && attrs != 0; { 95 switch { 96 case attrs&attrIfIndex != 0: 97 b = ifi.marshalIfIndex(proto, b) 98 attrs &^= attrIfIndex 99 case attrs&attrIPAddr != 0: 100 b = ifi.marshalIPAddr(proto, b) 101 attrs &^= attrIPAddr 102 case attrs&attrName != 0: 103 b = ifi.marshalName(proto, b) 104 attrs &^= attrName 105 case attrs&attrMTU != 0: 106 b = ifi.marshalMTU(proto, b) 107 attrs &^= attrMTU 108 } 109 } 110 return nil 111 } 112 113 func (ifi *InterfaceInfo) marshalIfIndex(proto int, b []byte) []byte { 114 b[0], b[1], b[2], b[3] = byte(ifi.Interface.Index>>24), byte(ifi.Interface.Index>>16), byte(ifi.Interface.Index>>8), byte(ifi.Interface.Index) 115 return b[4:] 116 } 117 118 func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) { 119 if len(b) < 4 { 120 return nil, errMessageTooShort 121 } 122 ifi.Interface.Index = int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3]) 123 return b[4:], nil 124 } 125 126 func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte { 127 switch proto { 128 case iana.ProtocolICMP: 129 b[0], b[1] = byte(afiIPv4>>8), byte(afiIPv4) 130 copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4()) 131 b = b[4+net.IPv4len:] 132 case iana.ProtocolIPv6ICMP: 133 b[0], b[1] = byte(afiIPv6>>8), byte(afiIPv6) 134 copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16()) 135 b = b[4+net.IPv6len:] 136 } 137 return b 138 } 139 140 func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) { 141 if len(b) < 4 { 142 return nil, errMessageTooShort 143 } 144 afi := int(b[0])<<8 | int(b[1]) 145 b = b[4:] 146 switch afi { 147 case afiIPv4: 148 if len(b) < net.IPv4len { 149 return nil, errMessageTooShort 150 } 151 ifi.Addr.IP = make(net.IP, net.IPv4len) 152 copy(ifi.Addr.IP, b[:net.IPv4len]) 153 b = b[net.IPv4len:] 154 case afiIPv6: 155 if len(b) < net.IPv6len { 156 return nil, errMessageTooShort 157 } 158 ifi.Addr.IP = make(net.IP, net.IPv6len) 159 copy(ifi.Addr.IP, b[:net.IPv6len]) 160 b = b[net.IPv6len:] 161 } 162 return b, nil 163 } 164 165 func (ifi *InterfaceInfo) marshalName(proto int, b []byte) []byte { 166 l := byte(ifi.nameLen()) 167 b[0] = l 168 copy(b[1:], []byte(ifi.Interface.Name)) 169 return b[l:] 170 } 171 172 func (ifi *InterfaceInfo) parseName(b []byte) ([]byte, error) { 173 if 4 > len(b) || len(b) < int(b[0]) { 174 return nil, errMessageTooShort 175 } 176 l := int(b[0]) 177 if l%4 != 0 || 4 > l || l > 64 { 178 return nil, errInvalidExtension 179 } 180 var name [63]byte 181 copy(name[:], b[1:l]) 182 ifi.Interface.Name = strings.Trim(string(name[:]), "\000") 183 return b[l:], nil 184 } 185 186 func (ifi *InterfaceInfo) marshalMTU(proto int, b []byte) []byte { 187 b[0], b[1], b[2], b[3] = byte(ifi.Interface.MTU>>24), byte(ifi.Interface.MTU>>16), byte(ifi.Interface.MTU>>8), byte(ifi.Interface.MTU) 188 return b[4:] 189 } 190 191 func (ifi *InterfaceInfo) parseMTU(b []byte) ([]byte, error) { 192 if len(b) < 4 { 193 return nil, errMessageTooShort 194 } 195 ifi.Interface.MTU = int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3]) 196 return b[4:], nil 197 } 198 199 func parseInterfaceInfo(b []byte) (Extension, error) { 200 ifi := &InterfaceInfo{ 201 Class: int(b[2]), 202 Type: int(b[3]), 203 } 204 if ifi.Type&(attrIfIndex|attrName|attrMTU) != 0 { 205 ifi.Interface = &net.Interface{} 206 } 207 if ifi.Type&attrIPAddr != 0 { 208 ifi.Addr = &net.IPAddr{} 209 } 210 attrs := ifi.Type & (attrIfIndex | attrIPAddr | attrName | attrMTU) 211 for b = b[4:]; len(b) > 0 && attrs != 0; { 212 var err error 213 switch { 214 case attrs&attrIfIndex != 0: 215 b, err = ifi.parseIfIndex(b) 216 attrs &^= attrIfIndex 217 case attrs&attrIPAddr != 0: 218 b, err = ifi.parseIPAddr(b) 219 attrs &^= attrIPAddr 220 case attrs&attrName != 0: 221 b, err = ifi.parseName(b) 222 attrs &^= attrName 223 case attrs&attrMTU != 0: 224 b, err = ifi.parseMTU(b) 225 attrs &^= attrMTU 226 } 227 if err != nil { 228 return nil, err 229 } 230 } 231 if ifi.Interface != nil && ifi.Interface.Name != "" && ifi.Addr != nil && ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil { 232 ifi.Addr.Zone = ifi.Interface.Name 233 } 234 return ifi, nil 235 }