VirtualBox

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

Last change on this file since 75665 was 75648, checked in by vboxsync, 6 years ago

Main/DHCPD: bugref:9288 Use new implementation of DHCP server (VCC 10 and GCC 4.4.4 support, other build fixes).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: DhcpOptions.h 75648 2018-11-21 18:02:38Z vboxsync $ */
2/** @file
3 * DHCP server - DHCP options
4 */
5
6/*
7 * Copyright (C) 2017-2018 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 _DHCP_OPTIONS_H_
19#define _DHCP_OPTIONS_H_
20
21#include "Defs.h"
22
23#include <string.h>
24
25#include <iprt/err.h>
26#include <iprt/types.h>
27#include <iprt/asm.h>
28#include <iprt/stdint.h>
29#include <iprt/net.h>
30
31#include <string>
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 { return m_OptCode; }
58 bool present() const { 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 std::string &str)
105 {
106 append(aDst, str.c_str(), str.size());
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 static void extract(std::string &aString, octets_t::const_iterator &pos, size_t cb)
148 {
149 aString.replace(aString.begin(), aString.end(), &pos[0], &pos[cb]);
150 pos += cb;
151 }
152
153
154 /*
155 * Parse textual representation (e.g. in config file)
156 */
157 static int parse1(uint8_t &aValue, const char *pcszValue);
158 static int parse1(uint16_t &aValue, const char *pcszValue);
159 static int parse1(uint32_t &aValue, const char *pcszValue);
160 static int parse1(RTNETADDRIPV4 &aValue, const char *pcszValue);
161
162 static int parseList(std::vector<RTNETADDRIPV4> &aList, const char *pcszValue);
163
164 static int parseHex(octets_t &aRawValue, const char *pcszValue);
165};
166
167
168inline octets_t &operator<<(octets_t &dst, const DhcpOption &option)
169{
170 option.encode(dst);
171 return dst;
172}
173
174
175optmap_t &operator<<(optmap_t &optmap, DhcpOption *option);
176optmap_t &operator<<(optmap_t &optmap, const std::shared_ptr<DhcpOption> &option);
177
178
179
180/*
181 * Only for << OptEnd() syntactic sugar...
182 */
183struct OptEnd {};
184inline octets_t &operator<<(octets_t &dst, const OptEnd &end)
185{
186 RT_NOREF(end);
187
188 dst.push_back(RTNET_DHCP_OPT_END);
189 return dst;
190}
191
192
193
194/*
195 * Option that has no value
196 */
197class OptNoValueBase
198 : public DhcpOption
199{
200 public:
201 explicit OptNoValueBase(uint8_t aOptCode)
202 : DhcpOption(aOptCode, false) {}
203
204 OptNoValueBase(uint8_t aOptCode, bool fPresent)
205 : DhcpOption(aOptCode, fPresent) {}
206
207 OptNoValueBase(uint8_t aOptCode, const DhcpClientMessage &req)
208 : DhcpOption(aOptCode, false)
209 {
210 decode(req);
211 }
212
213 virtual OptNoValueBase *clone() const
214 {
215 return new OptNoValueBase(*this);
216 }
217
218 protected:
219 virtual ssize_t encodeValue(octets_t &dst) const
220 {
221 RT_NOREF(dst);
222 return 0;
223 }
224
225 public:
226 static bool isLengthValid(size_t cb)
227 {
228 return cb == 0;
229 }
230
231 virtual int decodeValue(const octets_t &src, size_t cb)
232 {
233 RT_NOREF(src);
234
235 if (!isLengthValid(cb))
236 return VERR_INVALID_PARAMETER;
237
238 m_fPresent = true;
239 return VINF_SUCCESS;
240 }
241};
242
243template <uint8_t _OptCode>
244class OptNoValue
245 : public OptNoValueBase
246{
247 public:
248 static const uint8_t optcode = _OptCode;
249
250 OptNoValue()
251 : OptNoValueBase(optcode) {}
252
253 explicit OptNoValue(bool fPresent) /* there's no overloaded ctor with value */
254 : OptNoValueBase(optcode, fPresent) {}
255
256 explicit OptNoValue(const DhcpClientMessage &req)
257 : OptNoValueBase(optcode, req) {}
258};
259
260
261
262/*
263 * Option that contains single value of fixed-size type T
264 */
265template <typename T>
266class OptValueBase
267 : public DhcpOption
268{
269 public:
270 typedef T value_t;
271
272 protected:
273 T m_Value;
274
275 explicit OptValueBase(uint8_t aOptCode)
276 : DhcpOption(aOptCode, false), m_Value() {}
277
278 OptValueBase(uint8_t aOptCode, const T &aOptValue)
279 : DhcpOption(aOptCode), m_Value(aOptValue) {}
280
281 OptValueBase(uint8_t aOptCode, const DhcpClientMessage &req)
282 : DhcpOption(aOptCode, false), m_Value()
283 {
284 decode(req);
285 }
286
287 public:
288 virtual OptValueBase *clone() const
289 {
290 return new OptValueBase(*this);
291 }
292
293 public:
294 T &value() { return m_Value; }
295 const T &value() const { return m_Value; }
296
297 protected:
298 virtual ssize_t encodeValue(octets_t &dst) const
299 {
300 append(dst, m_Value);
301 return sizeof(T);
302 }
303
304 public:
305 static bool isLengthValid(size_t cb)
306 {
307 return cb == sizeof(T);
308 }
309
310 virtual int decodeValue(const octets_t &src, size_t cb)
311 {
312 if (!isLengthValid(cb))
313 return VERR_INVALID_PARAMETER;
314
315 octets_t::const_iterator pos(src.begin());
316 extract(m_Value, pos);
317
318 m_fPresent = true;
319 return VINF_SUCCESS;
320 }
321};
322
323template<uint8_t _OptCode, typename T>
324class OptValue
325 : public OptValueBase<T>
326{
327 public:
328 using typename OptValueBase<T>::value_t;
329
330 public:
331 static const uint8_t optcode = _OptCode;
332
333 OptValue()
334 : OptValueBase<T>(optcode) {}
335
336 explicit OptValue(const T &aOptValue)
337 : OptValueBase<T>(optcode, aOptValue) {}
338
339 explicit OptValue(const DhcpClientMessage &req)
340 : OptValueBase<T>(optcode, req) {}
341
342 static OptValue *parse(const char *pcszValue)
343 {
344 typename OptValueBase<T>::value_t v;
345 int rc = DhcpOption::parse1(v, pcszValue);
346 if (RT_FAILURE(rc))
347 return NULL;
348 return new OptValue(v);
349 }
350};
351
352
353
354/*
355 * Option that contains a string.
356 */
357class OptStringBase
358 : public DhcpOption
359{
360 public:
361 typedef std::string value_t;
362
363 protected:
364 std::string m_String;
365
366 explicit OptStringBase(uint8_t aOptCode)
367 : DhcpOption(aOptCode, false), m_String() {}
368
369 OptStringBase(uint8_t aOptCode, const std::string &aOptString)
370 : DhcpOption(aOptCode), m_String(aOptString) {}
371
372 OptStringBase(uint8_t aOptCode, const DhcpClientMessage &req)
373 : DhcpOption(aOptCode, false), m_String()
374 {
375 decode(req);
376 }
377
378 public:
379 virtual OptStringBase *clone() const
380 {
381 return new OptStringBase(*this);
382 }
383
384 public:
385 std::string &value() { return m_String; }
386 const std::string &value() const { return m_String; }
387
388 protected:
389 virtual ssize_t encodeValue(octets_t &dst) const
390 {
391 if (!isLengthValid(m_String.size()))
392 return -1;
393
394 append(dst, m_String);
395 return m_String.size();
396 }
397
398 public:
399 static bool isLengthValid(size_t cb)
400 {
401 return cb <= UINT8_MAX;
402 }
403
404 virtual int decodeValue(const octets_t &src, size_t cb)
405 {
406 if (!isLengthValid(cb))
407 return VERR_INVALID_PARAMETER;
408
409 octets_t::const_iterator pos(src.begin());
410 extract(m_String, pos, cb);
411 m_fPresent = true;
412 return VINF_SUCCESS;
413 }
414};
415
416template<uint8_t _OptCode>
417class OptString
418 : public OptStringBase
419{
420 public:
421 static const uint8_t optcode = _OptCode;
422
423 OptString()
424 : OptStringBase(optcode) {}
425
426 explicit OptString(const std::string &aOptString)
427 : OptStringBase(optcode, aOptString) {}
428
429 explicit OptString(const DhcpClientMessage &req)
430 : OptStringBase(optcode, req) {}
431
432 static OptString *parse(const char *pcszValue)
433 {
434 return new OptString(pcszValue);
435 }
436};
437
438
439
440/*
441 * Option that contains a list of values of type T
442 */
443template <typename T>
444class OptListBase
445 : public DhcpOption
446{
447 public:
448 typedef std::vector<T> value_t;
449
450 protected:
451 std::vector<T> m_List;
452
453 explicit OptListBase(uint8_t aOptCode)
454 : DhcpOption(aOptCode, false), m_List() {}
455
456 OptListBase(uint8_t aOptCode, const T &aOptSingle)
457 : DhcpOption(aOptCode), m_List(1, aOptSingle) {}
458
459 OptListBase(uint8_t aOptCode, const std::vector<T> &aOptList)
460 : DhcpOption(aOptCode), m_List(aOptList) {}
461
462 OptListBase(uint8_t aOptCode, const DhcpClientMessage &req)
463 : DhcpOption(aOptCode, false), m_List()
464 {
465 decode(req);
466 }
467
468 public:
469 virtual OptListBase *clone() const
470 {
471 return new OptListBase(*this);
472 }
473
474 public:
475 std::vector<T> &value() { return m_List; }
476 const std::vector<T> &value() const { return m_List; }
477
478 protected:
479 virtual ssize_t encodeValue(octets_t &dst) const
480 {
481 const size_t cbItem = sizeof(T);
482 size_t cbValue = 0;
483
484 for (size_t i = 0; i < m_List.size(); ++i)
485 {
486 if (cbValue + cbItem > UINT8_MAX)
487 break;
488
489 append(dst, m_List[i]);
490 cbValue += cbItem;
491 }
492
493 return cbValue;
494 }
495
496 public:
497 static bool isLengthValid(size_t cb)
498 {
499 return cb % sizeof(T) == 0;
500 }
501
502 virtual int decodeValue(const octets_t &src, size_t cb)
503 {
504 if (!isLengthValid(cb))
505 return VERR_INVALID_PARAMETER;
506
507 m_List.erase(m_List.begin(), m_List.end());
508
509 octets_t::const_iterator pos(src.begin());
510 for (size_t i = 0; i < cb / sizeof(T); ++i)
511 {
512 T item;
513 extract(item, pos);
514 m_List.push_back(item);
515 }
516 m_fPresent = true;
517 return VINF_SUCCESS;
518 }
519};
520
521template<uint8_t _OptCode, typename T>
522class OptList
523 : public OptListBase<T>
524
525{
526 public:
527 using typename OptListBase<T>::value_t;
528
529 public:
530 static const uint8_t optcode = _OptCode;
531
532 OptList()
533 : OptListBase<T>(optcode) {}
534
535 explicit OptList(const T &aOptSingle)
536 : OptListBase<T>(optcode, aOptSingle) {}
537
538 explicit OptList(const std::vector<T> &aOptList)
539 : OptListBase<T>(optcode, aOptList) {}
540
541 explicit OptList(const DhcpClientMessage &req)
542 : OptListBase<T>(optcode, req) {}
543
544 static OptList *parse(const char *pcszValue)
545 {
546 typename OptListBase<T>::value_t v;
547 int rc = DhcpOption::parseList(v, pcszValue);
548 if (RT_FAILURE(rc) || v.empty())
549 return NULL;
550 return new OptList(v);
551 }
552};
553
554
555/*
556 * Options specified by raw binary data that we don't know how to
557 * interpret.
558 */
559class RawOption
560 : public DhcpOption
561{
562 protected:
563 octets_t m_Data;
564
565 public:
566 explicit RawOption(uint8_t aOptCode)
567 : DhcpOption(aOptCode, false), m_Data() {}
568
569 RawOption(uint8_t aOptCode, const octets_t &aSrc)
570 : DhcpOption(aOptCode), m_Data(aSrc) {}
571
572 public:
573 virtual RawOption *clone() const
574 {
575 return new RawOption(*this);
576 }
577
578
579 protected:
580 virtual ssize_t encodeValue(octets_t &dst) const
581 {
582 dst.insert(dst.end(), m_Data.begin(), m_Data.end());
583 return m_Data.size();
584 }
585
586 virtual int decodeValue(const octets_t &src, size_t cb)
587 {
588 octets_t::const_iterator beg(src.begin());
589 octets_t data(beg, beg + cb);
590 m_Data.swap(data);
591
592 m_fPresent = true;
593 return VINF_SUCCESS;
594 }
595
596 public:
597 static RawOption *parse(uint8_t aOptCode, const char *pcszValue)
598 {
599 octets_t data;
600 int rc = DhcpOption::parseHex(data, pcszValue);
601 if (RT_FAILURE(rc))
602 return NULL;
603 return new RawOption(aOptCode, data);
604 }
605};
606
607
608
609/*
610 * Define the DHCP options we want to use.
611 */
612typedef OptValue<1, RTNETADDRIPV4> OptSubnetMask;
613typedef OptValue<2, uint32_t> OptTimeOffset;
614typedef OptList<3, RTNETADDRIPV4> OptRouter;
615typedef OptList<4, RTNETADDRIPV4> OptTimeServer;
616typedef OptList<6, RTNETADDRIPV4> OptDNS;
617typedef OptString<12> OptHostName;
618typedef OptString<15> OptDomainName;
619typedef OptString<17> OptRootPath;
620
621/* DHCP related options */
622typedef OptList<43, uint8_t> OptVendorSpecificInfo;
623typedef OptValue<50, RTNETADDRIPV4> OptRequestedAddress;
624typedef OptValue<51, uint32_t> OptLeaseTime;
625/* 52 - option overload is syntactic and handled internally */
626typedef OptValue<53, uint8_t> OptMessageType;
627typedef OptValue<54, RTNETADDRIPV4> OptServerId;
628typedef OptList<55, uint8_t> OptParameterRequest;
629typedef OptString<56> OptMessage;
630typedef OptValue<57, uint16_t> OptMaxDHCPMessageSize;
631typedef OptValue<58, uint32_t> OptRenewalTime;
632typedef OptValue<59, uint32_t> OptRebindingTime;
633typedef OptList<60, uint8_t> OptVendorClassId;
634typedef OptList<61, uint8_t> OptClientId;
635typedef OptString<66> OptTFTPServer; /* when overloaded */
636typedef OptString<67> OptBootFileName; /* when overloaded */
637typedef OptNoValue<80> OptRapidCommit; /* RFC4039 */
638
639#endif /* _DHCP_OPTIONS_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