VirtualBox

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

Last change on this file since 77924 was 76576, checked in by vboxsync, 6 years ago

NetworkServices: scm header guard alignment.

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