1
2
3
4
5 package icmp
6
7 import (
8 "encoding/binary"
9 "net"
10 "strings"
11
12 "golang.org/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
27 type InterfaceInfo struct {
28 Class int
29 Type int
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
74 func (ifi *InterfaceInfo) Len(proto int) int {
75 _, l := ifi.attrsAndLen(proto)
76 return l
77 }
78
79
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
243 type InterfaceIdent struct {
244 Class int
245 Type int
246 Name string
247 Index int
248 AFI int
249 Addr []byte
250 }
251
252
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
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:]), "\x00")
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 }
323
View as plain text