You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
5.5 KiB

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