dhcpv4.go 16 KB

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