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