Kea 3.3.1
libdhcp++.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <dhcp/dhcp4.h>
10#include <dhcp/dhcp6.h>
11#include <dhcp/libdhcp++.h>
12#include <dhcp/option.h>
13#include <dhcp/option_vendor.h>
14#include <dhcp/option6_ia.h>
15#include <dhcp/option6_iaaddr.h>
19#include <dhcp/option_custom.h>
24#include <util/buffer.h>
25#include <util/io.h>
26
27#include <boost/foreach.hpp>
28#include <boost/lexical_cast.hpp>
29#include <boost/shared_array.hpp>
30#include <boost/shared_ptr.hpp>
31
32#include <limits>
33#include <list>
34#include <unordered_map>
35#include <vector>
36
37using namespace std;
38using namespace isc::dhcp;
39using namespace isc::util;
40
41namespace isc {
42namespace dhcp {
43
44namespace {
45
49const OptionDefParamsEncapsulation OPTION_DEF_PARAMS[] = {
50 { STANDARD_V4_OPTION_DEFINITIONS, STANDARD_V4_OPTION_DEFINITIONS_SIZE, DHCP4_OPTION_SPACE },
51 { STANDARD_V6_OPTION_DEFINITIONS, STANDARD_V6_OPTION_DEFINITIONS_SIZE, DHCP6_OPTION_SPACE },
54 { ISC_V6_OPTION_DEFINITIONS, ISC_V6_OPTION_DEFINITIONS_SIZE, ISC_V6_OPTION_SPACE },
55 { MAPE_V6_OPTION_DEFINITIONS, MAPE_V6_OPTION_DEFINITIONS_SIZE, MAPE_V6_OPTION_SPACE },
56 { MAPT_V6_OPTION_DEFINITIONS, MAPT_V6_OPTION_DEFINITIONS_SIZE, MAPT_V6_OPTION_SPACE },
57 { LW_V6_OPTION_DEFINITIONS, LW_V6_OPTION_DEFINITIONS_SIZE, LW_V6_OPTION_SPACE },
58 { V4V6_RULE_OPTION_DEFINITIONS, V4V6_RULE_OPTION_DEFINITIONS_SIZE, V4V6_RULE_OPTION_SPACE },
59 { V4V6_BIND_OPTION_DEFINITIONS, V4V6_BIND_OPTION_DEFINITIONS_SIZE, V4V6_BIND_OPTION_SPACE },
60 { V6_NTP_SERVER_DEFINITIONS, V6_NTP_SERVER_DEFINITIONS_SIZE, V6_NTP_SERVER_SPACE },
61 { CABLELABS_CLIENT_CONF_DEFINITIONS, CABLELABS_CLIENT_CONF_DEFINITIONS_SIZE,
63 { LAST_RESORT_V4_OPTION_DEFINITIONS, LAST_RESORT_V4_OPTION_DEFINITIONS_SIZE, LAST_RESORT_V4_OPTION_SPACE },
64 { DHCP_AGENT_OPTION_DEFINITIONS, DHCP_AGENT_OPTION_DEFINITIONS_SIZE, DHCP_AGENT_OPTION_SPACE },
65 { NULL, 0, "" }
66};
67
68} // namespace
69
70} // namespace dhcp
71} // namespace isc
72
73// static array with factories for options
74map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
75
76// static array with factories for options
77map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
78
79// Static container with option definitions grouped by option space.
80OptionDefContainers LibDHCP::option_defs_;
81
82// Static container with option definitions created in runtime.
83StagedValue<OptionDefSpaceContainer> LibDHCP::runtime_option_defs_;
84
85// Null container.
87
88// Those two vendor classes are used for cable modems:
89
91const char* isc::dhcp::DOCSIS3_CLASS_MODEM = "docsis3.0";
92
94const char* isc::dhcp::DOCSIS3_CLASS_EROUTER = "eRouter1.0";
95
96// Let's keep it in .cc file. Moving it to .h would require including optionDefParams
97// definitions there
99 const OptionDefParams* params,
100 size_t params_size);
101
102bool LibDHCP::initialized_ = LibDHCP::initOptionDefs();
103
105LibDHCP::getOptionDefs(const string& space) {
106 auto const& container = option_defs_.find(space);
107 if (container != option_defs_.end()) {
108 return (container->second);
109 }
110
112}
113
115LibDHCP::getVendorOptionDefs(const Option::Universe u, const uint32_t vendor_id) {
116 if (Option::V4 == u) {
117 if (VENDOR_ID_CABLE_LABS == vendor_id) {
119 }
120 } else if (Option::V6 == u) {
121 if (VENDOR_ID_CABLE_LABS == vendor_id) {
123 } else if (ENTERPRISE_ID_ISC == vendor_id) {
125 }
126 }
127
129}
130
132LibDHCP::getOptionDef(const string& space, const uint16_t code) {
133 const OptionDefContainerPtr& defs = getOptionDefs(space);
134 const OptionDefContainerTypeIndex& idx = defs->get<1>();
135 const OptionDefContainerTypeRange& range = idx.equal_range(code);
136 if (range.first != range.second) {
137 return (*range.first);
138 }
139
140 return (OptionDefinitionPtr());
141}
142
144LibDHCP::getOptionDef(const string& space, const string& name) {
145 const OptionDefContainerPtr& defs = getOptionDefs(space);
146 const OptionDefContainerNameIndex& idx = defs->get<2>();
147 const OptionDefContainerNameRange& range = idx.equal_range(name);
148 if (range.first != range.second) {
149 return (*range.first);
150 }
151
152 return (OptionDefinitionPtr());
153}
154
156LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
157 const string& name) {
158 const OptionDefContainerPtr& defs = getVendorOptionDefs(u, vendor_id);
159
160 if (!defs) {
161 return (OptionDefinitionPtr());
162 }
163
164 const OptionDefContainerNameIndex& idx = defs->get<2>();
165 const OptionDefContainerNameRange& range = idx.equal_range(name);
166 if (range.first != range.second) {
167 return (*range.first);
168 }
169
170 return (OptionDefinitionPtr());
171}
172
174LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
175 const uint16_t code) {
176 const OptionDefContainerPtr& defs = getVendorOptionDefs(u, vendor_id);
177
178 if (!defs) {
179 // Weird universe or unknown vendor_id. We don't care. No definitions
180 // one way or another
181 // What is it anyway?
182 return (OptionDefinitionPtr());
183 }
184
185 const OptionDefContainerTypeIndex& idx = defs->get<1>();
186 const OptionDefContainerTypeRange& range = idx.equal_range(code);
187 if (range.first != range.second) {
188 return (*range.first);
189 }
190
191 return (OptionDefinitionPtr());
192}
193
195LibDHCP::getRuntimeOptionDef(const string& space, const uint16_t code) {
196 OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
197 const OptionDefContainerTypeIndex& index = container->get<1>();
198 const OptionDefContainerTypeRange& range = index.equal_range(code);
199 if (range.first != range.second) {
200 return (*range.first);
201 }
202
203 return (OptionDefinitionPtr());
204}
205
207LibDHCP::getRuntimeOptionDef(const string& space, const string& name) {
208 OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
209 const OptionDefContainerNameIndex& index = container->get<2>();
210 const OptionDefContainerNameRange& range = index.equal_range(name);
211 if (range.first != range.second) {
212 return (*range.first);
213 }
214
215 return (OptionDefinitionPtr());
216}
217
219LibDHCP::getRuntimeOptionDefs(const string& space) {
220 return (runtime_option_defs_.getValue().getItems(space));
221}
222
223void
225 OptionDefSpaceContainer defs_copy;
226 list<string> option_space_names = defs.getOptionSpaceNames();
227 for (auto const& name : option_space_names) {
228 OptionDefContainerPtr container = defs.getItems(name);
229 for (auto const& def : *container) {
230 OptionDefinitionPtr def_copy(new OptionDefinition(*def));
231 defs_copy.addItem(def_copy);
232 }
233 }
234 runtime_option_defs_ = defs_copy;
235}
236
237void
239 runtime_option_defs_.reset();
240}
241
242void
244 runtime_option_defs_.revert();
245}
246
247void
249 runtime_option_defs_.commit();
250}
251
253LibDHCP::getLastResortOptionDef(const string& space, const uint16_t code) {
255 const OptionDefContainerTypeIndex& index = container->get<1>();
256 const OptionDefContainerTypeRange& range = index.equal_range(code);
257 if (range.first != range.second) {
258 return (*range.first);
259 }
260
261 return (OptionDefinitionPtr());
262}
263
265LibDHCP::getLastResortOptionDef(const string& space, const string& name) {
267 const OptionDefContainerNameIndex& index = container->get<2>();
268 const OptionDefContainerNameRange& range = index.equal_range(name);
269 if (range.first != range.second) {
270 return (*range.first);
271 }
272
273 return (OptionDefinitionPtr());
274}
275
278 if (space == DHCP4_OPTION_SPACE) {
280 }
281
283}
284
285bool
286LibDHCP::shouldDeferOptionUnpack(const string& space, const uint16_t code) {
287 return ((space == DHCP4_OPTION_SPACE) &&
289 ((code >= 224) && (code <= 254))));
290}
291
294 uint16_t type,
295 const OptionBuffer& buf) {
296 FactoryMap::iterator it;
297 if (u == Option::V4) {
298 it = v4factories_.find(type);
299 if (it == v4factories_.end()) {
300 isc_throw(BadValue, "factory function not registered "
301 "for DHCP v4 option type " << type);
302 }
303 } else if (u == Option::V6) {
304 it = v6factories_.find(type);
305 if (it == v6factories_.end()) {
306 isc_throw(BadValue, "factory function not registered "
307 "for DHCPv6 option type " << type);
308 }
309 } else {
310 isc_throw(BadValue, "invalid universe specified (expected "
311 "Option::V4 or Option::V6");
312 }
313 return (it->second(u, type, buf));
314}
315
316size_t
318
319size_t
320LibDHCP::unpackOptions6(const OptionBuffer& buf, const string& option_space,
321 OptionCollection& options,
322 size_t* relay_msg_offset /* = 0 */,
323 size_t* relay_msg_len /* = 0 */,
324 size_t rec_level /* = 0 */) {
325 ++rec_level;
326 if (rec_level >= MAX_RECURSION_LEVEL) {
327 isc_throw(isc::Unexpected, "Too deep recursion in unpacking options");
328 }
329 size_t offset = 0;
330 size_t length = buf.size();
331 size_t last_offset = 0;
332
333 // Get the list of standard option definitions.
334 const OptionDefContainerPtr& option_defs = LibDHCP::getOptionDefs(option_space);
335 // Runtime option definitions for non standard option space and if
336 // the definition doesn't exist within the standard option definitions.
337 const OptionDefContainerPtr& runtime_option_defs = LibDHCP::getRuntimeOptionDefs(option_space);
338
339 // @todo Once we implement other option spaces we should add else clause
340 // here and gather option definitions for them. For now leaving option_defs
341 // empty will imply creation of generic Option.
342
343 // Get the search indexes #1. It allows to search for option definitions
344 // using option code.
345 const OptionDefContainerTypeIndex& idx = option_defs->get<1>();
346 const OptionDefContainerTypeIndex& runtime_idx = runtime_option_defs->get<1>();
347
348 // The buffer being read comprises a set of options, each starting with
349 // a two-byte type code and a two-byte length field.
350 while (offset < length) {
351 // Save the current offset for backtracking
352 last_offset = offset;
353
354 // Check if there is room for another option
355 if (offset + 4 > length) {
356 // Still something but smaller than an option
357 return (last_offset);
358 }
359
360 // Parse the option header
361 uint16_t opt_type = readUint16(&buf[offset], 2);
362 offset += 2;
363
364 uint16_t opt_len = readUint16(&buf[offset], 2);
365 offset += 2;
366
367 if (offset + opt_len > length) {
368 // We peeked at the option header of the next option, but
369 // discovered that it would end up beyond buffer end, so
370 // the option is truncated. Hence we can't parse
371 // it. Therefore we revert back by those bytes (as if
372 // we never parsed them).
373 //
374 // @note it is the responsibility of the caller to throw
375 // an exception on partial parsing
376 return (last_offset);
377 }
378
379 if (opt_type == D6O_RELAY_MSG && relay_msg_offset && relay_msg_len) {
380 // remember offset of the beginning of the relay-msg option
381 *relay_msg_offset = offset;
382 *relay_msg_len = opt_len;
383
384 // do not create that relay-msg option
385 offset += opt_len;
386 continue;
387 }
388
389 if (opt_type == D6O_VENDOR_OPTS) {
390 if (offset + 4 > length) {
391 // Truncated vendor-option. We expect at least
392 // 4 bytes for the enterprise-id field. Let's roll back
393 // option code + option length (4 bytes) and return.
394 return (last_offset);
395 }
396
397 // Parse this as vendor option
398 OptionPtr vendor_opt(new OptionVendor(Option::V6,
399 buf.begin() + offset,
400 buf.begin() + offset + opt_len,
401 rec_level));
402 options.insert(std::make_pair(opt_type, vendor_opt));
403
404 offset += opt_len;
405 continue;
406 }
407
408 // Get all definitions with the particular option code. Note
409 // that option code is non-unique within this container
410 // however at this point we expect to get one option
411 // definition with the particular code. If more are returned
412 // we report an error.
414 // Number of option definitions returned.
415 size_t num_defs = 0;
416
417 // We previously did the lookup only for dhcp6 option space, but with the
418 // addition of S46 options, we now do it for every space.
419 range = idx.equal_range(opt_type);
420 num_defs = std::distance(range.first, range.second);
421
422 // Standard option definitions do not include the definition for
423 // our option or we're searching for non-standard option. Try to
424 // find the definition among runtime option definitions.
425 if (num_defs == 0) {
426 range = runtime_idx.equal_range(opt_type);
427 num_defs = std::distance(range.first, range.second);
428 }
429
430 OptionPtr opt;
431 if (num_defs > 1) {
432 // Multiple options of the same code are not supported right now!
433 isc_throw(isc::Unexpected, "Internal error: multiple option"
434 " definitions for option type " << opt_type <<
435 " returned. Currently it is not supported to initialize"
436 " multiple option definitions for the same option code."
437 " This will be supported once support for option spaces"
438 " is implemented");
439 } else if (num_defs == 0) {
440 // @todo Don't crash if definition does not exist because
441 // only a few option definitions are initialized right
442 // now. In the future we will initialize definitions for
443 // all options and we will remove this elseif. For now,
444 // return generic option.
445 opt = OptionPtr(new Option(Option::V6, opt_type,
446 buf.begin() + offset,
447 buf.begin() + offset + opt_len));
448 } else {
449 try {
450 // The option definition has been found. Use it to create
451 // the option instance from the provided buffer chunk.
452 const OptionDefinitionPtr& def = *(range.first);
453 isc_throw_assert(def);
454 opt = def->optionFactory(Option::V6, opt_type,
455 buf.begin() + offset,
456 buf.begin() + offset + opt_len,
457 false, rec_level);
458
459 // Check the stated length against defined length of scalar options.
460 sanityCheckScalarLength(def, opt_len);
461 } catch (const SkipThisOptionError&) {
462 opt.reset();
463 } catch (const SkipRemainingOptionsError&) {
464 throw;
465 } catch (const std::exception& ex) {
466 isc_throw(OptionParseError, "opt_type: " << static_cast<uint16_t>(opt_type)
467 << ", opt_len: " << static_cast<uint16_t>(opt_len)
468 << ", error: " << ex.what());
469 }
470 }
471
472 // add option to options
473 if (opt) {
474 options.insert(std::make_pair(opt_type, opt));
475 }
476
477 offset += opt_len;
478 }
479
480 last_offset = offset;
481 return (last_offset);
482}
483
484size_t
485LibDHCP::unpackOptions4(const OptionBuffer& buf, const string& option_space,
486 OptionCollection& options, list<uint16_t>& deferred,
487 bool check) {
488 size_t offset = 0;
489 size_t last_offset = 0;
490
491 // Special case when option_space is dhcp4.
492 bool space_is_dhcp4 = (option_space == DHCP4_OPTION_SPACE);
493
494 // Get the list of standard option definitions.
495 const OptionDefContainerPtr& option_defs = LibDHCP::getOptionDefs(option_space);
496 // Runtime option definitions for non standard option space and if
497 // the definition doesn't exist within the standard option definitions.
498 const OptionDefContainerPtr& runtime_option_defs = LibDHCP::getRuntimeOptionDefs(option_space);
499
500 // Get the search indexes #1. It allows to search for option definitions
501 // using option code.
502 const OptionDefContainerTypeIndex& idx = option_defs->get<1>();
503 const OptionDefContainerTypeIndex& runtime_idx = runtime_option_defs->get<1>();
504
505 // Flexible PAD and END parsing.
506 bool flex_pad = (check && (runtime_idx.count(DHO_PAD) == 0));
507 bool flex_end = (check && (runtime_idx.count(DHO_END) == 0));
508
509 // The buffer being read comprises a set of options, each starting with
510 // a one-byte type code and a one-byte length field.
511
512 // Track seen options in a first pass.
513 vector<uint32_t> count(256, 0);
514 while (offset < buf.size()) {
515 // Get the option type
516 uint8_t opt_type = buf[offset++];
517
518 // DHO_END is a special, one octet long option
519 // Valid in dhcp4 space or when check is true and
520 // there is a sub-option configured for this code.
521 if ((opt_type == DHO_END) && (space_is_dhcp4 || flex_end)) {
522 // Done.
523 break;
524 }
525
526 // DHO_PAD is just a padding after DHO_END. Let's continue parsing
527 // in case we receive a message without DHO_END.
528 // Valid in dhcp4 space or when check is true and
529 // there is a sub-option configured for this code.
530 if ((opt_type == DHO_PAD) && (space_is_dhcp4 || flex_pad)) {
531 continue;
532 }
533
534 if (offset + 1 > buf.size()) {
535 // Error case.
536 break;
537 }
538
539 uint8_t opt_len = buf[offset++];
540 if (offset + opt_len > buf.size()) {
541 // Error case.
542 break;
543 }
544
545 // See below for this special case.
546 if (space_is_dhcp4 && opt_len == 0 && opt_type == DHO_HOST_NAME) {
547 continue;
548 }
549
550 offset += opt_len;
551
552 // Increment count.
553 count[opt_type] += 1;
554 }
555
556 // Fusing option buffers.
557 unordered_map<uint8_t, pair<OptionBuffer, uint32_t>> fused;
558
559 // Second pass.
560 offset = 0;
561 while (offset < buf.size()) {
562 // Save the current offset for backtracking
563 last_offset = offset;
564
565 // Get the option type
566 uint8_t opt_type = buf[offset++];
567
568 // DHO_END is a special, one octet long option
569 // Valid in dhcp4 space or when check is true and
570 // there is a sub-option configured for this code.
571 if ((opt_type == DHO_END) && (space_is_dhcp4 || flex_end)) {
572 // just return. Don't need to add DHO_END option
573 // Don't return offset because it makes this condition
574 // and partial parsing impossible to recognize.
575 return (last_offset);
576 }
577
578 // DHO_PAD is just a padding after DHO_END. Let's continue parsing
579 // in case we receive a message without DHO_END.
580 // Valid in dhcp4 space or when check is true and
581 // there is a sub-option configured for this code.
582 if ((opt_type == DHO_PAD) && (space_is_dhcp4 || flex_pad)) {
583 continue;
584 }
585
586 if (offset + 1 > buf.size()) {
587 // We peeked at the option header of the next option, but
588 // discovered that it would end up beyond buffer end, so
589 // the option is truncated. Hence we can't parse
590 // it. Therefore we revert back (as if we never parsed it).
591 //
592 // @note it is the responsibility of the caller to throw
593 // an exception on partial parsing
594 return (last_offset);
595 }
596
597 uint8_t opt_len = buf[offset++];
598 if (offset + opt_len > buf.size()) {
599 // We peeked at the option header of the next option, but
600 // discovered that it would end up beyond buffer end, so
601 // the option is truncated. Hence we can't parse
602 // it. Therefore we revert back (as if we never parsed it).
603 return (last_offset);
604 }
605
606 // While an empty Host Name option is non-RFC compliant, some clients
607 // do send it. In the spirit of being liberal, we'll just drop it,
608 // rather than the dropping the whole packet. We do not have a
609 // way to log this from here but meh... a PCAP will show it arriving,
610 // and we know we drop it.
611 if (space_is_dhcp4 && opt_len == 0 && opt_type == DHO_HOST_NAME) {
612 continue;
613 }
614
615 OptionBuffer obuf(buf.begin() + offset, buf.begin() + offset + opt_len);
616 offset += opt_len;
617
618 // Concatenate multiple instance of an option.
619 uint32_t opt_count = count[opt_type];
620 if (opt_count > 1) {
621 OptionBuffer& previous = fused[opt_type].first;
622 previous.insert(previous.end(), obuf.begin(), obuf.end());
623 uint32_t& already_seen = fused[opt_type].second;
624 ++already_seen;
625 if (already_seen != opt_count) {
626 continue;
627 } else {
628 // last occurrence: build the option.
629 obuf = previous;
630 }
631 }
632
633 // Get all definitions with the particular option code. Note
634 // that option code is non-unique within this container
635 // however at this point we expect to get one option
636 // definition with the particular code. If more are returned
637 // we report an error.
639 // Number of option definitions returned.
640 size_t num_defs = 0;
641
642 // Previously we did the lookup only for "dhcp4" option space, but there
643 // may be standard options in other spaces (e.g. radius). So we now do
644 // the lookup for every space.
645 range = idx.equal_range(opt_type);
646 num_defs = std::distance(range.first, range.second);
647
648 // Standard option definitions do not include the definition for
649 // our option or we're searching for non-standard option. Try to
650 // find the definition among runtime option definitions.
651 if (num_defs == 0) {
652 range = runtime_idx.equal_range(opt_type);
653 num_defs = std::distance(range.first, range.second);
654 }
655
656 // Check if option unpacking must be deferred
657 if (shouldDeferOptionUnpack(option_space, opt_type)) {
658 num_defs = 0;
659 // Store deferred option only once.
660 bool found = false;
661 for (auto const& existing : deferred) {
662 if (existing == opt_type) {
663 found = true;
664 break;
665 }
666 }
667 if (!found) {
668 deferred.push_back(opt_type);
669 }
670 }
671
672 if (space_is_dhcp4 &&
673 (opt_type == DHO_VIVSO_SUBOPTIONS ||
674 opt_type == DHO_VIVCO_SUBOPTIONS)) {
675 num_defs = 0;
676 }
677
678 OptionPtr opt;
679 if (num_defs > 1) {
680 // Multiple options of the same code are not supported right now!
681 isc_throw(isc::Unexpected, "Internal error: multiple option"
682 " definitions for option type " <<
683 static_cast<int>(opt_type) <<
684 " returned. Currently it is not supported to initialize"
685 " multiple option definitions for the same option code."
686 " This will be supported once support for option spaces"
687 " is implemented");
688 } else if (num_defs == 0) {
689 opt = OptionPtr(new Option(Option::V4, opt_type, obuf));
690 } else {
691 try {
692 // The option definition has been found. Use it to create
693 // the option instance from the provided buffer chunk.
694 const OptionDefinitionPtr& def = *(range.first);
695 isc_throw_assert(def);
696 opt = def->optionFactory(Option::V4, opt_type, obuf);
697
698 // Check the stated length against defined length of scalar options.
699 sanityCheckScalarLength(def, opt_len);
700 } catch (const SkipThisOptionError& ex) {
701 opt.reset();
702 } catch (const SkipRemainingOptionsError&) {
703 throw;
704 } catch (const std::exception& ex) {
705 isc_throw(OptionParseError, "opt_type: " << static_cast<uint16_t>(opt_type)
706 << ", opt_len: " << static_cast<uint16_t>(opt_len)
707 << ", error: " << ex.what());
708 }
709 }
710
711 // If we have the option, insert it
712 if (opt) {
713 options.insert(std::make_pair(opt_type, opt));
714 }
715 }
716 last_offset = offset;
717 return (last_offset);
718}
719
720void
723 return;
724 }
725
726 // Check the stated length against defined length of scalar options.
727 // If it exceeds the defined length throw. We don't check for undersized
728 // lengths as this is done in option factories and would break v4 option
729 // fusing.
730 size_t exp_len = OptionDataTypeUtil::getDataTypeLen(def->getType());
731 if ((exp_len > 0) && (opt_len > exp_len) && !def->getArrayType() &&
732 def->getEncapsulatedSpace().empty()) {
733 isc_throw(BadValue, "opt_len does not match defined option length "
734 << static_cast<uint16_t>(exp_len) << " for data type "
735 << OptionDataTypeUtil::getDataTypeName(def->getType()));
736 }
737}
738
739namespace { // Anonymous namespace.
740
741// VIVCO part of extendVendorOptions4.
742
743void
744extendVivco(OptionCollection& options) {
745 typedef vector<OpaqueDataTuple> TuplesCollection;
746 map<uint32_t, TuplesCollection> vendors_tuples;
747 auto const& range = options.equal_range(DHO_VIVCO_SUBOPTIONS);
748 BOOST_FOREACH(auto const& it, range) {
749 uint32_t offset = 0;
750 auto const& data = it.second->getData();
751 size_t size;
752 while ((size = data.size() - offset) != 0) {
753 if (size < sizeof(uint32_t)) {
754 options.erase(DHO_VIVCO_SUBOPTIONS);
756 "Truncated vendor-class information option"
757 << ", length=" << size);
758 }
759 uint32_t vendor_id = readUint32(&data[offset], data.size());
760 offset += 4;
761 try {
762 // From OptionVendorClass::unpack.
764 data.begin() + offset, data.end());
765 vendors_tuples[vendor_id].push_back(tuple);
766 offset += tuple.getTotalLength();
767 } catch (const OpaqueDataTupleError&) {
768 // Ignore this kind of error and continue.
769 break;
770 } catch (const isc::Exception&) {
771 options.erase(DHO_VIVCO_SUBOPTIONS);
772 throw;
773 }
774 }
775 }
776 if (vendors_tuples.empty()) {
777 return;
778 }
779 // Delete the initial option.
780 options.erase(DHO_VIVCO_SUBOPTIONS);
781 // Create a new instance of OptionVendor for each enterprise ID.
782 for (auto const& vendor : vendors_tuples) {
783 if (vendor.second.empty()) {
784 continue;
785 }
787 vendor.first));
788 for (size_t i = 0; i < vendor.second.size(); ++i) {
789 if (i == 0) {
790 vendor_opt->setTuple(0, vendor.second[0]);
791 } else {
792 vendor_opt->addTuple(vendor.second[i]);
793 }
794 }
795 // Add the new instance of VendorOption with respective sub-options for
796 // this enterprise ID.
797 options.insert(std::make_pair(DHO_VIVCO_SUBOPTIONS, vendor_opt));
798 }
799}
800
801// VIVSO part of extendVendorOptions4.
802
803void
804extendVivso(OptionCollection& options) {
805 map<uint32_t, OptionCollection> vendors_data;
806 auto const& range = options.equal_range(DHO_VIVSO_SUBOPTIONS);
807 BOOST_FOREACH(auto const& it, range) {
808 uint32_t offset = 0;
809 auto const& data = it.second->getData();
810 size_t size;
811 while ((size = data.size() - offset) != 0) {
812 if (size < sizeof(uint32_t)) {
813 options.erase(DHO_VIVSO_SUBOPTIONS);
815 "Truncated vendor-specific information option"
816 << ", length=" << size);
817 }
818 uint32_t vendor_id = readUint32(&data[offset], data.size());
819 offset += 4;
820 const OptionBuffer vendor_buffer(data.begin() + offset, data.end());
821 try {
822 offset += LibDHCP::unpackVendorOptions4(vendor_id, vendor_buffer,
823 vendors_data[vendor_id]);
824 } catch (const SkipThisOptionError&) {
825 // Ignore this kind of error and continue.
826 break;
827 } catch (const isc::Exception&) {
828 options.erase(DHO_VIVSO_SUBOPTIONS);
829 throw;
830 }
831 }
832 }
833 if (vendors_data.empty()) {
834 return;
835 }
836 // Delete the initial option.
837 options.erase(DHO_VIVSO_SUBOPTIONS);
838 // Create a new instance of OptionVendor for each enterprise ID.
839 for (auto const& vendor : vendors_data) {
840 OptionVendorPtr vendor_opt(new OptionVendor(Option::V4, vendor.first));
841 for (auto const& option : vendor.second) {
842 vendor_opt->addOption(option.second);
843 }
844 // Add the new instance of VendorOption with respective sub-options for
845 // this enterprise ID.
846 options.insert(std::make_pair(DHO_VIVSO_SUBOPTIONS, vendor_opt));
847 }
848}
849
850} // end of anonymous namespace.
851
852void
854 extendVivco(options);
855 extendVivso(options);
856}
857
858size_t
859LibDHCP::unpackVendorOptions6(const uint32_t vendor_id, const OptionBuffer& buf,
860 OptionCollection& options,
861 size_t rec_level /* = 0 */) {
862 ++rec_level;
863 if (rec_level >= MAX_RECURSION_LEVEL) {
865 "Too deep recursion in unpacking vendor options");
866 }
867 size_t offset = 0;
868 size_t length = buf.size();
869
870 // Get the list of option definitions for this particular vendor-id
871 const OptionDefContainerPtr& option_defs =
873
874 // Get the search index #1. It allows to search for option definitions
875 // using option code. If there's no such vendor-id space, we're out of luck
876 // anyway.
877 const OptionDefContainerTypeIndex* idx = 0;
878 if (option_defs) {
879 idx = &(option_defs->get<1>());
880 }
881
882 // The buffer being read comprises a set of options, each starting with
883 // a two-byte type code and a two-byte length field.
884 while (offset < length) {
885 if (offset + 4 > length) {
887 "Vendor option parse failed: truncated header");
888 }
889
890 uint16_t opt_type = readUint16(&buf[offset], 2);
891 offset += 2;
892
893 uint16_t opt_len = readUint16(&buf[offset], 2);
894 offset += 2;
895
896 if (offset + opt_len > length) {
898 "Vendor option parse failed. Tried to parse "
899 << offset + opt_len << " bytes from " << length
900 << "-byte long buffer.");
901 }
902
903 OptionPtr opt;
904 opt.reset();
905
906 // If there is a definition for such a vendor option...
907 if (idx) {
908 // Get all definitions with the particular option
909 // code. Note that option code is non-unique within this
910 // container however at this point we expect to get one
911 // option definition with the particular code. If more are
912 // returned we report an error.
913 const OptionDefContainerTypeRange& range =
914 idx->equal_range(opt_type);
915 // Get the number of returned option definitions for the
916 // option code.
917 size_t num_defs = std::distance(range.first, range.second);
918
919 if (num_defs > 1) {
920 // Multiple options of the same code are not supported
921 // right now!
922 isc_throw(isc::Unexpected, "Internal error: multiple option"
923 " definitions for option type " << opt_type <<
924 " returned. Currently it is not supported to"
925 " initialize multiple option definitions for the"
926 " same option code. This will be supported once"
927 " support for option spaces is implemented");
928 } else if (num_defs == 1) {
929 // The option definition has been found. Use it to create
930 // the option instance from the provided buffer chunk.
931 const OptionDefinitionPtr& def = *(range.first);
932 isc_throw_assert(def);
933 opt = def->optionFactory(Option::V6, opt_type,
934 buf.begin() + offset,
935 buf.begin() + offset + opt_len,
936 false, rec_level);
937 }
938 }
939
940 // This can happen in one of 2 cases:
941 // 1. we do not have definitions for that vendor-space
942 // 2. we do have definitions, but that particular option was
943 // not defined
944
945 if (!opt) {
946 opt = OptionPtr(new Option(Option::V6, opt_type,
947 buf.begin() + offset,
948 buf.begin() + offset + opt_len));
949 }
950
951 // add option to options
952 if (opt) {
953 options.insert(std::make_pair(opt_type, opt));
954 }
955 offset += opt_len;
956 }
957
958 return (offset);
959}
960
961size_t
962LibDHCP::unpackVendorOptions4(const uint32_t vendor_id, const OptionBuffer& buf,
963 OptionCollection& options) {
964 size_t offset = 0;
965
966 // Get the list of standard option definitions.
967 const OptionDefContainerPtr& option_defs =
969 // Get the search index #1. It allows to search for option definitions
970 // using option code.
971 const OptionDefContainerTypeIndex* idx = NULL;
972 if (option_defs) {
973 idx = &(option_defs->get<1>());
974 }
975
976 // The buffer being read comprises a set of options, each starting with
977 // a one-byte type code and a one-byte length field.
978 while (offset < buf.size()) {
979 // Note that Vendor-Specific info option (RFC3925) has a
980 // different option format than Vendor-Spec info for
981 // DHCPv6. (there's additional layer of data-length)
982 uint8_t data_len = buf[offset++];
983
984 if (offset + data_len > buf.size()) {
985 // The option is truncated.
987 "Attempt to parse truncated vendor option");
988 }
989
990 uint8_t offset_end = offset + data_len;
991
992 // beginning of data-chunk parser
993 while (offset < offset_end) {
994 uint8_t opt_type = buf[offset++];
995
996 // No DHO_END or DHO_PAD in vendor options
997
998 if (offset + 1 > offset_end) {
999 // opt_type must be cast to integer so as it is not
1000 // treated as unsigned char value (a number is
1001 // presented in error message).
1003 "Attempt to parse truncated vendor option "
1004 << static_cast<int>(opt_type));
1005 }
1006
1007 uint8_t opt_len = buf[offset++];
1008 if (offset + opt_len > offset_end) {
1010 "Option parse failed. Tried to parse "
1011 << offset + opt_len << " bytes from " << buf.size()
1012 << "-byte long buffer.");
1013 }
1014
1015 OptionPtr opt;
1016 opt.reset();
1017
1018 if (idx) {
1019 // Get all definitions with the particular option
1020 // code. Note that option code is non-unique within
1021 // this container however at this point we expect to
1022 // get one option definition with the particular
1023 // code. If more are returned we report an error.
1024 const OptionDefContainerTypeRange& range =
1025 idx->equal_range(opt_type);
1026 // Get the number of returned option definitions for
1027 // the option code.
1028 size_t num_defs = std::distance(range.first, range.second);
1029
1030 if (num_defs > 1) {
1031 // Multiple options of the same code are not
1032 // supported right now!
1033 isc_throw(isc::Unexpected, "Internal error: multiple"
1034 " option definitions for option type "
1035 << opt_type << " returned. Currently it is"
1036 " not supported to initialize multiple option"
1037 " definitions for the same option code."
1038 " This will be supported once support for"
1039 " option spaces is implemented");
1040 } else if (num_defs == 1) {
1041 // The option definition has been found. Use it to create
1042 // the option instance from the provided buffer chunk.
1043 const OptionDefinitionPtr& def = *(range.first);
1044 isc_throw_assert(def);
1045 opt = def->optionFactory(Option::V4, opt_type,
1046 buf.begin() + offset,
1047 buf.begin() + offset + opt_len);
1048 }
1049 }
1050
1051 if (!opt) {
1052 opt = OptionPtr(new Option(Option::V4, opt_type,
1053 buf.begin() + offset,
1054 buf.begin() + offset + opt_len));
1055 }
1056
1057 options.insert(std::make_pair(opt_type, opt));
1058 offset += opt_len;
1059
1060 } // end of data-chunk
1061
1062 break; // end of the vendor block.
1063 }
1064 return (offset);
1065}
1066
1067void
1069 bool top, bool check) {
1070 OptionCollection agent;
1071 OptionPtr end;
1072
1073 // We only look for type when we're the top level
1074 // call that starts packing for options for a packet.
1075 // This way we avoid doing type logic in all ensuing
1076 // recursive calls.
1077 if (top) {
1078 auto x = options.find(DHO_DHCP_MESSAGE_TYPE);
1079 if (x != options.end()) {
1080 x->second->pack(buf, check);
1081 }
1082 }
1083
1084 for (auto const& option : options) {
1085 // TYPE is already done, RAI and END options must be last.
1086 switch (option.first) {
1088 break;
1090 agent.insert(make_pair(DHO_DHCP_AGENT_OPTIONS, option.second));
1091 break;
1092 case DHO_END:
1093 end = option.second;
1094 break;
1095 default:
1096 option.second->pack(buf, check);
1097 break;
1098 }
1099 }
1100
1101 // Add the RAI option if it exists.
1102 for (auto const& option : agent) {
1103 option.second->pack(buf, check);
1104 }
1105
1106 // And at the end the END option.
1107 if (end) {
1108 end->pack(buf, check);
1109 }
1110}
1111
1112bool
1114 ScopedOptionsCopyContainer& scoped_options,
1115 uint32_t used) {
1116 bool result = false;
1117 // We need to loop until all options have been split.
1118 uint32_t tries = 0;
1119 for (;; tries++) {
1120 // Let's not do this forever if there is a bug hiding here somewhere...
1121 // 65535 times should be enough for any packet load...
1122 if (tries == std::numeric_limits<uint16_t>::max()) {
1123 isc_throw(Unexpected, "packet split failed after trying "
1124 << tries << " times.");
1125 }
1126 bool found = false;
1127 // Make a copy of the options so we can safely iterate over the
1128 // old container.
1129 OptionCollection copy = options;
1130 // Iterate over all options in the container.
1131 for (auto const& option : options) {
1132 OptionPtr candidate = option.second;
1133 OptionCollection& sub_options = candidate->getMutableOptions();
1134 // Split suboptions recursively, if any.
1135 OptionCollection distinct_options;
1136 bool updated = false;
1137 bool found_suboptions = false;
1138 // There are 3 cases when the total size is larger than (255 - used):
1139 // 1. option has no suboptions and has large data
1140 // 2. option has large suboptions and has no data
1141 // 3. option has both options and suboptions:
1142 // 3.1. suboptions are large and data is large
1143 // 3.2. suboptions are large and data is small
1144 // 3.3. suboptions are small and data is large
1145 // 3.4. suboptions are small and data is small but combined they are large
1146 // All other combinations reside in total size smaller than (255 - used):
1147 // 4. no split of any suboption or data:
1148 // 4.1 option has no suboptions and has small data
1149 // 4.2 option has small suboptions and has no data
1150 // 4.3 option has both small suboptions and small data
1151 // 4.4 option has no suboptions and has no data
1152 if (sub_options.size()) {
1153 // The 2. and 3. and 4.2 and 4.3 cases are handled here (the suboptions part).
1154 ScopedOptionsCopyPtr candidate_scoped_options(new ScopedSubOptionsCopy(candidate));
1155 found_suboptions = LibDHCP::splitOptions4(sub_options, scoped_options,
1156 used + candidate->getHeaderLen());
1157 // There are 3 cases here:
1158 // 2. option has large suboptions and has no data
1159 // 3. option has both options and suboptions:
1160 // 3.1. suboptions are large and data is large so there is suboption splitting
1161 // and found_suboptions is true
1162 // 3.2. suboptions are large and data is small so there is suboption splitting
1163 // and found_suboptions is true
1164 // 3.3. suboptions are small and data is large so there is no suboption splitting
1165 // and found_suboptions is false
1166 // 3.4. suboptions are small and data is small so there is no suboption splitting
1167 // and found_suboptions is false but combined they are large
1168 // 4. no split of any suboption or data
1169 // Also split if the overflow is caused by adding the suboptions
1170 // to the option data.
1171 if (found_suboptions || candidate->len() > (255 - used)) {
1172 // The 2. and 3. cases are handled here (the suboptions part).
1173 updated = true;
1174 scoped_options.push_back(candidate_scoped_options);
1175 // Erase the old options from the new container so that only
1176 // the new options are present.
1177 copy.erase(option.first);
1178 result = true;
1179 // If there are suboptions which have been split, one parent
1180 // option will be created for each of the chunk of the
1181 // suboptions. If the suboptions have not been split,
1182 // but they cause overflow when added to the option data,
1183 // one parent option will contain the option data and one
1184 // parent option will be created for each suboption.
1185 // This will guarantee that none of the options plus
1186 // suboptions will have more than 255 bytes.
1187 for (auto const& sub_option : candidate->getMutableOptions()) {
1188 OptionPtr data_sub_option(new Option(candidate->getUniverse(),
1189 candidate->getType(),
1190 OptionBuffer(0)));
1191 data_sub_option->addOption(sub_option.second);
1192 distinct_options.insert(make_pair(candidate->getType(), data_sub_option));
1193 }
1194 }
1195 }
1196 // The 1. and 3. and 4. cases are handled here (the data part).
1197 // Create a new option containing only data that needs to be split
1198 // and no suboptions (which are inserted in completely separate
1199 // options which are added at the end).
1200 OptionPtr data_option(new Option(candidate->getUniverse(),
1201 candidate->getType(),
1202 OptionBuffer(candidate->getData().begin(),
1203 candidate->getData().end())));
1204 OutputBuffer buf(0);
1205 data_option->pack(buf, false);
1206 uint32_t header_len = candidate->getHeaderLen();
1207 // At least 1 + header length bytes must be available.
1208 if (used >= 255 - header_len) {
1209 isc_throw(BadValue, "there is no space left to split option "
1210 << candidate->getType() << " after parent already used "
1211 << used);
1212 }
1213 // Maximum option buffer size is 255 - header size - buffer size
1214 // already used by parent options.
1215 uint8_t len = 255 - header_len - used;
1216 // Current option size after split is the sum of the data and the
1217 // header size. The suboptions are serialized in separate options.
1218 // The header is duplicated in all new options, but the rest of the
1219 // data must be split and serialized.
1220 uint32_t size = buf.getLength() - header_len;
1221 // Only split if data does not fit in the current option.
1222 // There are 3 cases here:
1223 // 1. option has no suboptions and has large data
1224 // 3. option has both options and suboptions:
1225 // 3.1. suboptions are large and data is large
1226 // 3.2. suboptions are large and data is small
1227 // 3.3. suboptions are small and data is large
1228 // 3.4. suboptions are small and data is small but combined they are large
1229 // 4. no split of any suboption or data
1230 if (size > len) {
1231 // The 1. and 3.1. and 3.3 cases are handled here (the data part).
1232 // Erase the old option from the new container so that only new
1233 // options are present.
1234 if (!updated) {
1235 updated = true;
1236 // Erase the old options from the new container so that only
1237 // the new options are present.
1238 copy.erase(option.first);
1239 result = true;
1240 }
1241 uint32_t offset = 0;
1242 // Drain the option buffer in multiple new options until all
1243 // data is serialized.
1244 for (; offset != size;) {
1245 // Adjust the data length of the new option if remaining
1246 // data is less than the 255 - header size (for the last
1247 // option).
1248 if (size - offset < len) {
1249 len = size - offset;
1250 }
1251 // Create new option with data starting from offset and
1252 // containing truncated length.
1253 const uint8_t* data = buf.getData();
1254 data += header_len;
1255 OptionPtr new_option(new Option(candidate->getUniverse(),
1256 candidate->getType(),
1257 OptionBuffer(data + offset,
1258 data + offset + len)));
1259 // Adjust the offset for remaining data to be written to the
1260 // next new option.
1261 offset += len;
1262 // Add the new option to the new container.
1263 copy.insert(make_pair(candidate->getType(), new_option));
1264 }
1265 } else if ((candidate->len() > (255 - used)) && size) {
1266 // The 3.2 and 3.4 cases are handled here (the data part).
1267 // Also split if the overflow is caused by adding the suboptions
1268 // to the option data (which should be of non zero size).
1269 // Add the new option to the new container.
1270 copy.insert(make_pair(candidate->getType(), data_option));
1271 }
1272 if (updated) {
1273 // Add the new options containing the split suboptions, if any,
1274 // to the new container.
1275 copy.insert(distinct_options.begin(), distinct_options.end());
1276 // After all new options have been split and added, update the
1277 // option container with the new container.
1278 options = copy;
1279 // Other options might need splitting, so we need to iterate
1280 // again until no option needs splitting.
1281 found = true;
1282 break;
1283 }
1284 }
1285 // No option needs splitting, so we can exit the loop.
1286 if (!found) {
1287 break;
1288 }
1289 }
1290 return (result);
1291}
1292
1293void
1295 for (auto const& option : options) {
1296 option.second->pack(buf);
1297 }
1298}
1299
1300void
1302 pair<OptionCollection::const_iterator, OptionCollection::const_iterator>
1303 range = options.equal_range(D6O_NTP_SERVER);
1304 if (range.first == range.second) {
1305 return;
1306 }
1307 auto const& ntp_servers = OptionCollection(range.first, range.second);
1308 static_cast<void>(options.erase(range.first, range.second));
1309 auto const& def = D6O_NTP_SERVER_DEF();
1310 for (auto const& opt : ntp_servers) {
1311 for (auto const& sub : opt.second->getOptions()) {
1312 auto new_option(new OptionCustom(def, Option::V6));
1313 new_option->addOption(sub.second);
1314 options.insert(make_pair(D6O_NTP_SERVER, new_option));
1315 }
1316 }
1317}
1318
1319void
1321 Option::Factory* factory) {
1322 switch (u) {
1323 case Option::V6:
1324 {
1325 if (v6factories_.find(opt_type) != v6factories_.end()) {
1326 isc_throw(BadValue, "There is already DHCPv6 factory registered "
1327 << "for option type " << opt_type);
1328 }
1329 v6factories_[opt_type] = factory;
1330 return;
1331 }
1332 case Option::V4:
1333 {
1334 // Option 0 is special (a one octet-long, equal 0) PAD option. It is never
1335 // instantiated as an Option object, but rather consumed during packet parsing.
1336 if (opt_type == 0) {
1337 isc_throw(BadValue, "Cannot redefine PAD option (code=0)");
1338 }
1339 // Option 255 is never instantiated as an option object. It is special
1340 // (a one-octet equal 255) option that is added at the end of all options
1341 // during packet assembly. It is also silently consumed during packet parsing.
1342 if (opt_type > 254) {
1343 isc_throw(BadValue, "Too big option type for DHCPv4, only 0-254 allowed.");
1344 }
1345 if (v4factories_.find(opt_type) != v4factories_.end()) {
1346 isc_throw(BadValue, "There is already DHCPv4 factory registered "
1347 << "for option type " << opt_type);
1348 }
1349 v4factories_[opt_type] = factory;
1350 return;
1351 }
1352 default:
1353 isc_throw(BadValue, "Invalid universe type specified.");
1354 }
1355
1356 return;
1357}
1358
1359bool
1360LibDHCP::initOptionDefs() {
1361 for (uint32_t i = 0; OPTION_DEF_PARAMS[i].optionDefParams; ++i) {
1362 string space = OPTION_DEF_PARAMS[i].space;
1363 option_defs_[space] = OptionDefContainerPtr(new OptionDefContainer());
1364 initOptionSpace(option_defs_[space],
1365 OPTION_DEF_PARAMS[i].optionDefParams,
1366 OPTION_DEF_PARAMS[i].size);
1367 }
1368
1369 static_cast<void>(LibDHCP::DHO_DHCP_REQUESTED_ADDRESS_DEF());
1370 static_cast<void>(LibDHCP::DHO_DHCP_SERVER_IDENTIFIER_DEF());
1371 static_cast<void>(LibDHCP::DHO_DHCP_AGENT_OPTIONS_DEF());
1372 static_cast<void>(LibDHCP::DHO_SUBNET_SELECTION_DEF());
1373 static_cast<void>(LibDHCP::DHO_DOMAIN_SEARCH_DEF());
1374 static_cast<void>(LibDHCP::DHO_STATUS_CODE_DEF());
1375 static_cast<void>(LibDHCP::D6O_CLIENT_FQDN_DEF());
1376 static_cast<void>(LibDHCP::D6O_LQ_QUERY_DEF());
1377 static_cast<void>(LibDHCP::D6O_CLIENT_DATA_DEF());
1378 static_cast<void>(LibDHCP::D6O_LQ_RELAY_DATA_DEF());
1379 static_cast<void>(LibDHCP::D6O_NTP_SERVER_DEF());
1380 static_cast<void>(LibDHCP::D6O_BOOTFILE_URL_DEF());
1381 static_cast<void>(LibDHCP::D6O_RSOO_DEF());
1382 static_cast<void>(LibDHCP::D6O_IAADDR_DEF());
1383
1384 return (true);
1385}
1386
1387uint32_t
1388LibDHCP::optionSpaceToVendorId(const string& option_space) {
1389 // 8 is a minimal length of "vendor-X" format
1390 if ((option_space.size() < 8) || (option_space.substr(0,7) != "vendor-")) {
1391 return (0);
1392 }
1393
1394 int64_t check;
1395 try {
1396 // text after "vendor-", supposedly numbers only
1397 string x = option_space.substr(7);
1398
1399 check = boost::lexical_cast<int64_t>(x);
1400 } catch (const boost::bad_lexical_cast &) {
1401 return (0);
1402 }
1403
1404 if ((check < 0) || (check > std::numeric_limits<uint32_t>::max())) {
1405 return (0);
1406 }
1407
1408 // value is small enough to fit
1409 return (static_cast<uint32_t>(check));
1410}
1411
1412void
1414 size_t params_size) {
1415 // Container holding vendor options is typically not initialized, as it
1416 // is held in map of null pointers. We need to initialize here in this
1417 // case.
1418 if (!defs) {
1419 defs.reset(new OptionDefContainer());
1420 } else {
1421 defs->clear();
1422 }
1423
1424 for (size_t i = 0; i < params_size; ++i) {
1425 string encapsulates(params[i].encapsulates);
1426 if (!encapsulates.empty() && params[i].array) {
1427 isc_throw(isc::BadValue, "invalid standard option definition: "
1428 << "option with code '" << params[i].code
1429 << "' may not encapsulate option space '"
1430 << encapsulates << "' because the definition"
1431 << " indicates that this option comprises an array"
1432 << " of values");
1433 }
1434
1435 // Depending whether an option encapsulates an option space or not
1436 // we pick different constructor to create an instance of the option
1437 // definition.
1438 OptionDefinitionPtr definition;
1439 if (encapsulates.empty()) {
1440 // Option does not encapsulate any option space.
1441 definition.reset(new OptionDefinition(params[i].name,
1442 params[i].code,
1443 params[i].space,
1444 params[i].type,
1445 params[i].array));
1446 } else {
1447 // Option does encapsulate an option space.
1448 definition.reset(new OptionDefinition(params[i].name,
1449 params[i].code,
1450 params[i].space,
1451 params[i].type,
1452 params[i].encapsulates));
1453
1454 }
1455
1456 for (size_t rec = 0; rec < params[i].records_size; ++rec) {
1457 definition->addRecordField(params[i].records[rec]);
1458 }
1459
1460 try {
1461 definition->validate();
1462 } catch (const isc::Exception&) {
1463 // This is unlikely event that validation fails and may
1464 // be only caused by programming error. To guarantee the
1465 // data consistency we clear all option definitions that
1466 // have been added so far and pass the exception forward.
1467 defs->clear();
1468 throw;
1469 }
1470
1471 // option_defs is a multi-index container with no unique indexes
1472 // so push_back can't fail).
1473 static_cast<void>(defs->push_back(definition));
1474 }
1475}
1476
1477const OptionDefinition&
1479 static OptionDefinitionPtr def =
1481 static bool check_once(true);
1482 if (check_once) {
1483 isc_throw_assert(def);
1484 isc_throw_assert(def->getName() == "dhcp-requested-address");
1486 isc_throw_assert(def->getType() == OPT_IPV4_ADDRESS_TYPE);
1487 isc_throw_assert(!def->getArrayType());
1488 isc_throw_assert(def->getEncapsulatedSpace().empty());
1489 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1490 check_once = false;
1491 }
1492 return (*def);
1493}
1494
1495const OptionDefinition&
1497 static OptionDefinitionPtr def =
1499 static bool check_once(true);
1500 if (check_once) {
1501 isc_throw_assert(def);
1502 isc_throw_assert(def->getName() == "dhcp-server-identifier");
1504 isc_throw_assert(def->getType() == OPT_IPV4_ADDRESS_TYPE);
1505 isc_throw_assert(!def->getArrayType());
1506 isc_throw_assert(def->getEncapsulatedSpace().empty());
1507 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1508 check_once = false;
1509 }
1510 return (*def);
1511}
1512
1513const OptionDefinition&
1515 static OptionDefinitionPtr def =
1517 static bool check_once(true);
1518 if (check_once) {
1519 isc_throw_assert(def);
1520 isc_throw_assert(def->getName() == "dhcp-agent-options");
1521 isc_throw_assert(def->getCode() == DHO_DHCP_AGENT_OPTIONS);
1522 isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
1523 isc_throw_assert(!def->getArrayType());
1524 isc_throw_assert(def->getEncapsulatedSpace() == DHCP_AGENT_OPTION_SPACE);
1525 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1526 check_once = false;
1527 }
1528 return (*def);
1529}
1530
1531const OptionDefinition&
1533 static OptionDefinitionPtr def =
1535 static bool check_once(true);
1536 if (check_once) {
1537 isc_throw_assert(def);
1538 isc_throw_assert(def->getName() == "subnet-selection");
1539 isc_throw_assert(def->getCode() == DHO_SUBNET_SELECTION);
1540 isc_throw_assert(def->getType() == OPT_IPV4_ADDRESS_TYPE);
1541 isc_throw_assert(!def->getArrayType());
1542 isc_throw_assert(def->getEncapsulatedSpace().empty());
1543 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1544 check_once = false;
1545 }
1546 return (*def);
1547}
1548
1549const OptionDefinition&
1551 static OptionDefinitionPtr def =
1553 static bool check_once(true);
1554 if (check_once) {
1555 isc_throw_assert(def);
1556 isc_throw_assert(def->getName() == "domain-search");
1557 isc_throw_assert(def->getCode() == DHO_DOMAIN_SEARCH);
1558 isc_throw_assert(def->getType() == OPT_FQDN_TYPE);
1559 isc_throw_assert(def->getArrayType());
1560 isc_throw_assert(def->getEncapsulatedSpace().empty());
1561 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1562 check_once = false;
1563 }
1564 return (*def);
1565}
1566
1567const OptionDefinition&
1569 static OptionDefinitionPtr def =
1571 static bool check_once(true);
1572 if (check_once) {
1573 isc_throw_assert(def);
1574 isc_throw_assert(def->getName() == "status-code");
1575 isc_throw_assert(def->getCode() == DHO_STATUS_CODE);
1576 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1577 isc_throw_assert(!def->getArrayType());
1578 isc_throw_assert(def->getEncapsulatedSpace().empty());
1579 isc_throw_assert(def->getOptionSpaceName() == DHCP4_OPTION_SPACE);
1580 check_once = false;
1581 }
1582 return (*def);
1583}
1584
1585const OptionDefinition&
1587 static OptionDefinitionPtr def =
1589 static bool check_once(true);
1590 if (check_once) {
1591 isc_throw_assert(def);
1592 isc_throw_assert(def->getName() == "client-fqdn");
1593 isc_throw_assert(def->getCode() == D6O_CLIENT_FQDN);
1594 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1595 isc_throw_assert(!def->getArrayType());
1596 isc_throw_assert(def->getEncapsulatedSpace().empty());
1597 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1598 check_once = false;
1599 }
1600 return (*def);
1601}
1602
1603const OptionDefinition&
1605 static OptionDefinitionPtr def =
1607 static bool check_once(true);
1608 if (check_once) {
1609 isc_throw_assert(def);
1610 isc_throw_assert(def->getName() == "lq-query");
1611 isc_throw_assert(def->getCode() == D6O_LQ_QUERY);
1612 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1613 isc_throw_assert(!def->getArrayType());
1614 isc_throw_assert(def->getEncapsulatedSpace() == DHCP6_OPTION_SPACE);
1615 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1616 check_once = false;
1617 }
1618 return (*def);
1619}
1620
1621const OptionDefinition&
1623 static OptionDefinitionPtr def =
1625 static bool check_once(true);
1626 if (check_once) {
1627 isc_throw_assert(def);
1628 isc_throw_assert(def->getName() == "client-data");
1629 isc_throw_assert(def->getCode() == D6O_CLIENT_DATA);
1630 isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
1631 isc_throw_assert(!def->getArrayType());
1632 isc_throw_assert(def->getEncapsulatedSpace() == DHCP6_OPTION_SPACE);
1633 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1634 check_once = false;
1635 }
1636 return (*def);
1637}
1638
1639const OptionDefinition&
1641 static OptionDefinitionPtr def =
1643 static bool check_once(true);
1644 if (check_once) {
1645 isc_throw_assert(def);
1646 isc_throw_assert(def->getName() == "lq-relay-data");
1647 isc_throw_assert(def->getCode() == D6O_LQ_RELAY_DATA);
1648 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1649 isc_throw_assert(!def->getArrayType());
1650 isc_throw_assert(def->getEncapsulatedSpace().empty());
1651 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1652 check_once = false;
1653 }
1654 return (*def);
1655}
1656
1657const OptionDefinition&
1659 static OptionDefinitionPtr def =
1661 static bool check_once(true);
1662 if (check_once) {
1663 isc_throw_assert(def);
1664 isc_throw_assert(def->getName() == "ntp-server");
1665 isc_throw_assert(def->getCode() == D6O_NTP_SERVER);
1666 isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
1667 isc_throw_assert(!def->getArrayType());
1668 isc_throw_assert(def->getEncapsulatedSpace() == V6_NTP_SERVER_SPACE);
1669 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1670 check_once = false;
1671 }
1672 return (*def);
1673}
1674
1675const OptionDefinition&
1677 static OptionDefinitionPtr def =
1679 static bool check_once(true);
1680 if (check_once) {
1681 isc_throw_assert(def);
1682 isc_throw_assert(def->getName() == "bootfile-url");
1683 isc_throw_assert(def->getCode() == D6O_BOOTFILE_URL);
1684 isc_throw_assert(def->getType() == OPT_STRING_TYPE);
1685 isc_throw_assert(!def->getArrayType());
1686 isc_throw_assert(def->getEncapsulatedSpace().empty());
1687 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1688 check_once = false;
1689 }
1690 return (*def);
1691}
1692
1693const OptionDefinition&
1695 static OptionDefinitionPtr def =
1697 static bool check_once(true);
1698 if (check_once) {
1699 isc_throw_assert(def);
1700 isc_throw_assert(def->getName() == "rsoo");
1701 isc_throw_assert(def->getCode() == D6O_RSOO);
1702 isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
1703 isc_throw_assert(!def->getArrayType());
1704 isc_throw_assert(def->getEncapsulatedSpace() == "rsoo-opts");
1705 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1706 check_once = false;
1707 }
1708 return (*def);
1709}
1710
1711const OptionDefinition&
1713 static OptionDefinitionPtr def =
1715 static bool check_once(true);
1716 if (check_once) {
1717 isc_throw_assert(def);
1718 isc_throw_assert(def->getName() == "iaaddr");
1719 isc_throw_assert(def->getCode() == D6O_IAADDR);
1720 isc_throw_assert(def->getType() == OPT_RECORD_TYPE);
1721 isc_throw_assert(!def->getArrayType());
1722 isc_throw_assert(def->getEncapsulatedSpace().empty());
1723 isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
1724 check_once = false;
1725 }
1726 return (*def);
1727}
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
static size_t unpackOptions4(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, std::list< uint16_t > &deferred, bool flexible_pad_end=false)
Parses provided buffer as DHCPv4 options and creates Option objects.
Definition libdhcp++.cc:485
static void OptionFactoryRegister(Option::Universe u, uint16_t type, Option::Factory *factory)
Registers factory method that produces options of specific option types.
static const OptionDefinition & D6O_LQ_RELAY_DATA_DEF()
Get definition of D6O_LQ_RELAY_DATA option.
static const OptionDefinition & D6O_NTP_SERVER_DEF()
Get definition of D6O_NTP_SERVER option.
static const OptionDefinition & D6O_RSOO_DEF()
Get definition of D6O_RSOO option.
static size_t MAX_RECURSION_LEVEL
Maximum level of recursion unpacking options.
Definition libdhcp++.h:499
static const OptionDefContainerPtr getOptionDefs(const std::string &space)
Returns collection of option definitions.
Definition libdhcp++.cc:105
static void splitNtpServerOptions6(isc::dhcp::OptionCollection &options)
Split NTP server option to one suboption per instance.
static bool shouldDeferOptionUnpack(const std::string &space, const uint16_t code)
Checks if an option unpacking has to be deferred.
Definition libdhcp++.cc:286
static isc::dhcp::OptionPtr optionFactory(isc::dhcp::Option::Universe u, uint16_t type, const OptionBuffer &buf)
Factory function to create instance of option.
Definition libdhcp++.cc:293
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
Definition libdhcp++.cc:224
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition libdhcp++.cc:132
static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id, const uint16_t code)
Returns vendor option definition for a given vendor-id and code.
Definition libdhcp++.cc:174
static size_t unpackOptions6(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, size_t *relay_msg_offset=0, size_t *relay_msg_len=0, size_t rec_level=0)
Parses provided buffer as DHCPv6 options and creates Option objects.
Definition libdhcp++.cc:320
static OptionDefContainerPtr getLastResortOptionDefs(const std::string &space)
Returns last resort option definitions for specified option space name.
Definition libdhcp++.cc:277
static const OptionDefinition & D6O_LQ_QUERY_DEF()
Get definition of D6O_LQ_QUERY option.
static OptionDefContainerPtr getRuntimeOptionDefs(const std::string &space)
Returns runtime (non-standard) option definitions for specified option space name.
Definition libdhcp++.cc:219
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition libdhcp++.cc:248
static void clearRuntimeOptionDefs()
Removes runtime option definitions.
Definition libdhcp++.cc:238
static const OptionDefinition & D6O_IAADDR_DEF()
Get definition of D6O_IAADDR option.
static void extendVendorOptions4(isc::dhcp::OptionCollection &options)
Extend vendor options from fused options in multiple OptionVendor or OptionVendorClass options and ad...
Definition libdhcp++.cc:853
static const OptionDefinition & D6O_CLIENT_DATA_DEF()
Get definition of D6O_CLIENT_DATA option.
static void sanityCheckScalarLength(const OptionDefinitionPtr &def, uint16_t opt_len)
Validates a scalar option's length against it's defined length.
Definition libdhcp++.cc:721
static void packOptions4(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options, bool top=false, bool check=true)
Stores DHCPv4 options in a buffer.
static size_t unpackVendorOptions6(const uint32_t vendor_id, const OptionBuffer &buf, isc::dhcp::OptionCollection &options, size_t rec_level=0)
Parses provided buffer as DHCPv6 vendor options and creates Option objects.
Definition libdhcp++.cc:859
static bool splitOptions4(isc::dhcp::OptionCollection &options, ScopedOptionsCopyContainer &scopedOptions, uint32_t used=0)
Split long options in multiple options with the same option code (RFC3396).
static const OptionDefinition & DHO_DHCP_REQUESTED_ADDRESS_DEF()
Get definition of DHO_DHCP_REQUESTED_ADDRESS option.
static const OptionDefinition & D6O_BOOTFILE_URL_DEF()
Get definition of D6O_BOOTFILE_URL option.
static const OptionDefinition & DHO_DHCP_SERVER_IDENTIFIER_DEF()
Get definition of DHO_DHCP_SERVER_IDENTIFIER option.
static const OptionDefinition & DHO_SUBNET_SELECTION_DEF()
Get definition of DHO_SUBNET_SELECTION option.
static void revertRuntimeOptionDefs()
Reverts uncommitted changes to runtime option definitions.
Definition libdhcp++.cc:243
static const OptionDefinition & DHO_DOMAIN_SEARCH_DEF()
Get definition of DHO_DOMAIN_SEARCH option.
static const OptionDefContainerPtr getVendorOptionDefs(Option::Universe u, const uint32_t vendor_id)
Returns option definitions for given universe and vendor.
Definition libdhcp++.cc:115
static const OptionDefinition & D6O_CLIENT_FQDN_DEF()
Get definition of D6O_CLIENT_FQDN option.
static const OptionDefinition & DHO_DHCP_AGENT_OPTIONS_DEF()
Get definition of DHO_DHCP_AGENT_OPTIONS option.
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
static OptionDefinitionPtr getRuntimeOptionDef(const std::string &space, const uint16_t code)
Returns runtime (non-standard) option definition by space and option code.
Definition libdhcp++.cc:195
static void packOptions6(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options)
Stores DHCPv6 options in a buffer.
static const OptionDefinition & DHO_STATUS_CODE_DEF()
Get definition of DHO_STATUS_CODE option.
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition libdhcp++.cc:253
static size_t unpackVendorOptions4(const uint32_t vendor_id, const OptionBuffer &buf, isc::dhcp::OptionCollection &options)
Parses provided buffer as DHCPv4 vendor options and creates Option objects.
Definition libdhcp++.cc:962
Exception to be thrown when the operation on OpaqueDataTuple object results in an error.
Represents a single instance of the opaque data preceded by length.
Option with defined data fields represented as buffers that can be accessed using data field index.
static const std::string & getDataTypeName(const OptionDataType data_type)
Return option data type name from the data type enumerator.
static int getDataTypeLen(const OptionDataType data_type)
Get data type buffer length.
Class of option definition space container.
void addItem(const OptionDefinitionPtr &def)
Adds a new option definition to the container.
Base class representing a DHCP option definition.
Wrapper exception thrown by unpackOptionsX functions to add option type and len to the underlying err...
Definition option.h:75
std::list< Selector > getOptionSpaceNames() const
Get a list of existing option spaces.
ItemsContainerPtr getItems(const Selector &option_space) const
Get all items for the particular option space.
This class encapsulates DHCPv6 Vendor Class and DHCPv4 V-I Vendor Class options.
This class represents vendor-specific information option.
static bool lenient_parsing_
Governs whether options should be parsed less strictly.
Definition option.h:490
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:90
OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer &buf)
a factory function prototype
Definition option.h:103
RAII object enabling duplication of the stored options and restoring the original options on destruct...
Definition pkt.h:1019
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Definition option.h:52
Exception thrown during option unpacking This exception is thrown when an error has occurred unpackin...
Definition option.h:67
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:355
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition buffer.h:407
size_t getLength() const
Return the length of data written in the buffer.
Definition buffer.h:421
This class implements set/commit mechanism for a single object.
@ D6O_CLIENT_FQDN
Definition dhcp6.h:59
@ D6O_RSOO
Definition dhcp6.h:86
@ D6O_RELAY_MSG
Definition dhcp6.h:29
@ D6O_VENDOR_OPTS
Definition dhcp6.h:37
@ D6O_BOOTFILE_URL
Definition dhcp6.h:79
@ D6O_LQ_QUERY
Definition dhcp6.h:64
@ D6O_IAADDR
Definition dhcp6.h:25
@ D6O_CLIENT_DATA
Definition dhcp6.h:65
@ D6O_LQ_RELAY_DATA
Definition dhcp6.h:67
@ D6O_NTP_SERVER
Definition dhcp6.h:76
#define DOCSIS3_V6_OPTION_SPACE
#define VENDOR_ID_CABLE_LABS
#define DOCSIS3_V4_OPTION_SPACE
global docsis3 option spaces
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition isc_assert.h:18
void initOptionSpace(OptionDefContainerPtr &defs, const OptionDefParams *params, size_t params_size)
const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer())
ElementPtr copy(ConstElementPtr from, unsigned level)
Copy the data up to a nesting level.
Definition data.cc:1543
boost::shared_ptr< OptionVendor > OptionVendorPtr
Pointer to a vendor option.
@ DHO_DHCP_MESSAGE_TYPE
Definition dhcp4.h:122
@ DHO_DHCP_SERVER_IDENTIFIER
Definition dhcp4.h:123
@ DHO_HOST_NAME
Definition dhcp4.h:81
@ DHO_VIVCO_SUBOPTIONS
Definition dhcp4.h:188
@ DHO_DHCP_REQUESTED_ADDRESS
Definition dhcp4.h:119
@ DHO_END
Definition dhcp4.h:229
@ DHO_PAD
Definition dhcp4.h:69
@ DHO_DHCP_AGENT_OPTIONS
Definition dhcp4.h:151
@ DHO_VENDOR_ENCAPSULATED_OPTIONS
Definition dhcp4.h:112
@ DHO_SUBNET_SELECTION
Definition dhcp4.h:182
@ DHO_DOMAIN_SEARCH
Definition dhcp4.h:183
@ DHO_VIVSO_SUBOPTIONS
Definition dhcp4.h:189
@ DHO_STATUS_CODE
Definition dhcp4.h:205
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition option.h:40
const OptionDefParams DOCSIS3_V4_OPTION_DEFINITIONS[]
Definitions of standard DHCPv4 options.
const char * DOCSIS3_CLASS_EROUTER
The class as specified in vendor-class option by the devices.
Definition libdhcp++.cc:94
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
const int DOCSIS3_V6_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
std::pair< OptionDefContainerNameIndex::const_iterator, OptionDefContainerNameIndex::const_iterator > OptionDefContainerNameRange
Pair of iterators to represent the range of options definitions having the same option name.
const char * DOCSIS3_CLASS_MODEM
DOCSIS3.0 compatible cable modem.
Definition libdhcp++.cc:91
boost::shared_ptr< OptionVendorClass > OptionVendorClassPtr
Defines a pointer to the OptionVendorClass.
std::map< std::string, OptionDefContainerPtr > OptionDefContainers
Container that holds option definitions for various option spaces.
std::shared_ptr< ScopedSubOptionsCopy > ScopedOptionsCopyPtr
A pointer to a ScopedSubOptionsCopy object.
Definition libdhcp++.h:30
OptionDefContainer::nth_index< 2 >::type OptionDefContainerNameIndex
Type of the index #2 - option name.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
std::pair< OptionDefContainerTypeIndex::const_iterator, OptionDefContainerTypeIndex::const_iterator > OptionDefContainerTypeRange
Pair of iterators to represent the range of options definitions having the same option type value.
boost::multi_index_container< OptionDefinitionPtr, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::hashed_non_unique< boost::multi_index::const_mem_fun< OptionDefinition, uint16_t, &OptionDefinition::getCode > >, boost::multi_index::hashed_non_unique< boost::multi_index::const_mem_fun< OptionDefinition, std::string, &OptionDefinition::getName > >, boost::multi_index::ordered_non_unique< boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::StampedElement::getModificationTime > >, boost::multi_index::hashed_non_unique< boost::multi_index::tag< OptionIdIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, uint64_t, &data::BaseStampedElement::getId > > > > OptionDefContainer
Multi index container for DHCP option definitions.
const int DOCSIS3_V4_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
OptionDefContainer::nth_index< 1 >::type OptionDefContainerTypeIndex
Type of the index #1 - option type.
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
std::vector< ScopedOptionsCopyPtr > ScopedOptionsCopyContainer
A container of ScopedOptionsCopyPtr objects.
Definition libdhcp++.h:32
const OptionDefParams DOCSIS3_V6_OPTION_DEFINITIONS[]
Definitions of standard DHCPv6 options.
boost::shared_ptr< OptionDefContainer > OptionDefContainerPtr
Pointer to an option definition container.
uint16_t readUint16(void const *const buffer, size_t const length)
uint16_t wrapper over readUint.
Definition io.h:76
uint32_t readUint32(void const *const buffer, size_t const length)
uint32_t wrapper over readUint.
Definition io.h:82
Defines the logger used by the top-level component of kea-lfc.
#define V4V6_BIND_OPTION_SPACE
#define LAST_RESORT_V4_OPTION_SPACE
#define DHCP4_OPTION_SPACE
global std option spaces
#define ISC_V6_OPTION_SPACE
#define V6_NTP_SERVER_SPACE
#define V4V6_RULE_OPTION_SPACE
#define MAPE_V6_OPTION_SPACE
#define DHCP_AGENT_OPTION_SPACE
encapsulated option spaces
#define LW_V6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
#define MAPT_V6_OPTION_SPACE
#define CABLELABS_CLIENT_CONF_SPACE
Encapsulation of option definition parameters and the structure size.
Parameters being used to make up an option definition.