dhcpv6.go 8.9 KB

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