dhcpv4.go 17 KB

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