OSDN Git Service

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