Kea 2.6.0
libdhcp++.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2024 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>
23#include <util/buffer.h>
24#include <util/io.h>
25
26#include <boost/foreach.hpp>
27#include <boost/lexical_cast.hpp>
28#include <boost/shared_array.hpp>
29#include <boost/shared_ptr.hpp>
30
31#include <limits>
32#include <list>
33
34using namespace std;
35using namespace isc::dhcp;
36using namespace isc::util;
37
38namespace isc {
39namespace dhcp {
40
41namespace {
42
46const OptionDefParamsEncapsulation OPTION_DEF_PARAMS[] = {
47 { STANDARD_V4_OPTION_DEFINITIONS, STANDARD_V4_OPTION_DEFINITIONS_SIZE, DHCP4_OPTION_SPACE },
48 { STANDARD_V6_OPTION_DEFINITIONS, STANDARD_V6_OPTION_DEFINITIONS_SIZE, DHCP6_OPTION_SPACE },
51 { ISC_V6_OPTION_DEFINITIONS, ISC_V6_OPTION_DEFINITIONS_SIZE, ISC_V6_OPTION_SPACE },
52 { MAPE_V6_OPTION_DEFINITIONS, MAPE_V6_OPTION_DEFINITIONS_SIZE, MAPE_V6_OPTION_SPACE },
53 { MAPT_V6_OPTION_DEFINITIONS, MAPT_V6_OPTION_DEFINITIONS_SIZE, MAPT_V6_OPTION_SPACE },
54 { LW_V6_OPTION_DEFINITIONS, LW_V6_OPTION_DEFINITIONS_SIZE, LW_V6_OPTION_SPACE },
55 { V4V6_RULE_OPTION_DEFINITIONS, V4V6_RULE_OPTION_DEFINITIONS_SIZE, V4V6_RULE_OPTION_SPACE },
56 { V4V6_BIND_OPTION_DEFINITIONS, V4V6_BIND_OPTION_DEFINITIONS_SIZE, V4V6_BIND_OPTION_SPACE },
57 { DHCP_AGENT_OPTION_DEFINITIONS, DHCP_AGENT_OPTION_DEFINITIONS_SIZE, DHCP_AGENT_OPTION_SPACE },
58 { LAST_RESORT_V4_OPTION_DEFINITIONS, LAST_RESORT_V4_OPTION_DEFINITIONS_SIZE, LAST_RESORT_V4_OPTION_SPACE },
59 { NULL, 0, "" }
60};
61
62} // namespace
63
64} // namespace dhcp
65} // namespace isc
66
67// static array with factories for options
68map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
69
70// static array with factories for options
71map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
72
73// Static container with option definitions grouped by option space.
74OptionDefContainers LibDHCP::option_defs_;
75
76// Static container with option definitions created in runtime.
77StagedValue<OptionDefSpaceContainer> LibDHCP::runtime_option_defs_;
78
79// Null container.
81
82// Those two vendor classes are used for cable modems:
83
85const char* isc::dhcp::DOCSIS3_CLASS_MODEM = "docsis3.0";
86
88const char* isc::dhcp::DOCSIS3_CLASS_EROUTER = "eRouter1.0";
89
90// Let's keep it in .cc file. Moving it to .h would require including optionDefParams
91// definitions there
93 const OptionDefParams* params,
94 size_t params_size);
95
96bool LibDHCP::initialized_ = LibDHCP::initOptionDefs();
97
99LibDHCP::getOptionDefs(const string& space) {
100 auto const& container = option_defs_.find(space);
101 if (container != option_defs_.end()) {
102 return (container->second);
103 }
104
106}
107
109LibDHCP::getVendorOptionDefs(const Option::Universe u, const uint32_t vendor_id) {
110 if (Option::V4 == u) {
111 if (VENDOR_ID_CABLE_LABS == vendor_id) {
113 }
114 } else if (Option::V6 == u) {
115 if (VENDOR_ID_CABLE_LABS == vendor_id) {
117 } else if (ENTERPRISE_ID_ISC == vendor_id) {
119 }
120 }
121
123}
124
126LibDHCP::getOptionDef(const string& space, const uint16_t code) {
127 const OptionDefContainerPtr& defs = getOptionDefs(space);
128 const OptionDefContainerTypeIndex& idx = defs->get<1>();
129 const OptionDefContainerTypeRange& range = idx.equal_range(code);
130 if (range.first != range.second) {
131 return (*range.first);
132 }
133
134 return (OptionDefinitionPtr());
135}
136
138LibDHCP::getOptionDef(const string& space, const string& name) {
139 const OptionDefContainerPtr& defs = getOptionDefs(space);
140 const OptionDefContainerNameIndex& idx = defs->get<2>();
141 const OptionDefContainerNameRange& range = idx.equal_range(name);
142 if (range.first != range.second) {
143 return (*range.first);
144 }
145
146 return (OptionDefinitionPtr());
147}
148
150LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
151 const string& name) {
152 const OptionDefContainerPtr& defs = getVendorOptionDefs(u, vendor_id);
153
154 if (!defs) {
155 return (OptionDefinitionPtr());
156 }
157
158 const OptionDefContainerNameIndex& idx = defs->get<2>();
159 const OptionDefContainerNameRange& range = idx.equal_range(name);
160 if (range.first != range.second) {
161 return (*range.first);
162 }
163
164 return (OptionDefinitionPtr());
165}
166
168LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
169 const uint16_t code) {
170 const OptionDefContainerPtr& defs = getVendorOptionDefs(u, vendor_id);
171
172 if (!defs) {
173 // Weird universe or unknown vendor_id. We don't care. No definitions
174 // one way or another
175 // What is it anyway?
176 return (OptionDefinitionPtr());
177 }
178
179 const OptionDefContainerTypeIndex& idx = defs->get<1>();
180 const OptionDefContainerTypeRange& range = idx.equal_range(code);
181 if (range.first != range.second) {
182 return (*range.first);
183 }
184
185 return (OptionDefinitionPtr());
186}
187
189LibDHCP::getRuntimeOptionDef(const string& space, const uint16_t code) {
190 OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
191 const OptionDefContainerTypeIndex& index = container->get<1>();
192 const OptionDefContainerTypeRange& range = index.equal_range(code);
193 if (range.first != range.second) {
194 return (*range.first);
195 }
196
197 return (OptionDefinitionPtr());
198}
199
201LibDHCP::getRuntimeOptionDef(const string& space, const string& name) {
202 OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
203 const OptionDefContainerNameIndex& index = container->get<2>();
204 const OptionDefContainerNameRange& range = index.equal_range(name);
205 if (range.first != range.second) {
206 return (*range.first);
207 }
208
209 return (OptionDefinitionPtr());
210}
211
213LibDHCP::getRuntimeOptionDefs(const string& space) {
214 return (runtime_option_defs_.getValue().getItems(space));
215}
216
217void
219 OptionDefSpaceContainer defs_copy;
220 list<string> option_space_names = defs.getOptionSpaceNames();
221 for (auto const& name : option_space_names) {
222 OptionDefContainerPtr container = defs.getItems(name);
223 for (auto const& def : *container) {
224 OptionDefinitionPtr def_copy(new OptionDefinition(*def));
225 defs_copy.addItem(def_copy);
226 }
227 }
228 runtime_option_defs_ = defs_copy;
229}
230
231void
233 runtime_option_defs_.reset();
234}
235
236void
238 runtime_option_defs_.revert();
239}
240
241void
243 runtime_option_defs_.commit();
244}
245
247LibDHCP::getLastResortOptionDef(const string& space, const uint16_t code) {
249 const OptionDefContainerTypeIndex& index = container->get<1>();
250 const OptionDefContainerTypeRange& range = index.equal_range(code);
251 if (range.first != range.second) {
252 return (*range.first);
253 }
254
255 return (OptionDefinitionPtr());
256}
257
259LibDHCP::getLastResortOptionDef(const string& space, const string& name) {
261 const OptionDefContainerNameIndex& index = container->get<2>();
262 const OptionDefContainerNameRange& range = index.equal_range(name);
263 if (range.first != range.second) {
264 return (*range.first);
265 }
266
267 return (OptionDefinitionPtr());
268}
269
272 if (space == DHCP4_OPTION_SPACE) {
274 }
275
277}
278
279bool
280LibDHCP::shouldDeferOptionUnpack(const string& space, const uint16_t code) {
281 return ((space == DHCP4_OPTION_SPACE) &&
283 ((code >= 224) && (code <= 254))));
284}
285
288 uint16_t type,
289 const OptionBuffer& buf) {
290 FactoryMap::iterator it;
291 if (u == Option::V4) {
292 it = v4factories_.find(type);
293 if (it == v4factories_.end()) {
294 isc_throw(BadValue, "factory function not registered "
295 "for DHCP v4 option type " << type);
296 }
297 } else if (u == Option::V6) {
298 it = v6factories_.find(type);
299 if (it == v6factories_.end()) {
300 isc_throw(BadValue, "factory function not registered "
301 "for DHCPv6 option type " << type);
302 }
303 } else {
304 isc_throw(BadValue, "invalid universe specified (expected "
305 "Option::V4 or Option::V6");
306 }
307 return (it->second(u, type, buf));
308}
309
310size_t
311LibDHCP::unpackOptions6(const OptionBuffer& buf, const string& option_space,
312 OptionCollection& options,
313 size_t* relay_msg_offset /* = 0 */,
314 size_t* relay_msg_len /* = 0 */) {
315 size_t offset = 0;
316 size_t length = buf.size();
317 size_t last_offset = 0;
318
319 // Get the list of standard option definitions.
320 const OptionDefContainerPtr& option_defs = LibDHCP::getOptionDefs(option_space);
321 // Runtime option definitions for non standard option space and if
322 // the definition doesn't exist within the standard option definitions.
323 const OptionDefContainerPtr& runtime_option_defs = LibDHCP::getRuntimeOptionDefs(option_space);
324
325 // @todo Once we implement other option spaces we should add else clause
326 // here and gather option definitions for them. For now leaving option_defs
327 // empty will imply creation of generic Option.
328
329 // Get the search indexes #1. It allows to search for option definitions
330 // using option code.
331 const OptionDefContainerTypeIndex& idx = option_defs->get<1>();
332 const OptionDefContainerTypeIndex& runtime_idx = runtime_option_defs->get<1>();
333
334 // The buffer being read comprises a set of options, each starting with
335 // a two-byte type code and a two-byte length field.
336 while (offset < length) {
337 // Save the current offset for backtracking
338 last_offset = offset;
339
340 // Check if there is room for another option
341 if (offset + 4 > length) {
342 // Still something but smaller than an option
343 return (last_offset);
344 }
345
346 // Parse the option header
347 uint16_t opt_type = readUint16(&buf[offset], 2);
348 offset += 2;
349
350 uint16_t opt_len = readUint16(&buf[offset], 2);
351 offset += 2;
352
353 if (offset + opt_len > length) {
354 // We peeked at the option header of the next option, but
355 // discovered that it would end up beyond buffer end, so
356 // the option is truncated. Hence we can't parse
357 // it. Therefore we revert back by those bytes (as if
358 // we never parsed them).
359 //
360 // @note it is the responsibility of the caller to throw
361 // an exception on partial parsing
362 return (last_offset);
363 }
364
365 if (opt_type == D6O_RELAY_MSG && relay_msg_offset && relay_msg_len) {
366 // remember offset of the beginning of the relay-msg option
367 *relay_msg_offset = offset;
368 *relay_msg_len = opt_len;
369
370 // do not create that relay-msg option
371 offset += opt_len;
372 continue;
373 }
374
375 if (opt_type == D6O_VENDOR_OPTS) {
376 if (offset + 4 > length) {
377 // Truncated vendor-option. We expect at least
378 // 4 bytes for the enterprise-id field. Let's roll back
379 // option code + option length (4 bytes) and return.
380 return (last_offset);
381 }
382
383 // Parse this as vendor option
384 OptionPtr vendor_opt(new OptionVendor(Option::V6, buf.begin() + offset,
385 buf.begin() + offset + opt_len));
386 options.insert(std::make_pair(opt_type, vendor_opt));
387
388 offset += opt_len;
389 continue;
390 }
391
392 // Get all definitions with the particular option code. Note
393 // that option code is non-unique within this container
394 // however at this point we expect to get one option
395 // definition with the particular code. If more are returned
396 // we report an error.
398 // Number of option definitions returned.
399 size_t num_defs = 0;
400
401 // We previously did the lookup only for dhcp6 option space, but with the
402 // addition of S46 options, we now do it for every space.
403 range = idx.equal_range(opt_type);
404 num_defs = std::distance(range.first, range.second);
405
406 // Standard option definitions do not include the definition for
407 // our option or we're searching for non-standard option. Try to
408 // find the definition among runtime option definitions.
409 if (num_defs == 0) {
410 range = runtime_idx.equal_range(opt_type);
411 num_defs = std::distance(range.first, range.second);
412 }
413
414 OptionPtr opt;
415 if (num_defs > 1) {
416 // Multiple options of the same code are not supported right now!
417 isc_throw(isc::Unexpected, "Internal error: multiple option"
418 " definitions for option type " << opt_type <<
419 " returned. Currently it is not supported to initialize"
420 " multiple option definitions for the same option code."
421 " This will be supported once support for option spaces"
422 " is implemented");
423 } else if (num_defs == 0) {
424 // @todo Don't crash if definition does not exist because
425 // only a few option definitions are initialized right
426 // now. In the future we will initialize definitions for
427 // all options and we will remove this elseif. For now,
428 // return generic option.
429 opt = OptionPtr(new Option(Option::V6, opt_type,
430 buf.begin() + offset,
431 buf.begin() + offset + opt_len));
432 } else {
433 try {
434 // The option definition has been found. Use it to create
435 // the option instance from the provided buffer chunk.
436 const OptionDefinitionPtr& def = *(range.first);
437 isc_throw_assert(def);
438 opt = def->optionFactory(Option::V6, opt_type,
439 buf.begin() + offset,
440 buf.begin() + offset + opt_len);
441 } catch (const SkipThisOptionError&) {
442 opt.reset();
443 }
444 }
445
446 // add option to options
447 if (opt) {
448 options.insert(std::make_pair(opt_type, opt));
449 }
450
451 offset += opt_len;
452 }
453
454 last_offset = offset;
455 return (last_offset);
456}
457
458size_t
459LibDHCP::unpackOptions4(const OptionBuffer& buf, const string& option_space,
460 OptionCollection& options, list<uint16_t>& deferred,
461 bool check) {
462 size_t offset = 0;
463 size_t last_offset = 0;
464
465 // Special case when option_space is dhcp4.
466 bool space_is_dhcp4 = (option_space == DHCP4_OPTION_SPACE);
467
468 // Get the list of standard option definitions.
469 const OptionDefContainerPtr& option_defs = LibDHCP::getOptionDefs(option_space);
470 // Runtime option definitions for non standard option space and if
471 // the definition doesn't exist within the standard option definitions.
472 const OptionDefContainerPtr& runtime_option_defs = LibDHCP::getRuntimeOptionDefs(option_space);
473
474 // Get the search indexes #1. It allows to search for option definitions
475 // using option code.
476 const OptionDefContainerTypeIndex& idx = option_defs->get<1>();
477 const OptionDefContainerTypeIndex& runtime_idx = runtime_option_defs->get<1>();
478
479 // Flexible PAD and END parsing.
480 bool flex_pad = (check && (runtime_idx.count(DHO_PAD) == 0));
481 bool flex_end = (check && (runtime_idx.count(DHO_END) == 0));
482
483 // The buffer being read comprises a set of options, each starting with
484 // a one-byte type code and a one-byte length field.
485 while (offset < buf.size()) {
486 // Save the current offset for backtracking
487 last_offset = offset;
488
489 // Get the option type
490 uint8_t opt_type = buf[offset++];
491
492 // DHO_END is a special, one octet long option
493 // Valid in dhcp4 space or when check is true and
494 // there is a sub-option configured for this code.
495 if ((opt_type == DHO_END) && (space_is_dhcp4 || flex_end)) {
496 // just return. Don't need to add DHO_END option
497 // Don't return offset because it makes this condition
498 // and partial parsing impossible to recognize.
499 return (last_offset);
500 }
501
502 // DHO_PAD is just a padding after DHO_END. Let's continue parsing
503 // in case we receive a message without DHO_END.
504 // Valid in dhcp4 space or when check is true and
505 // there is a sub-option configured for this code.
506 if ((opt_type == DHO_PAD) && (space_is_dhcp4 || flex_pad)) {
507 continue;
508 }
509
510 if (offset + 1 > buf.size()) {
511 // We peeked at the option header of the next option, but
512 // discovered that it would end up beyond buffer end, so
513 // the option is truncated. Hence we can't parse
514 // it. Therefore we revert back (as if we never parsed it).
515 //
516 // @note it is the responsibility of the caller to throw
517 // an exception on partial parsing
518 return (last_offset);
519 }
520
521 uint8_t opt_len = buf[offset++];
522 if (offset + opt_len > buf.size()) {
523 // We peeked at the option header of the next option, but
524 // discovered that it would end up beyond buffer end, so
525 // the option is truncated. Hence we can't parse
526 // it. Therefore we revert back (as if we never parsed it).
527 return (last_offset);
528 }
529
530 // While an empty Host Name option is non-RFC compliant, some clients
531 // do send it. In the spirit of being liberal, we'll just drop it,
532 // rather than the dropping the whole packet. We do not have a
533 // way to log this from here but meh... a PCAP will show it arriving,
534 // and we know we drop it.
535 if (space_is_dhcp4 && opt_len == 0 && opt_type == DHO_HOST_NAME) {
536 continue;
537 }
538
539 // Get all definitions with the particular option code. Note
540 // that option code is non-unique within this container
541 // however at this point we expect to get one option
542 // definition with the particular code. If more are returned
543 // we report an error.
545 // Number of option definitions returned.
546 size_t num_defs = 0;
547
548 // Previously we did the lookup only for "dhcp4" option space, but there
549 // may be standard options in other spaces (e.g. radius). So we now do
550 // the lookup for every space.
551 range = idx.equal_range(opt_type);
552 num_defs = std::distance(range.first, range.second);
553
554 // Standard option definitions do not include the definition for
555 // our option or we're searching for non-standard option. Try to
556 // find the definition among runtime option definitions.
557 if (num_defs == 0) {
558 range = runtime_idx.equal_range(opt_type);
559 num_defs = std::distance(range.first, range.second);
560 }
561
562 // Check if option unpacking must be deferred
563 if (shouldDeferOptionUnpack(option_space, opt_type)) {
564 num_defs = 0;
565 // Store deferred option only once.
566 bool found = false;
567 for (auto const& existing : deferred) {
568 if (existing == opt_type) {
569 found = true;
570 break;
571 }
572 }
573 if (!found) {
574 deferred.push_back(opt_type);
575 }
576 }
577
578 if (space_is_dhcp4 &&
579 (opt_type == DHO_VIVSO_SUBOPTIONS ||
580 opt_type == DHO_VIVCO_SUBOPTIONS)) {
581 num_defs = 0;
582 }
583
584 OptionPtr opt;
585 if (num_defs > 1) {
586 // Multiple options of the same code are not supported right now!
587 isc_throw(isc::Unexpected, "Internal error: multiple option"
588 " definitions for option type " <<
589 static_cast<int>(opt_type) <<
590 " returned. Currently it is not supported to initialize"
591 " multiple option definitions for the same option code."
592 " This will be supported once support for option spaces"
593 " is implemented");
594 } else if (num_defs == 0) {
595 opt = OptionPtr(new Option(Option::V4, opt_type,
596 buf.begin() + offset,
597 buf.begin() + offset + opt_len));
598 opt->setEncapsulatedSpace(DHCP4_OPTION_SPACE);
599 } else {
600 try {
601 // The option definition has been found. Use it to create
602 // the option instance from the provided buffer chunk.
603 const OptionDefinitionPtr& def = *(range.first);
604 isc_throw_assert(def);
605 opt = def->optionFactory(Option::V4, opt_type,
606 buf.begin() + offset,
607 buf.begin() + offset + opt_len);
608 } catch (const SkipThisOptionError&) {
609 opt.reset();
610 }
611 }
612
613 // If we have the option, insert it
614 if (opt) {
615 options.insert(std::make_pair(opt_type, opt));
616 }
617
618 offset += opt_len;
619 }
620 last_offset = offset;
621 return (last_offset);
622}
623
624bool
626 bool result = false;
627 // We need to loop until all options have been fused.
628 for (;;) {
629 uint32_t found = 0;
630 bool found_suboptions = false;
631 // Iterate over all options in the container.
632 for (auto const& option : options) {
633 OptionPtr candidate = option.second;
634 OptionCollection& sub_options = candidate->getMutableOptions();
635 // Fuse suboptions recursively, if any.
636 if (sub_options.size()) {
637 // Fusing suboptions might result in new options with multiple
638 // options having the same code, so we need to iterate again
639 // until no option needs fusing.
640 found_suboptions = LibDHCP::fuseOptions4(sub_options);
641 if (found_suboptions) {
642 result = true;
643 }
644 }
645 OptionBuffer data;
646 OptionCollection suboptions;
647 // Make a copy of the options so we can safely iterate over the
648 // old container.
649 OptionCollection copy = options;
650 for (auto const& old_option : copy) {
651 if (old_option.first == option.first) {
652 // Copy the option data to the buffer.
653 data.insert(data.end(), old_option.second->getData().begin(),
654 old_option.second->getData().end());
655 suboptions.insert(old_option.second->getOptions().begin(),
656 old_option.second->getOptions().end());
657 // Other options might need fusing, so we need to iterate
658 // again until no options needs fusing.
659 found++;
660 }
661 }
662 if (found > 1) {
663 result = true;
664 // Erase the old options from the new container so that only the
665 // new option is present.
666 copy.erase(option.first);
667 // Create new option with entire data.
668 OptionPtr new_option(new Option(candidate->getUniverse(),
669 candidate->getType(), data));
670 // Recreate suboptions container.
671 new_option->getMutableOptions() = suboptions;
672 // Add the new option to the new container.
673 copy.insert(make_pair(candidate->getType(), new_option));
674 // After all options have been fused and new option added,
675 // update the option container with the new container.
676 options = copy;
677 break;
678 } else {
679 found = 0;
680 }
681 }
682 // No option needs fusing, so we can exit the loop.
683 if ((found <= 1) && !found_suboptions) {
684 break;
685 }
686 }
687 return (result);
688}
689
690namespace { // Anonymous namespace.
691
692// VIVCO part of extendVendorOptions4.
693
694void
695extendVivco(OptionCollection& options) {
696 typedef vector<OpaqueDataTuple> TuplesCollection;
697 map<uint32_t, TuplesCollection> vendors_tuples;
698 auto const& range = options.equal_range(DHO_VIVCO_SUBOPTIONS);
699 BOOST_FOREACH(auto const& it, range) {
700 uint32_t offset = 0;
701 auto const& data = it.second->getData();
702 size_t size;
703 while ((size = data.size() - offset) != 0) {
704 if (size < sizeof(uint32_t)) {
705 options.erase(DHO_VIVCO_SUBOPTIONS);
707 "Truncated vendor-class information option"
708 << ", length=" << size);
709 }
710 uint32_t vendor_id = readUint32(&data[offset], data.size());
711 offset += 4;
712 try {
713 // From OptionVendorClass::unpack.
715 data.begin() + offset, data.end());
716 vendors_tuples[vendor_id].push_back(tuple);
717 offset += tuple.getTotalLength();
718 } catch (const OpaqueDataTupleError&) {
719 // Ignore this kind of error and continue.
720 break;
721 } catch (const isc::Exception&) {
722 options.erase(DHO_VIVCO_SUBOPTIONS);
723 throw;
724 }
725 }
726 }
727 if (vendors_tuples.empty()) {
728 return;
729 }
730 // Delete the initial option.
731 options.erase(DHO_VIVCO_SUBOPTIONS);
732 // Create a new instance of OptionVendor for each enterprise ID.
733 for (auto const& vendor : vendors_tuples) {
734 if (vendor.second.empty()) {
735 continue;
736 }
738 vendor.first));
739 for (size_t i = 0; i < vendor.second.size(); ++i) {
740 if (i == 0) {
741 vendor_opt->setTuple(0, vendor.second[0]);
742 } else {
743 vendor_opt->addTuple(vendor.second[i]);
744 }
745 }
746 // Add the new instance of VendorOption with respective sub-options for
747 // this enterprise ID.
748 options.insert(std::make_pair(DHO_VIVCO_SUBOPTIONS, vendor_opt));
749 }
750}
751
752// VIVSO part of extendVendorOptions4.
753
754void
755extendVivso(OptionCollection& options) {
756 map<uint32_t, OptionCollection> vendors_data;
757 auto const& range = options.equal_range(DHO_VIVSO_SUBOPTIONS);
758 BOOST_FOREACH(auto const& it, range) {
759 uint32_t offset = 0;
760 auto const& data = it.second->getData();
761 size_t size;
762 while ((size = data.size() - offset) != 0) {
763 if (size < sizeof(uint32_t)) {
764 options.erase(DHO_VIVSO_SUBOPTIONS);
766 "Truncated vendor-specific information option"
767 << ", length=" << size);
768 }
769 uint32_t vendor_id = readUint32(&data[offset], data.size());
770 offset += 4;
771 const OptionBuffer vendor_buffer(data.begin() + offset, data.end());
772 try {
773 offset += LibDHCP::unpackVendorOptions4(vendor_id, vendor_buffer,
774 vendors_data[vendor_id]);
775 } catch (const SkipThisOptionError&) {
776 // Ignore this kind of error and continue.
777 break;
778 } catch (const isc::Exception&) {
779 options.erase(DHO_VIVSO_SUBOPTIONS);
780 throw;
781 }
782 }
783 }
784 if (vendors_data.empty()) {
785 return;
786 }
787 // Delete the initial option.
788 options.erase(DHO_VIVSO_SUBOPTIONS);
789 // Create a new instance of OptionVendor for each enterprise ID.
790 for (auto const& vendor : vendors_data) {
791 OptionVendorPtr vendor_opt(new OptionVendor(Option::V4, vendor.first));
792 for (auto const& option : vendor.second) {
793 vendor_opt->addOption(option.second);
794 }
795 // Add the new instance of VendorOption with respective sub-options for
796 // this enterprise ID.
797 options.insert(std::make_pair(DHO_VIVSO_SUBOPTIONS, vendor_opt));
798 }
799}
800
801} // end of anonymous namespace.
802
803void
805 extendVivco(options);
806 extendVivso(options);
807}
808
809size_t
810LibDHCP::unpackVendorOptions6(const uint32_t vendor_id, const OptionBuffer& buf,
811 OptionCollection& options) {
812 size_t offset = 0;
813 size_t length = buf.size();
814
815 // Get the list of option definitions for this particular vendor-id
816 const OptionDefContainerPtr& option_defs =
818
819 // Get the search index #1. It allows to search for option definitions
820 // using option code. If there's no such vendor-id space, we're out of luck
821 // anyway.
822 const OptionDefContainerTypeIndex* idx = NULL;
823 if (option_defs) {
824 idx = &(option_defs->get<1>());
825 }
826
827 // The buffer being read comprises a set of options, each starting with
828 // a two-byte type code and a two-byte length field.
829 while (offset < length) {
830 if (offset + 4 > length) {
832 "Vendor option parse failed: truncated header");
833 }
834
835 uint16_t opt_type = readUint16(&buf[offset], 2);
836 offset += 2;
837
838 uint16_t opt_len = readUint16(&buf[offset], 2);
839 offset += 2;
840
841 if (offset + opt_len > length) {
843 "Vendor option parse failed. Tried to parse "
844 << offset + opt_len << " bytes from " << length
845 << "-byte long buffer.");
846 }
847
848 OptionPtr opt;
849 opt.reset();
850
851 // If there is a definition for such a vendor option...
852 if (idx) {
853 // Get all definitions with the particular option
854 // code. Note that option code is non-unique within this
855 // container however at this point we expect to get one
856 // option definition with the particular code. If more are
857 // returned we report an error.
858 const OptionDefContainerTypeRange& range =
859 idx->equal_range(opt_type);
860 // Get the number of returned option definitions for the
861 // option code.
862 size_t num_defs = std::distance(range.first, range.second);
863
864 if (num_defs > 1) {
865 // Multiple options of the same code are not supported
866 // right now!
867 isc_throw(isc::Unexpected, "Internal error: multiple option"
868 " definitions for option type " << opt_type <<
869 " returned. Currently it is not supported to"
870 " initialize multiple option definitions for the"
871 " same option code. This will be supported once"
872 " support for option spaces is implemented");
873 } else if (num_defs == 1) {
874 // The option definition has been found. Use it to create
875 // the option instance from the provided buffer chunk.
876 const OptionDefinitionPtr& def = *(range.first);
877 isc_throw_assert(def);
878 opt = def->optionFactory(Option::V6, opt_type,
879 buf.begin() + offset,
880 buf.begin() + offset + opt_len);
881 }
882 }
883
884 // This can happen in one of 2 cases:
885 // 1. we do not have definitions for that vendor-space
886 // 2. we do have definitions, but that particular option was
887 // not defined
888
889 if (!opt) {
890 opt = OptionPtr(new Option(Option::V6, opt_type,
891 buf.begin() + offset,
892 buf.begin() + offset + opt_len));
893 }
894
895 // add option to options
896 if (opt) {
897 options.insert(std::make_pair(opt_type, opt));
898 }
899 offset += opt_len;
900 }
901
902 return (offset);
903}
904
905size_t
906LibDHCP::unpackVendorOptions4(const uint32_t vendor_id, const OptionBuffer& buf,
907 OptionCollection& options) {
908 size_t offset = 0;
909
910 // Get the list of standard option definitions.
911 const OptionDefContainerPtr& option_defs =
913 // Get the search index #1. It allows to search for option definitions
914 // using option code.
915 const OptionDefContainerTypeIndex* idx = NULL;
916 if (option_defs) {
917 idx = &(option_defs->get<1>());
918 }
919
920 // The buffer being read comprises a set of options, each starting with
921 // a one-byte type code and a one-byte length field.
922 while (offset < buf.size()) {
923 // Note that Vendor-Specific info option (RFC3925) has a
924 // different option format than Vendor-Spec info for
925 // DHCPv6. (there's additional layer of data-length)
926 uint8_t data_len = buf[offset++];
927
928 if (offset + data_len > buf.size()) {
929 // The option is truncated.
931 "Attempt to parse truncated vendor option");
932 }
933
934 uint8_t offset_end = offset + data_len;
935
936 // beginning of data-chunk parser
937 while (offset < offset_end) {
938 uint8_t opt_type = buf[offset++];
939
940 // No DHO_END or DHO_PAD in vendor options
941
942 if (offset + 1 > offset_end) {
943 // opt_type must be cast to integer so as it is not
944 // treated as unsigned char value (a number is
945 // presented in error message).
947 "Attempt to parse truncated vendor option "
948 << static_cast<int>(opt_type));
949 }
950
951 uint8_t opt_len = buf[offset++];
952 if (offset + opt_len > offset_end) {
954 "Option parse failed. Tried to parse "
955 << offset + opt_len << " bytes from " << buf.size()
956 << "-byte long buffer.");
957 }
958
959 OptionPtr opt;
960 opt.reset();
961
962 if (idx) {
963 // Get all definitions with the particular option
964 // code. Note that option code is non-unique within
965 // this container however at this point we expect to
966 // get one option definition with the particular
967 // code. If more are returned we report an error.
968 const OptionDefContainerTypeRange& range =
969 idx->equal_range(opt_type);
970 // Get the number of returned option definitions for
971 // the option code.
972 size_t num_defs = std::distance(range.first, range.second);
973
974 if (num_defs > 1) {
975 // Multiple options of the same code are not
976 // supported right now!
977 isc_throw(isc::Unexpected, "Internal error: multiple"
978 " option definitions for option type "
979 << opt_type << " returned. Currently it is"
980 " not supported to initialize multiple option"
981 " definitions for the same option code."
982 " This will be supported once support for"
983 " option spaces is implemented");
984 } else if (num_defs == 1) {
985 // The option definition has been found. Use it to create
986 // the option instance from the provided buffer chunk.
987 const OptionDefinitionPtr& def = *(range.first);
988 isc_throw_assert(def);
989 opt = def->optionFactory(Option::V4, opt_type,
990 buf.begin() + offset,
991 buf.begin() + offset + opt_len);
992 }
993 }
994
995 if (!opt) {
996 opt = OptionPtr(new Option(Option::V4, opt_type,
997 buf.begin() + offset,
998 buf.begin() + offset + opt_len));
999 }
1000
1001 options.insert(std::make_pair(opt_type, opt));
1002 offset += opt_len;
1003
1004 } // end of data-chunk
1005
1006 break; // end of the vendor block.
1007 }
1008 return (offset);
1009}
1010
1011void
1013 bool top, bool check) {
1014 OptionCollection agent;
1015 OptionPtr end;
1016
1017 // We only look for type when we're the top level
1018 // call that starts packing for options for a packet.
1019 // This way we avoid doing type logic in all ensuing
1020 // recursive calls.
1021 if (top) {
1022 auto x = options.find(DHO_DHCP_MESSAGE_TYPE);
1023 if (x != options.end()) {
1024 x->second->pack(buf, check);
1025 }
1026 }
1027
1028 for (auto const& option : options) {
1029 // TYPE is already done, RAI and END options must be last.
1030 switch (option.first) {
1032 break;
1034 agent.insert(make_pair(DHO_DHCP_AGENT_OPTIONS, option.second));
1035 break;
1036 case DHO_END:
1037 end = option.second;
1038 break;
1039 default:
1040 option.second->pack(buf, check);
1041 break;
1042 }
1043 }
1044
1045 // Add the RAI option if it exists.
1046 for (auto const& option : agent) {
1047 option.second->pack(buf, check);
1048 }
1049
1050 // And at the end the END option.
1051 if (end) {
1052 end->pack(buf, check);
1053 }
1054}
1055
1056bool
1058 ScopedOptionsCopyContainer& scoped_options,
1059 uint32_t used) {
1060 bool result = false;
1061 // We need to loop until all options have been split.
1062 uint32_t tries = 0;
1063 for (;; tries++) {
1064 // Let's not do this forever if there is a bug hiding here somewhere...
1065 // 65535 times should be enough for any packet load...
1066 if (tries == std::numeric_limits<uint16_t>::max()) {
1067 isc_throw(Unexpected, "packet split failed after trying "
1068 << tries << " times.");
1069 }
1070 bool found = false;
1071 // Make a copy of the options so we can safely iterate over the
1072 // old container.
1073 OptionCollection copy = options;
1074 // Iterate over all options in the container.
1075 for (auto const& option : options) {
1076 OptionPtr candidate = option.second;
1077 OptionCollection& sub_options = candidate->getMutableOptions();
1078 // Split suboptions recursively, if any.
1079 OptionCollection distinct_options;
1080 bool updated = false;
1081 bool found_suboptions = false;
1082 // There are 3 cases when the total size is larger than (255 - used):
1083 // 1. option has no suboptions and has large data
1084 // 2. option has large suboptions and has no data
1085 // 3. option has both options and suboptions:
1086 // 3.1. suboptions are large and data is large
1087 // 3.2. suboptions are large and data is small
1088 // 3.3. suboptions are small and data is large
1089 // 3.4. suboptions are small and data is small but combined they are large
1090 // All other combinations reside in total size smaller than (255 - used):
1091 // 4. no split of any suboption or data:
1092 // 4.1 option has no suboptions and has small data
1093 // 4.2 option has small suboptions and has no data
1094 // 4.3 option has both small suboptions and small data
1095 // 4.4 option has no suboptions and has no data
1096 if (sub_options.size()) {
1097 // The 2. and 3. and 4.2 and 4.3 cases are handled here (the suboptions part).
1098 ScopedOptionsCopyPtr candidate_scoped_options(new ScopedSubOptionsCopy(candidate));
1099 found_suboptions = LibDHCP::splitOptions4(sub_options, scoped_options,
1100 used + candidate->getHeaderLen());
1101 // There are 3 cases here:
1102 // 2. option has large suboptions and has no data
1103 // 3. option has both options and suboptions:
1104 // 3.1. suboptions are large and data is large so there is suboption splitting
1105 // and found_suboptions is true
1106 // 3.2. suboptions are large and data is small so there is suboption splitting
1107 // and found_suboptions is true
1108 // 3.3. suboptions are small and data is large so there is no suboption splitting
1109 // and found_suboptions is false
1110 // 3.4. suboptions are small and data is small so there is no suboption splitting
1111 // and found_suboptions is false but combined they are large
1112 // 4. no split of any suboption or data
1113 // Also split if the overflow is caused by adding the suboptions
1114 // to the option data.
1115 if (found_suboptions || candidate->len() > (255 - used)) {
1116 // The 2. and 3. cases are handled here (the suboptions part).
1117 updated = true;
1118 scoped_options.push_back(candidate_scoped_options);
1119 // Erase the old options from the new container so that only
1120 // the new options are present.
1121 copy.erase(option.first);
1122 result = true;
1123 // If there are suboptions which have been split, one parent
1124 // option will be created for each of the chunk of the
1125 // suboptions. If the suboptions have not been split,
1126 // but they cause overflow when added to the option data,
1127 // one parent option will contain the option data and one
1128 // parent option will be created for each suboption.
1129 // This will guarantee that none of the options plus
1130 // suboptions will have more than 255 bytes.
1131 for (auto const& sub_option : candidate->getMutableOptions()) {
1132 OptionPtr data_sub_option(new Option(candidate->getUniverse(),
1133 candidate->getType(),
1134 OptionBuffer(0)));
1135 data_sub_option->addOption(sub_option.second);
1136 distinct_options.insert(make_pair(candidate->getType(), data_sub_option));
1137 }
1138 }
1139 }
1140 // The 1. and 3. and 4. cases are handled here (the data part).
1141 // Create a new option containing only data that needs to be split
1142 // and no suboptions (which are inserted in completely separate
1143 // options which are added at the end).
1144 OptionPtr data_option(new Option(candidate->getUniverse(),
1145 candidate->getType(),
1146 OptionBuffer(candidate->getData().begin(),
1147 candidate->getData().end())));
1148 OutputBuffer buf(0);
1149 data_option->pack(buf, false);
1150 uint32_t header_len = candidate->getHeaderLen();
1151 // At least 1 + header length bytes must be available.
1152 if (used >= 255 - header_len) {
1153 isc_throw(BadValue, "there is no space left to split option "
1154 << candidate->getType() << " after parent already used "
1155 << used);
1156 }
1157 // Maximum option buffer size is 255 - header size - buffer size
1158 // already used by parent options.
1159 uint8_t len = 255 - header_len - used;
1160 // Current option size after split is the sum of the data and the
1161 // header size. The suboptions are serialized in separate options.
1162 // The header is duplicated in all new options, but the rest of the
1163 // data must be split and serialized.
1164 uint32_t size = buf.getLength() - header_len;
1165 // Only split if data does not fit in the current option.
1166 // There are 3 cases here:
1167 // 1. option has no suboptions and has large data
1168 // 3. option has both options and suboptions:
1169 // 3.1. suboptions are large and data is large
1170 // 3.2. suboptions are large and data is small
1171 // 3.3. suboptions are small and data is large
1172 // 3.4. suboptions are small and data is small but combined they are large
1173 // 4. no split of any suboption or data
1174 if (size > len) {
1175 // The 1. and 3.1. and 3.3 cases are handled here (the data part).
1176 // Erase the old option from the new container so that only new
1177 // options are present.
1178 if (!updated) {
1179 updated = true;
1180 // Erase the old options from the new container so that only
1181 // the new options are present.
1182 copy.erase(option.first);
1183 result = true;
1184 }
1185 uint32_t offset = 0;
1186 // Drain the option buffer in multiple new options until all
1187 // data is serialized.
1188 for (; offset != size;) {
1189 // Adjust the data length of the new option if remaining
1190 // data is less than the 255 - header size (for the last
1191 // option).
1192 if (size - offset < len) {
1193 len = size - offset;
1194 }
1195 // Create new option with data starting from offset and
1196 // containing truncated length.
1197 const uint8_t* data = buf.getData();
1198 data += header_len;
1199 OptionPtr new_option(new Option(candidate->getUniverse(),
1200 candidate->getType(),
1201 OptionBuffer(data + offset,
1202 data + offset + len)));
1203 // Adjust the offset for remaining data to be written to the
1204 // next new option.
1205 offset += len;
1206 // Add the new option to the new container.
1207 copy.insert(make_pair(candidate->getType(), new_option));
1208 }
1209 } else if ((candidate->len() > (255 - used)) && size) {
1210 // The 3.2 and 3.4 cases are handled here (the data part).
1211 // Also split if the overflow is caused by adding the suboptions
1212 // to the option data (which should be of non zero size).
1213 // Add the new option to the new container.
1214 copy.insert(make_pair(candidate->getType(), data_option));
1215 }
1216 if (updated) {
1217 // Add the new options containing the split suboptions, if any,
1218 // to the new container.
1219 copy.insert(distinct_options.begin(), distinct_options.end());
1220 // After all new options have been split and added, update the
1221 // option container with the new container.
1222 options = copy;
1223 // Other options might need splitting, so we need to iterate
1224 // again until no option needs splitting.
1225 found = true;
1226 break;
1227 }
1228 }
1229 // No option needs splitting, so we can exit the loop.
1230 if (!found) {
1231 break;
1232 }
1233 }
1234 return (result);
1235}
1236
1237void
1239 for (auto const& option : options) {
1240 option.second->pack(buf);
1241 }
1242}
1243
1244void
1246 Option::Factory* factory) {
1247 switch (u) {
1248 case Option::V6:
1249 {
1250 if (v6factories_.find(opt_type) != v6factories_.end()) {
1251 isc_throw(BadValue, "There is already DHCPv6 factory registered "
1252 << "for option type " << opt_type);
1253 }
1254 v6factories_[opt_type] = factory;
1255 return;
1256 }
1257 case Option::V4:
1258 {
1259 // Option 0 is special (a one octet-long, equal 0) PAD option. It is never
1260 // instantiated as an Option object, but rather consumed during packet parsing.
1261 if (opt_type == 0) {
1262 isc_throw(BadValue, "Cannot redefine PAD option (code=0)");
1263 }
1264 // Option 255 is never instantiated as an option object. It is special
1265 // (a one-octet equal 255) option that is added at the end of all options
1266 // during packet assembly. It is also silently consumed during packet parsing.
1267 if (opt_type > 254) {
1268 isc_throw(BadValue, "Too big option type for DHCPv4, only 0-254 allowed.");
1269 }
1270 if (v4factories_.find(opt_type) != v4factories_.end()) {
1271 isc_throw(BadValue, "There is already DHCPv4 factory registered "
1272 << "for option type " << opt_type);
1273 }
1274 v4factories_[opt_type] = factory;
1275 return;
1276 }
1277 default:
1278 isc_throw(BadValue, "Invalid universe type specified.");
1279 }
1280
1281 return;
1282}
1283
1284bool
1285LibDHCP::initOptionDefs() {
1286 for (uint32_t i = 0; OPTION_DEF_PARAMS[i].optionDefParams; ++i) {
1287 string space = OPTION_DEF_PARAMS[i].space;
1288 option_defs_[space] = OptionDefContainerPtr(new OptionDefContainer());
1289 initOptionSpace(option_defs_[space],
1290 OPTION_DEF_PARAMS[i].optionDefParams,
1291 OPTION_DEF_PARAMS[i].size);
1292 }
1293
1294 return (true);
1295}
1296
1297uint32_t
1298LibDHCP::optionSpaceToVendorId(const string& option_space) {
1299 // 8 is a minimal length of "vendor-X" format
1300 if ((option_space.size() < 8) || (option_space.substr(0,7) != "vendor-")) {
1301 return (0);
1302 }
1303
1304 int64_t check;
1305 try {
1306 // text after "vendor-", supposedly numbers only
1307 string x = option_space.substr(7);
1308
1309 check = boost::lexical_cast<int64_t>(x);
1310 } catch (const boost::bad_lexical_cast &) {
1311 return (0);
1312 }
1313
1314 if ((check < 0) || (check > std::numeric_limits<uint32_t>::max())) {
1315 return (0);
1316 }
1317
1318 // value is small enough to fit
1319 return (static_cast<uint32_t>(check));
1320}
1321
1322void
1324 size_t params_size) {
1325 // Container holding vendor options is typically not initialized, as it
1326 // is held in map of null pointers. We need to initialize here in this
1327 // case.
1328 if (!defs) {
1329 defs.reset(new OptionDefContainer());
1330 } else {
1331 defs->clear();
1332 }
1333
1334 for (size_t i = 0; i < params_size; ++i) {
1335 string encapsulates(params[i].encapsulates);
1336 if (!encapsulates.empty() && params[i].array) {
1337 isc_throw(isc::BadValue, "invalid standard option definition: "
1338 << "option with code '" << params[i].code
1339 << "' may not encapsulate option space '"
1340 << encapsulates << "' because the definition"
1341 << " indicates that this option comprises an array"
1342 << " of values");
1343 }
1344
1345 // Depending whether an option encapsulates an option space or not
1346 // we pick different constructor to create an instance of the option
1347 // definition.
1348 OptionDefinitionPtr definition;
1349 if (encapsulates.empty()) {
1350 // Option does not encapsulate any option space.
1351 definition.reset(new OptionDefinition(params[i].name,
1352 params[i].code,
1353 params[i].space,
1354 params[i].type,
1355 params[i].array));
1356 } else {
1357 // Option does encapsulate an option space.
1358 definition.reset(new OptionDefinition(params[i].name,
1359 params[i].code,
1360 params[i].space,
1361 params[i].type,
1362 params[i].encapsulates));
1363
1364 }
1365
1366 for (size_t rec = 0; rec < params[i].records_size; ++rec) {
1367 definition->addRecordField(params[i].records[rec]);
1368 }
1369
1370 try {
1371 definition->validate();
1372 } catch (const isc::Exception&) {
1373 // This is unlikely event that validation fails and may
1374 // be only caused by programming error. To guarantee the
1375 // data consistency we clear all option definitions that
1376 // have been added so far and pass the exception forward.
1377 defs->clear();
1378 throw;
1379 }
1380
1381 // option_defs is a multi-index container with no unique indexes
1382 // so push_back can't fail).
1383 static_cast<void>(defs->push_back(definition));
1384 }
1385}
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.
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:459
static void OptionFactoryRegister(Option::Universe u, uint16_t type, Option::Factory *factory)
Registers factory method that produces options of specific option types.
Definition: libdhcp++.cc:1245
static size_t unpackVendorOptions6(const uint32_t vendor_id, const OptionBuffer &buf, isc::dhcp::OptionCollection &options)
Parses provided buffer as DHCPv6 vendor options and creates Option objects.
Definition: libdhcp++.cc:810
static const OptionDefContainerPtr getOptionDefs(const std::string &space)
Returns collection of option definitions.
Definition: libdhcp++.cc:99
static bool shouldDeferOptionUnpack(const std::string &space, const uint16_t code)
Checks if an option unpacking has to be deferred.
Definition: libdhcp++.cc:280
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:287
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
Definition: libdhcp++.cc:218
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:126
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:168
static OptionDefContainerPtr getLastResortOptionDefs(const std::string &space)
Returns last resort option definitions for specified option space name.
Definition: libdhcp++.cc:271
static OptionDefContainerPtr getRuntimeOptionDefs(const std::string &space)
Returns runtime (non-standard) option definitions for specified option space name.
Definition: libdhcp++.cc:213
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition: libdhcp++.cc:242
static void clearRuntimeOptionDefs()
Removes runtime option definitions.
Definition: libdhcp++.cc:232
static void extendVendorOptions4(isc::dhcp::OptionCollection &options)
Extend vendor options from fused options in multiple OptionVendor or OptionVendorClass options and ad...
Definition: libdhcp++.cc:804
static void packOptions4(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options, bool top=false, bool check=true)
Stores DHCPv4 options in a buffer.
Definition: libdhcp++.cc:1012
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).
Definition: libdhcp++.cc:1057
static void revertRuntimeOptionDefs()
Reverts uncommitted changes to runtime option definitions.
Definition: libdhcp++.cc:237
static const OptionDefContainerPtr getVendorOptionDefs(Option::Universe u, const uint32_t vendor_id)
Returns option definitions for given universe and vendor.
Definition: libdhcp++.cc:109
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:1298
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:189
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)
Parses provided buffer as DHCPv6 options and creates Option objects.
Definition: libdhcp++.cc:311
static void packOptions6(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options)
Stores DHCPv6 options in a buffer.
Definition: libdhcp++.cc:1238
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition: libdhcp++.cc:247
static bool fuseOptions4(isc::dhcp::OptionCollection &options)
Fuse multiple options with the same option code in long options (RFC3396).
Definition: libdhcp++.cc:625
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:906
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.
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.
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.
Definition: option_vendor.h:29
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer &buf)
a factory function prototype
Definition: option.h:96
RAII object enabling duplication of the stored options and restoring the original options on destruct...
Definition: pkt.h:996
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:343
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:395
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:409
This class implements set/commit mechanism for a single object.
Definition: staged_value.h:32
@ D6O_RELAY_MSG
Definition: dhcp6.h:29
@ D6O_VENDOR_OPTS
Definition: dhcp6.h:37
#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)
Definition: libdhcp++.cc:1323
const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer())
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1420
boost::shared_ptr< OptionVendor > OptionVendorPtr
Pointer to a vendor option.
@ DHO_DHCP_MESSAGE_TYPE
Definition: dhcp4.h:122
@ DHO_HOST_NAME
Definition: dhcp4.h:81
@ DHO_VIVCO_SUBOPTIONS
Definition: dhcp4.h:188
@ 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_VIVSO_SUBOPTIONS
Definition: dhcp4.h:189
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:88
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:85
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 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
Encapsulation of option definition parameters and the structure size.
Parameters being used to make up an option definition.