icmp6.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // Copyright 2012 Google, Inc. All rights reserved.
  2. // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
  3. //
  4. // Use of this source code is governed by a BSD-style license
  5. // that can be found in the LICENSE file in the root of the source
  6. // tree.
  7. package layers
  8. import (
  9. "encoding/binary"
  10. "errors"
  11. "fmt"
  12. "reflect"
  13. "github.com/google/gopacket"
  14. )
  15. const (
  16. // The following are from RFC 4443
  17. ICMPv6TypeDestinationUnreachable = 1
  18. ICMPv6TypePacketTooBig = 2
  19. ICMPv6TypeTimeExceeded = 3
  20. ICMPv6TypeParameterProblem = 4
  21. ICMPv6TypeEchoRequest = 128
  22. ICMPv6TypeEchoReply = 129
  23. // The following are from RFC 4861
  24. ICMPv6TypeRouterSolicitation = 133
  25. ICMPv6TypeRouterAdvertisement = 134
  26. ICMPv6TypeNeighborSolicitation = 135
  27. ICMPv6TypeNeighborAdvertisement = 136
  28. ICMPv6TypeRedirect = 137
  29. // The following are from RFC 2710
  30. ICMPv6TypeMLDv1MulticastListenerQueryMessage = 130
  31. ICMPv6TypeMLDv1MulticastListenerReportMessage = 131
  32. ICMPv6TypeMLDv1MulticastListenerDoneMessage = 132
  33. // The following are from RFC 3810
  34. ICMPv6TypeMLDv2MulticastListenerReportMessageV2 = 143
  35. )
  36. const (
  37. // DestinationUnreachable
  38. ICMPv6CodeNoRouteToDst = 0
  39. ICMPv6CodeAdminProhibited = 1
  40. ICMPv6CodeBeyondScopeOfSrc = 2
  41. ICMPv6CodeAddressUnreachable = 3
  42. ICMPv6CodePortUnreachable = 4
  43. ICMPv6CodeSrcAddressFailedPolicy = 5
  44. ICMPv6CodeRejectRouteToDst = 6
  45. // TimeExceeded
  46. ICMPv6CodeHopLimitExceeded = 0
  47. ICMPv6CodeFragmentReassemblyTimeExceeded = 1
  48. // ParameterProblem
  49. ICMPv6CodeErroneousHeaderField = 0
  50. ICMPv6CodeUnrecognizedNextHeader = 1
  51. ICMPv6CodeUnrecognizedIPv6Option = 2
  52. )
  53. type icmpv6TypeCodeInfoStruct struct {
  54. typeStr string
  55. codeStr *map[uint8]string
  56. }
  57. var (
  58. icmpv6TypeCodeInfo = map[uint8]icmpv6TypeCodeInfoStruct{
  59. ICMPv6TypeDestinationUnreachable: icmpv6TypeCodeInfoStruct{
  60. "DestinationUnreachable", &map[uint8]string{
  61. ICMPv6CodeNoRouteToDst: "NoRouteToDst",
  62. ICMPv6CodeAdminProhibited: "AdminProhibited",
  63. ICMPv6CodeBeyondScopeOfSrc: "BeyondScopeOfSrc",
  64. ICMPv6CodeAddressUnreachable: "AddressUnreachable",
  65. ICMPv6CodePortUnreachable: "PortUnreachable",
  66. ICMPv6CodeSrcAddressFailedPolicy: "SrcAddressFailedPolicy",
  67. ICMPv6CodeRejectRouteToDst: "RejectRouteToDst",
  68. },
  69. },
  70. ICMPv6TypePacketTooBig: icmpv6TypeCodeInfoStruct{
  71. "PacketTooBig", nil,
  72. },
  73. ICMPv6TypeTimeExceeded: icmpv6TypeCodeInfoStruct{
  74. "TimeExceeded", &map[uint8]string{
  75. ICMPv6CodeHopLimitExceeded: "HopLimitExceeded",
  76. ICMPv6CodeFragmentReassemblyTimeExceeded: "FragmentReassemblyTimeExceeded",
  77. },
  78. },
  79. ICMPv6TypeParameterProblem: icmpv6TypeCodeInfoStruct{
  80. "ParameterProblem", &map[uint8]string{
  81. ICMPv6CodeErroneousHeaderField: "ErroneousHeaderField",
  82. ICMPv6CodeUnrecognizedNextHeader: "UnrecognizedNextHeader",
  83. ICMPv6CodeUnrecognizedIPv6Option: "UnrecognizedIPv6Option",
  84. },
  85. },
  86. ICMPv6TypeEchoRequest: icmpv6TypeCodeInfoStruct{
  87. "EchoRequest", nil,
  88. },
  89. ICMPv6TypeEchoReply: icmpv6TypeCodeInfoStruct{
  90. "EchoReply", nil,
  91. },
  92. ICMPv6TypeRouterSolicitation: icmpv6TypeCodeInfoStruct{
  93. "RouterSolicitation", nil,
  94. },
  95. ICMPv6TypeRouterAdvertisement: icmpv6TypeCodeInfoStruct{
  96. "RouterAdvertisement", nil,
  97. },
  98. ICMPv6TypeNeighborSolicitation: icmpv6TypeCodeInfoStruct{
  99. "NeighborSolicitation", nil,
  100. },
  101. ICMPv6TypeNeighborAdvertisement: icmpv6TypeCodeInfoStruct{
  102. "NeighborAdvertisement", nil,
  103. },
  104. ICMPv6TypeRedirect: icmpv6TypeCodeInfoStruct{
  105. "Redirect", nil,
  106. },
  107. }
  108. )
  109. type ICMPv6TypeCode uint16
  110. // Type returns the ICMPv6 type field.
  111. func (a ICMPv6TypeCode) Type() uint8 {
  112. return uint8(a >> 8)
  113. }
  114. // Code returns the ICMPv6 code field.
  115. func (a ICMPv6TypeCode) Code() uint8 {
  116. return uint8(a)
  117. }
  118. func (a ICMPv6TypeCode) String() string {
  119. t, c := a.Type(), a.Code()
  120. strInfo, ok := icmpv6TypeCodeInfo[t]
  121. if !ok {
  122. // Unknown ICMPv6 type field
  123. return fmt.Sprintf("%d(%d)", t, c)
  124. }
  125. typeStr := strInfo.typeStr
  126. if strInfo.codeStr == nil && c == 0 {
  127. // The ICMPv6 type does not make use of the code field
  128. return fmt.Sprintf("%s", strInfo.typeStr)
  129. }
  130. if strInfo.codeStr == nil && c != 0 {
  131. // The ICMPv6 type does not make use of the code field, but it is present anyway
  132. return fmt.Sprintf("%s(Code: %d)", typeStr, c)
  133. }
  134. codeStr, ok := (*strInfo.codeStr)[c]
  135. if !ok {
  136. // We don't know this ICMPv6 code; print the numerical value
  137. return fmt.Sprintf("%s(Code: %d)", typeStr, c)
  138. }
  139. return fmt.Sprintf("%s(%s)", typeStr, codeStr)
  140. }
  141. func (a ICMPv6TypeCode) GoString() string {
  142. t := reflect.TypeOf(a)
  143. return fmt.Sprintf("%s(%d, %d)", t.String(), a.Type(), a.Code())
  144. }
  145. // SerializeTo writes the ICMPv6TypeCode value to the 'bytes' buffer.
  146. func (a ICMPv6TypeCode) SerializeTo(bytes []byte) {
  147. binary.BigEndian.PutUint16(bytes, uint16(a))
  148. }
  149. // CreateICMPv6TypeCode is a convenience function to create an ICMPv6TypeCode
  150. // gopacket type from the ICMPv6 type and code values.
  151. func CreateICMPv6TypeCode(typ uint8, code uint8) ICMPv6TypeCode {
  152. return ICMPv6TypeCode(binary.BigEndian.Uint16([]byte{typ, code}))
  153. }
  154. // ICMPv6 is the layer for IPv6 ICMP packet data
  155. type ICMPv6 struct {
  156. BaseLayer
  157. TypeCode ICMPv6TypeCode
  158. Checksum uint16
  159. // TypeBytes is deprecated and always nil. See the different ICMPv6 message types
  160. // instead (e.g. ICMPv6TypeRouterSolicitation).
  161. TypeBytes []byte
  162. tcpipchecksum
  163. }
  164. // LayerType returns LayerTypeICMPv6.
  165. func (i *ICMPv6) LayerType() gopacket.LayerType { return LayerTypeICMPv6 }
  166. // DecodeFromBytes decodes the given bytes into this layer.
  167. func (i *ICMPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
  168. if len(data) < 4 {
  169. df.SetTruncated()
  170. return errors.New("ICMP layer less then 4 bytes for ICMPv6 packet")
  171. }
  172. i.TypeCode = CreateICMPv6TypeCode(data[0], data[1])
  173. i.Checksum = binary.BigEndian.Uint16(data[2:4])
  174. i.BaseLayer = BaseLayer{data[:4], data[4:]}
  175. return nil
  176. }
  177. // SerializeTo writes the serialized form of this layer into the
  178. // SerializationBuffer, implementing gopacket.SerializableLayer.
  179. // See the docs for gopacket.SerializableLayer for more info.
  180. func (i *ICMPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
  181. bytes, err := b.PrependBytes(4)
  182. if err != nil {
  183. return err
  184. }
  185. i.TypeCode.SerializeTo(bytes)
  186. if opts.ComputeChecksums {
  187. bytes[2] = 0
  188. bytes[3] = 0
  189. csum, err := i.computeChecksum(b.Bytes(), IPProtocolICMPv6)
  190. if err != nil {
  191. return err
  192. }
  193. i.Checksum = csum
  194. }
  195. binary.BigEndian.PutUint16(bytes[2:], i.Checksum)
  196. return nil
  197. }
  198. // CanDecode returns the set of layer types that this DecodingLayer can decode.
  199. func (i *ICMPv6) CanDecode() gopacket.LayerClass {
  200. return LayerTypeICMPv6
  201. }
  202. // NextLayerType returns the layer type contained by this DecodingLayer.
  203. func (i *ICMPv6) NextLayerType() gopacket.LayerType {
  204. switch i.TypeCode.Type() {
  205. case ICMPv6TypeEchoRequest:
  206. return LayerTypeICMPv6Echo
  207. case ICMPv6TypeEchoReply:
  208. return LayerTypeICMPv6Echo
  209. case ICMPv6TypeRouterSolicitation:
  210. return LayerTypeICMPv6RouterSolicitation
  211. case ICMPv6TypeRouterAdvertisement:
  212. return LayerTypeICMPv6RouterAdvertisement
  213. case ICMPv6TypeNeighborSolicitation:
  214. return LayerTypeICMPv6NeighborSolicitation
  215. case ICMPv6TypeNeighborAdvertisement:
  216. return LayerTypeICMPv6NeighborAdvertisement
  217. case ICMPv6TypeRedirect:
  218. return LayerTypeICMPv6Redirect
  219. case ICMPv6TypeMLDv1MulticastListenerQueryMessage: // Same Code for MLDv1 Query and MLDv2 Query
  220. if len(i.Payload) > 20 { // Only payload size differs
  221. return LayerTypeMLDv2MulticastListenerQuery
  222. } else {
  223. return LayerTypeMLDv1MulticastListenerQuery
  224. }
  225. case ICMPv6TypeMLDv1MulticastListenerDoneMessage:
  226. return LayerTypeMLDv1MulticastListenerDone
  227. case ICMPv6TypeMLDv1MulticastListenerReportMessage:
  228. return LayerTypeMLDv1MulticastListenerReport
  229. case ICMPv6TypeMLDv2MulticastListenerReportMessageV2:
  230. return LayerTypeMLDv2MulticastListenerReport
  231. }
  232. return gopacket.LayerTypePayload
  233. }
  234. func decodeICMPv6(data []byte, p gopacket.PacketBuilder) error {
  235. i := &ICMPv6{}
  236. return decodingLayerDecoder(i, data, p)
  237. }