dhcpv4.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. // Copyright 2016 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. "bytes"
  9. "encoding/binary"
  10. "fmt"
  11. "net"
  12. "github.com/google/gopacket"
  13. )
  14. // DHCPOp rerprents a bootp operation
  15. type DHCPOp byte
  16. // bootp operations
  17. const (
  18. DHCPOpRequest DHCPOp = 1
  19. DHCPOpReply DHCPOp = 2
  20. )
  21. // String returns a string version of a DHCPOp.
  22. func (o DHCPOp) String() string {
  23. switch o {
  24. case DHCPOpRequest:
  25. return "Request"
  26. case DHCPOpReply:
  27. return "Reply"
  28. default:
  29. return "Unknown"
  30. }
  31. }
  32. // DHCPMsgType represents a DHCP operation
  33. type DHCPMsgType byte
  34. // Constants that represent DHCP operations
  35. const (
  36. DHCPMsgTypeUnspecified DHCPMsgType = iota
  37. DHCPMsgTypeDiscover
  38. DHCPMsgTypeOffer
  39. DHCPMsgTypeRequest
  40. DHCPMsgTypeDecline
  41. DHCPMsgTypeAck
  42. DHCPMsgTypeNak
  43. DHCPMsgTypeRelease
  44. DHCPMsgTypeInform
  45. )
  46. // String returns a string version of a DHCPMsgType.
  47. func (o DHCPMsgType) String() string {
  48. switch o {
  49. case DHCPMsgTypeUnspecified:
  50. return "Unspecified"
  51. case DHCPMsgTypeDiscover:
  52. return "Discover"
  53. case DHCPMsgTypeOffer:
  54. return "Offer"
  55. case DHCPMsgTypeRequest:
  56. return "Request"
  57. case DHCPMsgTypeDecline:
  58. return "Decline"
  59. case DHCPMsgTypeAck:
  60. return "Ack"
  61. case DHCPMsgTypeNak:
  62. return "Nak"
  63. case DHCPMsgTypeRelease:
  64. return "Release"
  65. case DHCPMsgTypeInform:
  66. return "Inform"
  67. default:
  68. return "Unknown"
  69. }
  70. }
  71. //DHCPMagic is the RFC 2131 "magic cooke" for DHCP.
  72. var DHCPMagic uint32 = 0x63825363
  73. // DHCPv4 contains data for a single DHCP packet.
  74. type DHCPv4 struct {
  75. BaseLayer
  76. Operation DHCPOp
  77. HardwareType LinkType
  78. HardwareLen uint8
  79. HardwareOpts uint8
  80. Xid uint32
  81. Secs uint16
  82. Flags uint16
  83. ClientIP net.IP
  84. YourClientIP net.IP
  85. NextServerIP net.IP
  86. RelayAgentIP net.IP
  87. ClientHWAddr net.HardwareAddr
  88. ServerName []byte
  89. File []byte
  90. Options DHCPOptions
  91. }
  92. // DHCPOptions is used to get nicely printed option lists which would normally
  93. // be cut off after 5 options.
  94. type DHCPOptions []DHCPOption
  95. // String returns a string version of the options list.
  96. func (o DHCPOptions) String() string {
  97. buf := &bytes.Buffer{}
  98. buf.WriteByte('[')
  99. for i, opt := range o {
  100. buf.WriteString(opt.String())
  101. if i+1 != len(o) {
  102. buf.WriteString(", ")
  103. }
  104. }
  105. buf.WriteByte(']')
  106. return buf.String()
  107. }
  108. // LayerType returns gopacket.LayerTypeDHCPv4
  109. func (d *DHCPv4) LayerType() gopacket.LayerType { return LayerTypeDHCPv4 }
  110. // DecodeFromBytes decodes the given bytes into this layer.
  111. func (d *DHCPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
  112. d.Options = d.Options[:0]
  113. d.Operation = DHCPOp(data[0])
  114. d.HardwareType = LinkType(data[1])
  115. d.HardwareLen = data[2]
  116. d.HardwareOpts = data[3]
  117. d.Xid = binary.BigEndian.Uint32(data[4:8])
  118. d.Secs = binary.BigEndian.Uint16(data[8:10])
  119. d.Flags = binary.BigEndian.Uint16(data[10:12])
  120. d.ClientIP = net.IP(data[12:16])
  121. d.YourClientIP = net.IP(data[16:20])
  122. d.NextServerIP = net.IP(data[20:24])
  123. d.RelayAgentIP = net.IP(data[24:28])
  124. d.ClientHWAddr = net.HardwareAddr(data[28 : 28+d.HardwareLen])
  125. d.ServerName = data[44:108]
  126. d.File = data[108:236]
  127. if binary.BigEndian.Uint32(data[236:240]) != DHCPMagic {
  128. return InvalidMagicCookie
  129. }
  130. if len(data) <= 240 {
  131. // DHCP Packet could have no option (??)
  132. return nil
  133. }
  134. options := data[240:]
  135. stop := len(options)
  136. start := 0
  137. for start < stop {
  138. o := DHCPOption{}
  139. if err := o.decode(options[start:]); err != nil {
  140. return err
  141. }
  142. if o.Type == DHCPOptEnd {
  143. break
  144. }
  145. d.Options = append(d.Options, o)
  146. // Check if the option is a single byte pad
  147. if o.Type == DHCPOptPad {
  148. start++
  149. } else {
  150. start += int(o.Length) + 2
  151. }
  152. }
  153. return nil
  154. }
  155. // Len returns the length of a DHCPv4 packet.
  156. func (d *DHCPv4) Len() uint16 {
  157. n := uint16(240)
  158. for _, o := range d.Options {
  159. if o.Type == DHCPOptPad {
  160. n++
  161. } else {
  162. n += uint16(o.Length) + 2
  163. }
  164. }
  165. n++ // for opt end
  166. return n
  167. }
  168. // SerializeTo writes the serialized form of this layer into the
  169. // SerializationBuffer, implementing gopacket.SerializableLayer.
  170. // See the docs for gopacket.SerializableLayer for more info.
  171. func (d *DHCPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
  172. plen := int(d.Len())
  173. data, err := b.PrependBytes(plen)
  174. if err != nil {
  175. return err
  176. }
  177. data[0] = byte(d.Operation)
  178. data[1] = byte(d.HardwareType)
  179. if opts.FixLengths {
  180. d.HardwareLen = uint8(len(d.ClientHWAddr))
  181. }
  182. data[2] = d.HardwareLen
  183. data[3] = d.HardwareOpts
  184. binary.BigEndian.PutUint32(data[4:8], d.Xid)
  185. binary.BigEndian.PutUint16(data[8:10], d.Secs)
  186. binary.BigEndian.PutUint16(data[10:12], d.Flags)
  187. copy(data[12:16], d.ClientIP.To4())
  188. copy(data[16:20], d.YourClientIP.To4())
  189. copy(data[20:24], d.NextServerIP.To4())
  190. copy(data[24:28], d.RelayAgentIP.To4())
  191. copy(data[28:44], d.ClientHWAddr)
  192. copy(data[44:108], d.ServerName)
  193. copy(data[108:236], d.File)
  194. binary.BigEndian.PutUint32(data[236:240], DHCPMagic)
  195. if len(d.Options) > 0 {
  196. offset := 240
  197. for _, o := range d.Options {
  198. if err := o.encode(data[offset:]); err != nil {
  199. return err
  200. }
  201. // A pad option is only a single byte
  202. if o.Type == DHCPOptPad {
  203. offset++
  204. } else {
  205. offset += 2 + len(o.Data)
  206. }
  207. }
  208. optend := NewDHCPOption(DHCPOptEnd, nil)
  209. if err := optend.encode(data[offset:]); err != nil {
  210. return err
  211. }
  212. }
  213. return nil
  214. }
  215. // CanDecode returns the set of layer types that this DecodingLayer can decode.
  216. func (d *DHCPv4) CanDecode() gopacket.LayerClass {
  217. return LayerTypeDHCPv4
  218. }
  219. // NextLayerType returns the layer type contained by this DecodingLayer.
  220. func (d *DHCPv4) NextLayerType() gopacket.LayerType {
  221. return gopacket.LayerTypePayload
  222. }
  223. func decodeDHCPv4(data []byte, p gopacket.PacketBuilder) error {
  224. dhcp := &DHCPv4{}
  225. err := dhcp.DecodeFromBytes(data, p)
  226. if err != nil {
  227. return err
  228. }
  229. p.AddLayer(dhcp)
  230. return p.NextDecoder(gopacket.LayerTypePayload)
  231. }
  232. // DHCPOpt represents a DHCP option or parameter from RFC-2132
  233. type DHCPOpt byte
  234. // Constants for the DHCPOpt options.
  235. const (
  236. DHCPOptPad DHCPOpt = 0
  237. DHCPOptSubnetMask DHCPOpt = 1 // 4, net.IP
  238. DHCPOptTimeOffset DHCPOpt = 2 // 4, int32 (signed seconds from UTC)
  239. DHCPOptRouter DHCPOpt = 3 // n*4, [n]net.IP
  240. DHCPOptTimeServer DHCPOpt = 4 // n*4, [n]net.IP
  241. DHCPOptNameServer DHCPOpt = 5 // n*4, [n]net.IP
  242. DHCPOptDNS DHCPOpt = 6 // n*4, [n]net.IP
  243. DHCPOptLogServer DHCPOpt = 7 // n*4, [n]net.IP
  244. DHCPOptCookieServer DHCPOpt = 8 // n*4, [n]net.IP
  245. DHCPOptLPRServer DHCPOpt = 9 // n*4, [n]net.IP
  246. DHCPOptImpressServer DHCPOpt = 10 // n*4, [n]net.IP
  247. DHCPOptResLocServer DHCPOpt = 11 // n*4, [n]net.IP
  248. DHCPOptHostname DHCPOpt = 12 // n, string
  249. DHCPOptBootfileSize DHCPOpt = 13 // 2, uint16
  250. DHCPOptMeritDumpFile DHCPOpt = 14 // >1, string
  251. DHCPOptDomainName DHCPOpt = 15 // n, string
  252. DHCPOptSwapServer DHCPOpt = 16 // n*4, [n]net.IP
  253. DHCPOptRootPath DHCPOpt = 17 // n, string
  254. DHCPOptExtensionsPath DHCPOpt = 18 // n, string
  255. DHCPOptIPForwarding DHCPOpt = 19 // 1, bool
  256. DHCPOptSourceRouting DHCPOpt = 20 // 1, bool
  257. DHCPOptPolicyFilter DHCPOpt = 21 // 8*n, [n]{net.IP/net.IP}
  258. DHCPOptDatagramMTU DHCPOpt = 22 // 2, uint16
  259. DHCPOptDefaultTTL DHCPOpt = 23 // 1, byte
  260. DHCPOptPathMTUAgingTimeout DHCPOpt = 24 // 4, uint32
  261. DHCPOptPathPlateuTableOption DHCPOpt = 25 // 2*n, []uint16
  262. DHCPOptInterfaceMTU DHCPOpt = 26 // 2, uint16
  263. DHCPOptAllSubsLocal DHCPOpt = 27 // 1, bool
  264. DHCPOptBroadcastAddr DHCPOpt = 28 // 4, net.IP
  265. DHCPOptMaskDiscovery DHCPOpt = 29 // 1, bool
  266. DHCPOptMaskSupplier DHCPOpt = 30 // 1, bool
  267. DHCPOptRouterDiscovery DHCPOpt = 31 // 1, bool
  268. DHCPOptSolicitAddr DHCPOpt = 32 // 4, net.IP
  269. DHCPOptStaticRoute DHCPOpt = 33 // n*8, [n]{net.IP/net.IP} -- note the 2nd is router not mask
  270. DHCPOptARPTrailers DHCPOpt = 34 // 1, bool
  271. DHCPOptARPTimeout DHCPOpt = 35 // 4, uint32
  272. DHCPOptEthernetEncap DHCPOpt = 36 // 1, bool
  273. DHCPOptTCPTTL DHCPOpt = 37 // 1, byte
  274. DHCPOptTCPKeepAliveInt DHCPOpt = 38 // 4, uint32
  275. DHCPOptTCPKeepAliveGarbage DHCPOpt = 39 // 1, bool
  276. DHCPOptNISDomain DHCPOpt = 40 // n, string
  277. DHCPOptNISServers DHCPOpt = 41 // 4*n, [n]net.IP
  278. DHCPOptNTPServers DHCPOpt = 42 // 4*n, [n]net.IP
  279. DHCPOptVendorOption DHCPOpt = 43 // n, [n]byte // may be encapsulated.
  280. DHCPOptNetBIOSTCPNS DHCPOpt = 44 // 4*n, [n]net.IP
  281. DHCPOptNetBIOSTCPDDS DHCPOpt = 45 // 4*n, [n]net.IP
  282. DHCPOptNETBIOSTCPNodeType DHCPOpt = 46 // 1, magic byte
  283. DHCPOptNetBIOSTCPScope DHCPOpt = 47 // n, string
  284. DHCPOptXFontServer DHCPOpt = 48 // n, string
  285. DHCPOptXDisplayManager DHCPOpt = 49 // n, string
  286. DHCPOptRequestIP DHCPOpt = 50 // 4, net.IP
  287. DHCPOptLeaseTime DHCPOpt = 51 // 4, uint32
  288. DHCPOptExtOptions DHCPOpt = 52 // 1, 1/2/3
  289. DHCPOptMessageType DHCPOpt = 53 // 1, 1-7
  290. DHCPOptServerID DHCPOpt = 54 // 4, net.IP
  291. DHCPOptParamsRequest DHCPOpt = 55 // n, []byte
  292. DHCPOptMessage DHCPOpt = 56 // n, 3
  293. DHCPOptMaxMessageSize DHCPOpt = 57 // 2, uint16
  294. DHCPOptT1 DHCPOpt = 58 // 4, uint32
  295. DHCPOptT2 DHCPOpt = 59 // 4, uint32
  296. DHCPOptClassID DHCPOpt = 60 // n, []byte
  297. DHCPOptClientID DHCPOpt = 61 // n >= 2, []byte
  298. DHCPOptDomainSearch DHCPOpt = 119 // n, string
  299. DHCPOptSIPServers DHCPOpt = 120 // n, url
  300. DHCPOptClasslessStaticRoute DHCPOpt = 121 //
  301. DHCPOptEnd DHCPOpt = 255
  302. )
  303. // String returns a string version of a DHCPOpt.
  304. func (o DHCPOpt) String() string {
  305. switch o {
  306. case DHCPOptPad:
  307. return "(padding)"
  308. case DHCPOptSubnetMask:
  309. return "SubnetMask"
  310. case DHCPOptTimeOffset:
  311. return "TimeOffset"
  312. case DHCPOptRouter:
  313. return "Router"
  314. case DHCPOptTimeServer:
  315. return "rfc868" // old time server protocol stringified to dissuade confusion w. NTP
  316. case DHCPOptNameServer:
  317. return "ien116" // obscure nameserver protocol stringified to dissuade confusion w. DNS
  318. case DHCPOptDNS:
  319. return "DNS"
  320. case DHCPOptLogServer:
  321. return "mitLCS" // MIT LCS server protocol yada yada w. Syslog
  322. case DHCPOptCookieServer:
  323. return "CookieServer"
  324. case DHCPOptLPRServer:
  325. return "LPRServer"
  326. case DHCPOptImpressServer:
  327. return "ImpressServer"
  328. case DHCPOptResLocServer:
  329. return "ResourceLocationServer"
  330. case DHCPOptHostname:
  331. return "Hostname"
  332. case DHCPOptBootfileSize:
  333. return "BootfileSize"
  334. case DHCPOptMeritDumpFile:
  335. return "MeritDumpFile"
  336. case DHCPOptDomainName:
  337. return "DomainName"
  338. case DHCPOptSwapServer:
  339. return "SwapServer"
  340. case DHCPOptRootPath:
  341. return "RootPath"
  342. case DHCPOptExtensionsPath:
  343. return "ExtensionsPath"
  344. case DHCPOptIPForwarding:
  345. return "IPForwarding"
  346. case DHCPOptSourceRouting:
  347. return "SourceRouting"
  348. case DHCPOptPolicyFilter:
  349. return "PolicyFilter"
  350. case DHCPOptDatagramMTU:
  351. return "DatagramMTU"
  352. case DHCPOptDefaultTTL:
  353. return "DefaultTTL"
  354. case DHCPOptPathMTUAgingTimeout:
  355. return "PathMTUAgingTimeout"
  356. case DHCPOptPathPlateuTableOption:
  357. return "PathPlateuTableOption"
  358. case DHCPOptInterfaceMTU:
  359. return "InterfaceMTU"
  360. case DHCPOptAllSubsLocal:
  361. return "AllSubsLocal"
  362. case DHCPOptBroadcastAddr:
  363. return "BroadcastAddress"
  364. case DHCPOptMaskDiscovery:
  365. return "MaskDiscovery"
  366. case DHCPOptMaskSupplier:
  367. return "MaskSupplier"
  368. case DHCPOptRouterDiscovery:
  369. return "RouterDiscovery"
  370. case DHCPOptSolicitAddr:
  371. return "SolicitAddr"
  372. case DHCPOptStaticRoute:
  373. return "StaticRoute"
  374. case DHCPOptARPTrailers:
  375. return "ARPTrailers"
  376. case DHCPOptARPTimeout:
  377. return "ARPTimeout"
  378. case DHCPOptEthernetEncap:
  379. return "EthernetEncap"
  380. case DHCPOptTCPTTL:
  381. return "TCPTTL"
  382. case DHCPOptTCPKeepAliveInt:
  383. return "TCPKeepAliveInt"
  384. case DHCPOptTCPKeepAliveGarbage:
  385. return "TCPKeepAliveGarbage"
  386. case DHCPOptNISDomain:
  387. return "NISDomain"
  388. case DHCPOptNISServers:
  389. return "NISServers"
  390. case DHCPOptNTPServers:
  391. return "NTPServers"
  392. case DHCPOptVendorOption:
  393. return "VendorOption"
  394. case DHCPOptNetBIOSTCPNS:
  395. return "NetBIOSOverTCPNS"
  396. case DHCPOptNetBIOSTCPDDS:
  397. return "NetBiosOverTCPDDS"
  398. case DHCPOptNETBIOSTCPNodeType:
  399. return "NetBIOSOverTCPNodeType"
  400. case DHCPOptNetBIOSTCPScope:
  401. return "NetBIOSOverTCPScope"
  402. case DHCPOptXFontServer:
  403. return "XFontServer"
  404. case DHCPOptXDisplayManager:
  405. return "XDisplayManager"
  406. case DHCPOptEnd:
  407. return "(end)"
  408. case DHCPOptSIPServers:
  409. return "SipServers"
  410. case DHCPOptRequestIP:
  411. return "RequestIP"
  412. case DHCPOptLeaseTime:
  413. return "LeaseTime"
  414. case DHCPOptExtOptions:
  415. return "ExtOpts"
  416. case DHCPOptMessageType:
  417. return "MessageType"
  418. case DHCPOptServerID:
  419. return "ServerID"
  420. case DHCPOptParamsRequest:
  421. return "ParamsRequest"
  422. case DHCPOptMessage:
  423. return "Message"
  424. case DHCPOptMaxMessageSize:
  425. return "MaxDHCPSize"
  426. case DHCPOptT1:
  427. return "Timer1"
  428. case DHCPOptT2:
  429. return "Timer2"
  430. case DHCPOptClassID:
  431. return "ClassID"
  432. case DHCPOptClientID:
  433. return "ClientID"
  434. case DHCPOptDomainSearch:
  435. return "DomainSearch"
  436. case DHCPOptClasslessStaticRoute:
  437. return "ClasslessStaticRoute"
  438. default:
  439. return "Unknown"
  440. }
  441. }
  442. // DHCPOption rerpresents a DHCP option.
  443. type DHCPOption struct {
  444. Type DHCPOpt
  445. Length uint8
  446. Data []byte
  447. }
  448. // String returns a string version of a DHCP Option.
  449. func (o DHCPOption) String() string {
  450. switch o.Type {
  451. case DHCPOptHostname, DHCPOptMeritDumpFile, DHCPOptDomainName, DHCPOptRootPath,
  452. DHCPOptExtensionsPath, DHCPOptNISDomain, DHCPOptNetBIOSTCPScope, DHCPOptXFontServer,
  453. DHCPOptXDisplayManager, DHCPOptMessage, DHCPOptDomainSearch: // string
  454. return fmt.Sprintf("Option(%s:%s)", o.Type, string(o.Data))
  455. case DHCPOptMessageType:
  456. if len(o.Data) != 1 {
  457. return fmt.Sprintf("Option(%s:INVALID)", o.Type)
  458. }
  459. return fmt.Sprintf("Option(%s:%s)", o.Type, DHCPMsgType(o.Data[0]))
  460. case DHCPOptSubnetMask, DHCPOptServerID, DHCPOptBroadcastAddr,
  461. DHCPOptSolicitAddr, DHCPOptRequestIP: // net.IP
  462. if len(o.Data) < 4 {
  463. return fmt.Sprintf("Option(%s:INVALID)", o.Type)
  464. }
  465. return fmt.Sprintf("Option(%s:%s)", o.Type, net.IP(o.Data))
  466. case DHCPOptT1, DHCPOptT2, DHCPOptLeaseTime, DHCPOptPathMTUAgingTimeout,
  467. DHCPOptARPTimeout, DHCPOptTCPKeepAliveInt: // uint32
  468. if len(o.Data) != 4 {
  469. return fmt.Sprintf("Option(%s:INVALID)", o.Type)
  470. }
  471. return fmt.Sprintf("Option(%s:%d)", o.Type,
  472. uint32(o.Data[0])<<24|uint32(o.Data[1])<<16|uint32(o.Data[2])<<8|uint32(o.Data[3]))
  473. case DHCPOptParamsRequest:
  474. buf := &bytes.Buffer{}
  475. buf.WriteString(fmt.Sprintf("Option(%s:", o.Type))
  476. for i, v := range o.Data {
  477. buf.WriteString(DHCPOpt(v).String())
  478. if i+1 != len(o.Data) {
  479. buf.WriteByte(',')
  480. }
  481. }
  482. buf.WriteString(")")
  483. return buf.String()
  484. default:
  485. return fmt.Sprintf("Option(%s:%v)", o.Type, o.Data)
  486. }
  487. }
  488. // NewDHCPOption constructs a new DHCPOption with a given type and data.
  489. func NewDHCPOption(t DHCPOpt, data []byte) DHCPOption {
  490. o := DHCPOption{Type: t}
  491. if data != nil {
  492. o.Data = data
  493. o.Length = uint8(len(data))
  494. }
  495. return o
  496. }
  497. func (o *DHCPOption) encode(b []byte) error {
  498. switch o.Type {
  499. case DHCPOptPad, DHCPOptEnd:
  500. b[0] = byte(o.Type)
  501. default:
  502. b[0] = byte(o.Type)
  503. b[1] = o.Length
  504. copy(b[2:], o.Data)
  505. }
  506. return nil
  507. }
  508. func (o *DHCPOption) decode(data []byte) error {
  509. if len(data) < 1 {
  510. // Pad/End have a length of 1
  511. return DecOptionNotEnoughData
  512. }
  513. o.Type = DHCPOpt(data[0])
  514. switch o.Type {
  515. case DHCPOptPad, DHCPOptEnd:
  516. o.Data = nil
  517. default:
  518. if len(data) < 2 {
  519. return DecOptionNotEnoughData
  520. }
  521. o.Length = data[1]
  522. if int(o.Length) > len(data[2:]) {
  523. return DecOptionMalformed
  524. }
  525. o.Data = data[2 : 2+int(o.Length)]
  526. }
  527. return nil
  528. }
  529. // DHCPv4Error is used for constant errors for DHCPv4. It is needed for test asserts.
  530. type DHCPv4Error string
  531. // DHCPv4Error implements error interface.
  532. func (d DHCPv4Error) Error() string {
  533. return string(d)
  534. }
  535. const (
  536. // DecOptionNotEnoughData is returned when there is not enough data during option's decode process
  537. DecOptionNotEnoughData = DHCPv4Error("Not enough data to decode")
  538. // DecOptionMalformed is returned when the option is malformed
  539. DecOptionMalformed = DHCPv4Error("Option is malformed")
  540. // InvalidMagicCookie is returned when Magic cookie is missing into BOOTP header
  541. InvalidMagicCookie = DHCPv4Error("Bad DHCP header")
  542. )