dhcpv6.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. // Copyright 2018 Google, Inc. All rights reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license
  4. // that can be found in the LICENSE file in the root of the source
  5. // tree.
  6. package layers
  7. import (
  8. "encoding/binary"
  9. "errors"
  10. "fmt"
  11. "net"
  12. "github.com/google/gopacket"
  13. )
  14. // DHCPv6MsgType represents a DHCPv6 operation
  15. type DHCPv6MsgType byte
  16. // Constants that represent DHCP operations
  17. const (
  18. DHCPv6MsgTypeUnspecified DHCPv6MsgType = iota
  19. DHCPv6MsgTypeSolicit
  20. DHCPv6MsgTypeAdverstise
  21. DHCPv6MsgTypeRequest
  22. DHCPv6MsgTypeConfirm
  23. DHCPv6MsgTypeRenew
  24. DHCPv6MsgTypeRebind
  25. DHCPv6MsgTypeReply
  26. DHCPv6MsgTypeRelease
  27. DHCPv6MsgTypeDecline
  28. DHCPv6MsgTypeReconfigure
  29. DHCPv6MsgTypeInformationRequest
  30. DHCPv6MsgTypeRelayForward
  31. DHCPv6MsgTypeRelayReply
  32. )
  33. // String returns a string version of a DHCPv6MsgType.
  34. func (o DHCPv6MsgType) String() string {
  35. switch o {
  36. case DHCPv6MsgTypeUnspecified:
  37. return "Unspecified"
  38. case DHCPv6MsgTypeSolicit:
  39. return "Solicit"
  40. case DHCPv6MsgTypeAdverstise:
  41. return "Adverstise"
  42. case DHCPv6MsgTypeRequest:
  43. return "Request"
  44. case DHCPv6MsgTypeConfirm:
  45. return "Confirm"
  46. case DHCPv6MsgTypeRenew:
  47. return "Renew"
  48. case DHCPv6MsgTypeRebind:
  49. return "Rebind"
  50. case DHCPv6MsgTypeReply:
  51. return "Reply"
  52. case DHCPv6MsgTypeRelease:
  53. return "Release"
  54. case DHCPv6MsgTypeDecline:
  55. return "Decline"
  56. case DHCPv6MsgTypeReconfigure:
  57. return "Reconfigure"
  58. case DHCPv6MsgTypeInformationRequest:
  59. return "InformationRequest"
  60. case DHCPv6MsgTypeRelayForward:
  61. return "RelayForward"
  62. case DHCPv6MsgTypeRelayReply:
  63. return "RelayReply"
  64. default:
  65. return "Unknown"
  66. }
  67. }
  68. // DHCPv6 contains data for a single DHCP packet.
  69. type DHCPv6 struct {
  70. BaseLayer
  71. MsgType DHCPv6MsgType
  72. HopCount uint8
  73. LinkAddr net.IP
  74. PeerAddr net.IP
  75. TransactionID []byte
  76. Options DHCPv6Options
  77. }
  78. // LayerType returns gopacket.LayerTypeDHCPv6
  79. func (d *DHCPv6) LayerType() gopacket.LayerType { return LayerTypeDHCPv6 }
  80. // DecodeFromBytes decodes the given bytes into this layer.
  81. func (d *DHCPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
  82. d.BaseLayer = BaseLayer{Contents: data}
  83. d.Options = d.Options[:0]
  84. d.MsgType = DHCPv6MsgType(data[0])
  85. offset := 0
  86. if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
  87. d.HopCount = data[1]
  88. d.LinkAddr = net.IP(data[2:18])
  89. d.PeerAddr = net.IP(data[18:34])
  90. offset = 34
  91. } else {
  92. d.TransactionID = data[1:4]
  93. offset = 4
  94. }
  95. stop := len(data)
  96. for offset < stop {
  97. o := DHCPv6Option{}
  98. if err := o.decode(data[offset:]); err != nil {
  99. return err
  100. }
  101. d.Options = append(d.Options, o)
  102. offset += int(o.Length) + 4 // 2 from option code, 2 from option length
  103. }
  104. return nil
  105. }
  106. // Len returns the length of a DHCPv6 packet.
  107. func (d *DHCPv6) Len() int {
  108. n := 1
  109. if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
  110. n += 33
  111. } else {
  112. n += 3
  113. }
  114. for _, o := range d.Options {
  115. n += int(o.Length) + 4 // 2 from option code, 2 from option length
  116. }
  117. return n
  118. }
  119. // SerializeTo writes the serialized form of this layer into the
  120. // SerializationBuffer, implementing gopacket.SerializableLayer.
  121. // See the docs for gopacket.SerializableLayer for more info.
  122. func (d *DHCPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
  123. plen := int(d.Len())
  124. data, err := b.PrependBytes(plen)
  125. if err != nil {
  126. return err
  127. }
  128. offset := 0
  129. data[0] = byte(d.MsgType)
  130. if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
  131. data[1] = byte(d.HopCount)
  132. copy(data[2:18], d.LinkAddr.To16())
  133. copy(data[18:34], d.PeerAddr.To16())
  134. offset = 34
  135. } else {
  136. copy(data[1:4], d.TransactionID)
  137. offset = 4
  138. }
  139. if len(d.Options) > 0 {
  140. for _, o := range d.Options {
  141. if err := o.encode(data[offset:], opts); err != nil {
  142. return err
  143. }
  144. offset += int(o.Length) + 4 // 2 from option code, 2 from option length
  145. }
  146. }
  147. return nil
  148. }
  149. // CanDecode returns the set of layer types that this DecodingLayer can decode.
  150. func (d *DHCPv6) CanDecode() gopacket.LayerClass {
  151. return LayerTypeDHCPv6
  152. }
  153. // NextLayerType returns the layer type contained by this DecodingLayer.
  154. func (d *DHCPv6) NextLayerType() gopacket.LayerType {
  155. return gopacket.LayerTypePayload
  156. }
  157. func decodeDHCPv6(data []byte, p gopacket.PacketBuilder) error {
  158. dhcp := &DHCPv6{}
  159. err := dhcp.DecodeFromBytes(data, p)
  160. if err != nil {
  161. return err
  162. }
  163. p.AddLayer(dhcp)
  164. return p.NextDecoder(gopacket.LayerTypePayload)
  165. }
  166. // DHCPv6StatusCode represents a DHCP status code - RFC-3315
  167. type DHCPv6StatusCode uint16
  168. // Constants for the DHCPv6StatusCode.
  169. const (
  170. DHCPv6StatusCodeSuccess DHCPv6StatusCode = iota
  171. DHCPv6StatusCodeUnspecFail
  172. DHCPv6StatusCodeNoAddrsAvail
  173. DHCPv6StatusCodeNoBinding
  174. DHCPv6StatusCodeNotOnLink
  175. DHCPv6StatusCodeUseMulticast
  176. )
  177. // String returns a string version of a DHCPv6StatusCode.
  178. func (o DHCPv6StatusCode) String() string {
  179. switch o {
  180. case DHCPv6StatusCodeSuccess:
  181. return "Success"
  182. case DHCPv6StatusCodeUnspecFail:
  183. return "UnspecifiedFailure"
  184. case DHCPv6StatusCodeNoAddrsAvail:
  185. return "NoAddressAvailable"
  186. case DHCPv6StatusCodeNoBinding:
  187. return "NoBinding"
  188. case DHCPv6StatusCodeNotOnLink:
  189. return "NotOnLink"
  190. case DHCPv6StatusCodeUseMulticast:
  191. return "UseMulticast"
  192. default:
  193. return "Unknown"
  194. }
  195. }
  196. // DHCPv6DUIDType represents a DHCP DUID - RFC-3315
  197. type DHCPv6DUIDType uint16
  198. // Constants for the DHCPv6DUIDType.
  199. const (
  200. DHCPv6DUIDTypeLLT DHCPv6DUIDType = iota + 1
  201. DHCPv6DUIDTypeEN
  202. DHCPv6DUIDTypeLL
  203. )
  204. // String returns a string version of a DHCPv6DUIDType.
  205. func (o DHCPv6DUIDType) String() string {
  206. switch o {
  207. case DHCPv6DUIDTypeLLT:
  208. return "LLT"
  209. case DHCPv6DUIDTypeEN:
  210. return "EN"
  211. case DHCPv6DUIDTypeLL:
  212. return "LL"
  213. default:
  214. return "Unknown"
  215. }
  216. }
  217. // DHCPv6DUID means DHCP Unique Identifier as stated in RFC 3315, section 9 (https://tools.ietf.org/html/rfc3315#page-19)
  218. type DHCPv6DUID struct {
  219. Type DHCPv6DUIDType
  220. // LLT, LL
  221. HardwareType []byte
  222. // EN
  223. EnterpriseNumber []byte
  224. // LLT
  225. Time []byte
  226. // LLT, LL
  227. LinkLayerAddress net.HardwareAddr
  228. // EN
  229. Identifier []byte
  230. }
  231. // DecodeFromBytes decodes the given bytes into a DHCPv6DUID
  232. func (d *DHCPv6DUID) DecodeFromBytes(data []byte) error {
  233. if len(data) < 2 {
  234. return errors.New("Not enough bytes to decode: " + string(len(data)))
  235. }
  236. d.Type = DHCPv6DUIDType(binary.BigEndian.Uint16(data[:2]))
  237. if d.Type == DHCPv6DUIDTypeLLT || d.Type == DHCPv6DUIDTypeLL {
  238. d.HardwareType = data[2:4]
  239. }
  240. if d.Type == DHCPv6DUIDTypeLLT {
  241. d.Time = data[4:8]
  242. d.LinkLayerAddress = net.HardwareAddr(data[8:])
  243. } else if d.Type == DHCPv6DUIDTypeEN {
  244. d.EnterpriseNumber = data[2:6]
  245. d.Identifier = data[6:]
  246. } else { // DHCPv6DUIDTypeLL
  247. d.LinkLayerAddress = net.HardwareAddr(data[4:])
  248. }
  249. return nil
  250. }
  251. // Encode encodes the DHCPv6DUID in a slice of bytes
  252. func (d *DHCPv6DUID) Encode() []byte {
  253. length := d.Len()
  254. data := make([]byte, length)
  255. binary.BigEndian.PutUint16(data[0:2], uint16(d.Type))
  256. if d.Type == DHCPv6DUIDTypeLLT || d.Type == DHCPv6DUIDTypeLL {
  257. copy(data[2:4], d.HardwareType)
  258. }
  259. if d.Type == DHCPv6DUIDTypeLLT {
  260. copy(data[4:8], d.Time)
  261. copy(data[8:], d.LinkLayerAddress)
  262. } else if d.Type == DHCPv6DUIDTypeEN {
  263. copy(data[2:6], d.EnterpriseNumber)
  264. copy(data[6:], d.Identifier)
  265. } else {
  266. copy(data[4:], d.LinkLayerAddress)
  267. }
  268. return data
  269. }
  270. // Len returns the length of the DHCPv6DUID, respecting the type
  271. func (d *DHCPv6DUID) Len() int {
  272. length := 2 // d.Type
  273. if d.Type == DHCPv6DUIDTypeLLT {
  274. length += 2 /*HardwareType*/ + 4 /*d.Time*/ + len(d.LinkLayerAddress)
  275. } else if d.Type == DHCPv6DUIDTypeEN {
  276. length += 4 /*d.EnterpriseNumber*/ + len(d.Identifier)
  277. } else { // LL
  278. length += 2 /*d.HardwareType*/ + len(d.LinkLayerAddress)
  279. }
  280. return length
  281. }
  282. func (d *DHCPv6DUID) String() string {
  283. duid := "Type: " + d.Type.String() + ", "
  284. if d.Type == DHCPv6DUIDTypeLLT {
  285. duid += fmt.Sprintf("HardwareType: %v, Time: %v, LinkLayerAddress: %v", d.HardwareType, d.Time, d.LinkLayerAddress)
  286. } else if d.Type == DHCPv6DUIDTypeEN {
  287. duid += fmt.Sprintf("EnterpriseNumber: %v, Identifier: %v", d.EnterpriseNumber, d.Identifier)
  288. } else { // DHCPv6DUIDTypeLL
  289. duid += fmt.Sprintf("HardwareType: %v, LinkLayerAddress: %v", d.HardwareType, d.LinkLayerAddress)
  290. }
  291. return duid
  292. }
  293. func decodeDHCPv6DUID(data []byte) (*DHCPv6DUID, error) {
  294. duid := &DHCPv6DUID{}
  295. err := duid.DecodeFromBytes(data)
  296. if err != nil {
  297. return nil, err
  298. }
  299. return duid, nil
  300. }