VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/Dhcpd/DhcpOptions.h@ 79563

Last change on this file since 79563 was 79563, checked in by vboxsync, 5 years ago

Dhcpd: Went over the Dhcpd and related code adding comments and doing some exception vetting. bugref:9288

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.1 KB
Line 
1/* $Id: DhcpOptions.h 79563 2019-07-06 01:22:56Z vboxsync $ */
2/** @file
3 * DHCP server - DHCP options
4 */
5
6/*
7 * Copyright (C) 2017-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef VBOX_INCLUDED_SRC_Dhcpd_DhcpOptions_h
19#define VBOX_INCLUDED_SRC_Dhcpd_DhcpOptions_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24#include "DhcpdInternal.h"
25
26#include <iprt/asm.h>
27#include <iprt/err.h>
28#include <iprt/net.h>
29#include <iprt/string.h>
30#include <iprt/cpp/ministring.h>
31
32
33class DhcpClientMessage;
34
35
36class DhcpOption
37{
38 protected:
39 uint8_t m_OptCode;
40 bool m_fPresent;
41
42 public:
43 explicit DhcpOption(uint8_t aOptCode)
44 : m_OptCode(aOptCode), m_fPresent(true) {}
45
46 DhcpOption(uint8_t aOptCode, bool fPresent)
47 : m_OptCode(aOptCode), m_fPresent(fPresent) {}
48
49 virtual DhcpOption *clone() const = 0;
50
51 virtual ~DhcpOption() {}
52
53 public:
54 static DhcpOption *parse(uint8_t aOptCode, int aEnc, const char *pcszValue);
55
56 public:
57 uint8_t optcode() const RT_NOEXCEPT { return m_OptCode; }
58 bool present() const RT_NOEXCEPT { return m_fPresent; }
59
60 public:
61 int encode(octets_t &dst) const;
62
63 int decode(const rawopts_t &map);
64 int decode(const DhcpClientMessage &req);
65
66 protected:
67 virtual ssize_t encodeValue(octets_t &dst) const = 0;
68 virtual int decodeValue(const octets_t &src, size_t cb) = 0;
69
70 protected:
71 static const octets_t *findOption(const rawopts_t &aOptMap, uint8_t aOptCode);
72
73 protected:
74 /*
75 * Serialization
76 */
77 static void append(octets_t &aDst, uint8_t aValue)
78 {
79 aDst.push_back(aValue);
80 }
81
82 static void append(octets_t &aDst, uint16_t aValue)
83 {
84 RTUINT16U u16 = { RT_H2N_U16(aValue) };
85 aDst.insert(aDst.end(), u16.au8, u16.au8 + sizeof(aValue));
86 }
87
88 static void append(octets_t &aDst, uint32_t aValue)
89 {
90 RTUINT32U u32 = { RT_H2N_U32(aValue) };
91 aDst.insert(aDst.end(), u32.au8, u32.au8 + sizeof(aValue));
92 }
93
94 static void append(octets_t &aDst, RTNETADDRIPV4 aIPv4)
95 {
96 aDst.insert(aDst.end(), aIPv4.au8, aIPv4.au8 + sizeof(aIPv4));
97 }
98
99 static void append(octets_t &aDst, const char *pszString, size_t cb)
100 {
101 aDst.insert(aDst.end(), pszString, pszString + cb);
102 }
103
104 static void append(octets_t &aDst, const RTCString &str)
105 {
106 append(aDst, str.c_str(), str.length());
107 }
108
109 /* non-overloaded name to avoid ambiguity */
110 static void appendLength(octets_t &aDst, size_t cb)
111 {
112 append(aDst, static_cast<uint8_t>(cb));
113 }
114
115
116 /*
117 * Deserialization
118 */
119 static void extract(uint8_t &aValue, octets_t::const_iterator &pos)
120 {
121 aValue = *pos;
122 pos += sizeof(uint8_t);
123 }
124
125 static void extract(uint16_t &aValue, octets_t::const_iterator &pos)
126 {
127 RTUINT16U u16;
128 memcpy(u16.au8, &pos[0], sizeof(uint16_t));
129 aValue = RT_N2H_U16(u16.u);
130 pos += sizeof(uint16_t);
131 }
132
133 static void extract(uint32_t &aValue, octets_t::const_iterator &pos)
134 {
135 RTUINT32U u32;
136 memcpy(u32.au8, &pos[0], sizeof(uint32_t));
137 aValue = RT_N2H_U32(u32.u);
138 pos += sizeof(uint32_t);
139 }
140
141 static void extract(RTNETADDRIPV4 &aValue, octets_t::const_iterator &pos)
142 {
143 memcpy(aValue.au8, &pos[0], sizeof(RTNETADDRIPV4));
144 pos += sizeof(RTNETADDRIPV4);
145 }
146
147#if 0 /** @todo fix me */
148 static void extract(RTCString &aString, octets_t::const_iterator &pos, size_t cb)
149 {
150 aString.replace(aString.begin(), aString.end(), &pos[0], &pos[cb]);
151 pos += cb;
152 }
153#endif
154
155
156 /*
157 * Parse textual representation (e.g. in config file)
158 */
159 static int parse1(uint8_t &aValue, const char *pcszValue);
160 static int parse1(uint16_t &aValue, const char *pcszValue);
161 static int parse1(uint32_t &aValue, const char *pcszValue);
162 static int parse1(RTNETADDRIPV4 &aValue, const char *pcszValue);
163
164 static int parseList(std::vector<RTNETADDRIPV4> &aList, const char *pcszValue);
165
166 static int parseHex(octets_t &aRawValue, const char *pcszValue);
167};
168
169
170inline octets_t &operator<<(octets_t &dst, const DhcpOption &option)
171{
172 option.encode(dst);
173 return dst;
174}
175
176
177optmap_t &operator<<(optmap_t &optmap, DhcpOption *option);
178optmap_t &operator<<(optmap_t &optmap, const std::shared_ptr<DhcpOption> &option);
179
180
181
182/*
183 * Only for << OptEnd() syntactic sugar...
184 */
185struct OptEnd {};
186inline octets_t &operator<<(octets_t &dst, const OptEnd &end)
187{
188 RT_NOREF(end);
189
190 dst.push_back(RTNET_DHCP_OPT_END);
191 return dst;
192}
193
194
195
196/*
197 * Option that has no value
198 */
199class OptNoValueBase
200 : public DhcpOption
201{
202 public:
203 explicit OptNoValueBase(uint8_t aOptCode)
204 : DhcpOption(aOptCode, false) {}
205
206 OptNoValueBase(uint8_t aOptCode, bool fPresent)
207 : DhcpOption(aOptCode, fPresent) {}
208
209 OptNoValueBase(uint8_t aOptCode, const DhcpClientMessage &req)
210 : DhcpOption(aOptCode, false)
211 {
212 decode(req);
213 }
214
215 virtual OptNoValueBase *clone() const
216 {
217 return new OptNoValueBase(*this);
218 }
219
220 protected:
221 virtual ssize_t encodeValue(octets_t &dst) const
222 {
223 RT_NOREF(dst);
224 return 0;
225 }
226
227 public:
228 static bool isLengthValid(size_t cb)
229 {
230 return cb == 0;
231 }
232
233 virtual int decodeValue(const octets_t &src, size_t cb)
234 {
235 RT_NOREF(src);
236
237 if (!isLengthValid(cb))
238 return VERR_INVALID_PARAMETER;
239
240 m_fPresent = true;
241 return VINF_SUCCESS;
242 }
243};
244
245template <uint8_t _OptCode>
246class OptNoValue
247 : public OptNoValueBase
248{
249 public:
250 static const uint8_t optcode = _OptCode;
251
252 OptNoValue()
253 : OptNoValueBase(optcode) {}
254
255 explicit OptNoValue(bool fPresent) /* there's no overloaded ctor with value */
256 : OptNoValueBase(optcode, fPresent) {}
257
258 explicit OptNoValue(const DhcpClientMessage &req)
259 : OptNoValueBase(optcode, req) {}
260};
261
262
263
264/*
265 * Option that contains single value of fixed-size type T
266 */
267template <typename T>
268class OptValueBase
269 : public DhcpOption
270{
271 public:
272 typedef T value_t;
273
274 protected:
275 T m_Value;
276
277 explicit OptValueBase(uint8_t aOptCode)
278 : DhcpOption(aOptCode, false), m_Value() {}
279
280 OptValueBase(uint8_t aOptCode, const T &aOptValue)
281 : DhcpOption(aOptCode), m_Value(aOptValue) {}
282
283 OptValueBase(uint8_t aOptCode, const DhcpClientMessage &req)
284 : DhcpOption(aOptCode, false), m_Value()
285 {
286 decode(req);
287 }
288
289 public:
290 virtual OptValueBase *clone() const
291 {
292 return new OptValueBase(*this);
293 }
294
295 public:
296 T &value() { return m_Value; }
297 const T &value() const { return m_Value; }
298
299 protected:
300 virtual ssize_t encodeValue(octets_t &dst) const
301 {
302 append(dst, m_Value);
303 return sizeof(T);
304 }
305
306 public:
307 static bool isLengthValid(size_t cb)
308 {
309 return cb == sizeof(T);
310 }
311
312 virtual int decodeValue(const octets_t &src, size_t cb)
313 {
314 if (!isLengthValid(cb))
315 return VERR_INVALID_PARAMETER;
316
317 octets_t::const_iterator pos(src.begin());
318 extract(m_Value, pos);
319
320 m_fPresent = true;
321 return VINF_SUCCESS;
322 }
323};
324
325template<uint8_t _OptCode, typename T>
326class OptValue
327 : public OptValueBase<T>
328{
329 public:
330 using typename OptValueBase<T>::value_t;
331
332 public:
333 static const uint8_t optcode = _OptCode;
334
335 OptValue()
336 : OptValueBase<T>(optcode) {}
337
338 explicit OptValue(const T &aOptValue)
339 : OptValueBase<T>(optcode, aOptValue) {}
340
341 explicit OptValue(const DhcpClientMessage &req)
342 : OptValueBase<T>(optcode, req) {}
343
344 static OptValue *parse(const char *pcszValue)
345 {
346 typename OptValueBase<T>::value_t v;
347 int rc = DhcpOption::parse1(v, pcszValue);
348 if (RT_FAILURE(rc))
349 return NULL;
350 return new OptValue(v);
351 }
352};
353
354
355
356/*
357 * Option that contains a string.
358 */
359class OptStringBase
360 : public DhcpOption
361{
362 public:
363 typedef RTCString value_t;
364
365 protected:
366 RTCString m_String;
367
368 explicit OptStringBase(uint8_t aOptCode)
369 : DhcpOption(aOptCode, false), m_String() {}
370
371 OptStringBase(uint8_t aOptCode, const RTCString &aOptString)
372 : DhcpOption(aOptCode), m_String(aOptString) {}
373
374 OptStringBase(uint8_t aOptCode, const DhcpClientMessage &req)
375 : DhcpOption(aOptCode, false), m_String()
376 {
377 decode(req);
378 }
379
380 public:
381 virtual OptStringBase *clone() const
382 {
383 return new OptStringBase(*this);
384 }
385
386 public:
387 RTCString &value() { return m_String; }
388 const RTCString &value() const { return m_String; }
389
390 protected:
391 virtual ssize_t encodeValue(octets_t &dst) const
392 {
393 if (!isLengthValid(m_String.length()))
394 return -1;
395
396 append(dst, m_String);
397 return m_String.length();
398 }
399
400 public:
401 static bool isLengthValid(size_t cb)
402 {
403 return cb <= UINT8_MAX;
404 }
405
406 virtual int decodeValue(const octets_t &src, size_t cb)
407 {
408 if (!isLengthValid(cb))
409 return VERR_INVALID_PARAMETER;
410
411 int rc = m_String.assignNoThrow((char *)&src.front(), cb); /** @todo encoding. */
412 m_fPresent = true;
413 return rc;
414 }
415};
416
417template<uint8_t _OptCode>
418class OptString
419 : public OptStringBase
420{
421 public:
422 static const uint8_t optcode = _OptCode;
423
424 OptString()
425 : OptStringBase(optcode) {}
426
427 explicit OptString(const RTCString &aOptString)
428 : OptStringBase(optcode, aOptString) {}
429
430 explicit OptString(const DhcpClientMessage &req)
431 : OptStringBase(optcode, req) {}
432
433 static OptString *parse(const char *pcszValue)
434 {
435 return new OptString(pcszValue);
436 }
437};
438
439
440
441/*
442 * Option that contains a list of values of type T
443 */
444template <typename T>
445class OptListBase
446 : public DhcpOption
447{
448 public:
449 typedef std::vector<T> value_t;
450
451 protected:
452 std::vector<T> m_List;
453
454 explicit OptListBase(uint8_t aOptCode)
455 : DhcpOption(aOptCode, false), m_List() {}
456
457 OptListBase(uint8_t aOptCode, const T &aOptSingle)
458 : DhcpOption(aOptCode), m_List(1, aOptSingle) {}
459
460 OptListBase(uint8_t aOptCode, const std::vector<T> &aOptList)
461 : DhcpOption(aOptCode), m_List(aOptList) {}
462
463 OptListBase(uint8_t aOptCode, const DhcpClientMessage &req)
464 : DhcpOption(aOptCode, false), m_List()
465 {
466 decode(req);
467 }
468
469 public:
470 virtual OptListBase *clone() const
471 {
472 return new OptListBase(*this);
473 }
474
475 public:
476 std::vector<T> &value() { return m_List; }
477 const std::vector<T> &value() const { return m_List; }
478
479 protected:
480 virtual ssize_t encodeValue(octets_t &dst) const
481 {
482 const size_t cbItem = sizeof(T);
483 size_t cbValue = 0;
484
485 for (size_t i = 0; i < m_List.size(); ++i)
486 {
487 if (cbValue + cbItem > UINT8_MAX)
488 break;
489
490 append(dst, m_List[i]);
491 cbValue += cbItem;
492 }
493
494 return cbValue;
495 }
496
497 public:
498 static bool isLengthValid(size_t cb)
499 {
500 return cb % sizeof(T) == 0;
501 }
502
503 virtual int decodeValue(const octets_t &src, size_t cb)
504 {
505 if (!isLengthValid(cb))
506 return VERR_INVALID_PARAMETER;
507
508 m_List.erase(m_List.begin(), m_List.end());
509
510 octets_t::const_iterator pos(src.begin());
511 for (size_t i = 0; i < cb / sizeof(T); ++i)
512 {
513 T item;
514 extract(item, pos);
515 m_List.push_back(item);
516 }
517 m_fPresent = true;
518 return VINF_SUCCESS;
519 }
520};
521
522template<uint8_t _OptCode, typename T>
523class OptList
524 : public OptListBase<T>
525
526{
527 public:
528 using typename OptListBase<T>::value_t;
529
530 public:
531 static const uint8_t optcode = _OptCode;
532
533 OptList()
534 : OptListBase<T>(optcode) {}
535
536 explicit OptList(const T &aOptSingle)
537 : OptListBase<T>(optcode, aOptSingle) {}
538
539 explicit OptList(const std::vector<T> &aOptList)
540 : OptListBase<T>(optcode, aOptList) {}
541
542 explicit OptList(const DhcpClientMessage &req)
543 : OptListBase<T>(optcode, req) {}
544
545 static OptList *parse(const char *pcszValue)
546 {
547 typename OptListBase<T>::value_t v;
548 int rc = DhcpOption::parseList(v, pcszValue);
549 if (RT_FAILURE(rc) || v.empty())
550 return NULL;
551 return new OptList(v);
552 }
553};
554
555
556/*
557 * Options specified by raw binary data that we don't know how to
558 * interpret.
559 */
560class RawOption
561 : public DhcpOption
562{
563 protected:
564 octets_t m_Data;
565
566 public:
567 explicit RawOption(uint8_t aOptCode)
568 : DhcpOption(aOptCode, false), m_Data() {}
569
570 RawOption(uint8_t aOptCode, const octets_t &aSrc)
571 : DhcpOption(aOptCode), m_Data(aSrc) {}
572
573 public:
574 virtual RawOption *clone() const
575 {
576 return new RawOption(*this);
577 }
578
579
580 protected:
581 virtual ssize_t encodeValue(octets_t &dst) const
582 {
583 dst.insert(dst.end(), m_Data.begin(), m_Data.end());
584 return m_Data.size();
585 }
586
587 virtual int decodeValue(const octets_t &src, size_t cb)
588 {
589 octets_t::const_iterator beg(src.begin());
590 octets_t data(beg, beg + cb);
591 m_Data.swap(data);
592
593 m_fPresent = true;
594 return VINF_SUCCESS;
595 }
596
597 public:
598 static RawOption *parse(uint8_t aOptCode, const char *pcszValue)
599 {
600 octets_t data;
601 int rc = DhcpOption::parseHex(data, pcszValue);
602 if (RT_FAILURE(rc))
603 return NULL;
604 return new RawOption(aOptCode, data);
605 }
606};
607
608
609
610/** @name The DHCP options types.
611 * @{
612 */
613typedef OptValue<1, RTNETADDRIPV4> OptSubnetMask;
614typedef OptValue<2, uint32_t> OptTimeOffset;
615typedef OptList<3, RTNETADDRIPV4> OptRouter;
616typedef OptList<4, RTNETADDRIPV4> OptTimeServer;
617typedef OptList<6, RTNETADDRIPV4> OptDNS;
618typedef OptString<12> OptHostName;
619typedef OptString<15> OptDomainName;
620typedef OptString<17> OptRootPath;
621
622/* DHCP related options */
623typedef OptList<43, uint8_t> OptVendorSpecificInfo;
624typedef OptValue<50, RTNETADDRIPV4> OptRequestedAddress;
625typedef OptValue<51, uint32_t> OptLeaseTime;
626/* 52 - option overload is syntactic and handled internally */
627typedef OptValue<53, uint8_t> OptMessageType;
628typedef OptValue<54, RTNETADDRIPV4> OptServerId;
629typedef OptList<55, uint8_t> OptParameterRequest;
630typedef OptString<56> OptMessage;
631typedef OptValue<57, uint16_t> OptMaxDHCPMessageSize;
632typedef OptValue<58, uint32_t> OptRenewalTime;
633typedef OptValue<59, uint32_t> OptRebindingTime;
634typedef OptList<60, uint8_t> OptVendorClassId;
635typedef OptList<61, uint8_t> OptClientId;
636typedef OptString<66> OptTFTPServer; /* when overloaded */
637typedef OptString<67> OptBootFileName; /* when overloaded */
638typedef OptList<77, uint8_t> OptUserClassId;
639typedef OptNoValue<80> OptRapidCommit; /* RFC4039 */
640/** @} */
641
642#endif /* !VBOX_INCLUDED_SRC_Dhcpd_DhcpOptions_h */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette