Kea: libdhcp++.cc Source File

| Kea 2.2.0

libdhcp++.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2022 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>
16#include <dhcp/option_definition.h>
17#include <dhcp/option_int_array.h>
18#include <dhcp/std_option_defs.h>
19#include <dhcp/docsis3_option_defs.h>
20#include <exceptions/exceptions.h>
21#include <exceptions/isc_assert.h>
22#include <util/buffer.h>
23
24#include <boost/lexical_cast.hpp>
25#include <boost/shared_array.hpp>
26#include <boost/shared_ptr.hpp>
27
28#include <limits>
29#include <list>
30
31using namespace std;
32using namespace isc::dhcp;
33using namespace isc::util;
34
35namespace isc {
36namespace dhcp {
37
38namespace {
39
43const OptionDefParamsEncapsulation OPTION_DEF_PARAMS[] = {
44 { STANDARD_V4_OPTION_DEFINITIONS, STANDARD_V4_OPTION_DEFINITIONS_SIZE, DHCP4_OPTION_SPACE },
45 { STANDARD_V6_OPTION_DEFINITIONS, STANDARD_V6_OPTION_DEFINITIONS_SIZE, DHCP6_OPTION_SPACE },
46 { DOCSIS3_V4_OPTION_DEFINITIONS, DOCSIS3_V4_OPTION_DEFINITIONS_SIZE, DOCSIS3_V4_OPTION_SPACE },
47 { DOCSIS3_V6_OPTION_DEFINITIONS, DOCSIS3_V6_OPTION_DEFINITIONS_SIZE, DOCSIS3_V6_OPTION_SPACE },
48 { ISC_V6_OPTION_DEFINITIONS, ISC_V6_OPTION_DEFINITIONS_SIZE, ISC_V6_OPTION_SPACE },
49 { MAPE_V6_OPTION_DEFINITIONS, MAPE_V6_OPTION_DEFINITIONS_SIZE, MAPE_V6_OPTION_SPACE },
50 { MAPT_V6_OPTION_DEFINITIONS, MAPT_V6_OPTION_DEFINITIONS_SIZE, MAPT_V6_OPTION_SPACE },
51 { LW_V6_OPTION_DEFINITIONS, LW_V6_OPTION_DEFINITIONS_SIZE, LW_V6_OPTION_SPACE },
52 { V4V6_RULE_OPTION_DEFINITIONS, V4V6_RULE_OPTION_DEFINITIONS_SIZE, V4V6_RULE_OPTION_SPACE },
53 { V4V6_BIND_OPTION_DEFINITIONS, V4V6_BIND_OPTION_DEFINITIONS_SIZE, V4V6_BIND_OPTION_SPACE },
54 { LAST_RESORT_V4_OPTION_DEFINITIONS, LAST_RESORT_V4_OPTION_DEFINITIONS_SIZE, LAST_RESORT_V4_OPTION_SPACE },
55 { NULL, 0, "" }
56};
57
58} // namespace
59
60} // namespace dhcp
61} // namespace isc
62
63// static array with factories for options
64std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
65
66// static array with factories for options
67std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
68
69// Static container with option definitions grouped by option space.
70 OptionDefContainers LibDHCP::option_defs_;
71
72// Static container with option definitions created in runtime.
73 StagedValue<OptionDefSpaceContainer> LibDHCP::runtime_option_defs_;
74
75// Null container.
76 const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer());
77
78// Those two vendor classes are used for cable modems:
79
81 const char* isc::dhcp::DOCSIS3_CLASS_MODEM = "docsis3.0";
82
84 const char* isc::dhcp::DOCSIS3_CLASS_EROUTER = "eRouter1.0";
85
86// Let's keep it in .cc file. Moving it to .h would require including optionDefParams
87// definitions there
88void initOptionSpace(OptionDefContainerPtr& defs,
89 const OptionDefParams* params,
90 size_t params_size);
91
92bool LibDHCP::initialized_ = LibDHCP::initOptionDefs();
93
94const OptionDefContainerPtr
95LibDHCP::getOptionDefs(const std::string& space) {
96 auto const& container = option_defs_.find(space);
97 if (container != option_defs_.end()) {
98 return (container->second);
99 }
100
101 return (null_option_def_container_);
102}
103
104const OptionDefContainerPtr
105LibDHCP::getVendorOptionDefs(const Option::Universe u, const uint32_t vendor_id) {
106 if (Option::V4 == u) {
107 if (VENDOR_ID_CABLE_LABS == vendor_id) {
108 return getOptionDefs(DOCSIS3_V4_OPTION_SPACE);
109 }
110 } else if (Option::V6 == u) {
111 if (VENDOR_ID_CABLE_LABS == vendor_id) {
112 return getOptionDefs(DOCSIS3_V6_OPTION_SPACE);
113 } else if (ENTERPRISE_ID_ISC == vendor_id) {
114 return getOptionDefs(ISC_V6_OPTION_SPACE);
115 }
116 }
117
118 return (null_option_def_container_);
119}
120
121 OptionDefinitionPtr
122LibDHCP::getOptionDef(const std::string& space, const uint16_t code) {
123 const OptionDefContainerPtr& defs = getOptionDefs(space);
124 const OptionDefContainerTypeIndex& idx = defs->get<1>();
125 const OptionDefContainerTypeRange& range = idx.equal_range(code);
126 if (range.first != range.second) {
127 return (*range.first);
128 }
129
130 return (OptionDefinitionPtr());
131}
132
133 OptionDefinitionPtr
134 LibDHCP::getOptionDef(const std::string& space, const std::string& name) {
135 const OptionDefContainerPtr& defs = getOptionDefs(space);
136 const OptionDefContainerNameIndex& idx = defs->get<2>();
137 const OptionDefContainerNameRange& range = idx.equal_range(name);
138 if (range.first != range.second) {
139 return (*range.first);
140 }
141
142 return (OptionDefinitionPtr());
143}
144
145 OptionDefinitionPtr
146 LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
147 const std::string& name) {
148 const OptionDefContainerPtr& defs = getVendorOptionDefs(u, vendor_id);
149
150 if (!defs) {
151 return (OptionDefinitionPtr());
152 }
153
154 const OptionDefContainerNameIndex& idx = defs->get<2>();
155 const OptionDefContainerNameRange& range = idx.equal_range(name);
156 if (range.first != range.second) {
157 return (*range.first);
158 }
159
160 return (OptionDefinitionPtr());
161}
162
163 OptionDefinitionPtr
164LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
165 const uint16_t code) {
166 const OptionDefContainerPtr& defs = getVendorOptionDefs(u, vendor_id);
167
168 if (!defs) {
169 // Weird universe or unknown vendor_id. We don't care. No definitions
170 // one way or another
171 // What is it anyway?
172 return (OptionDefinitionPtr());
173 }
174
175 const OptionDefContainerTypeIndex& idx = defs->get<1>();
176 const OptionDefContainerTypeRange& range = idx.equal_range(code);
177 if (range.first != range.second) {
178 return (*range.first);
179 }
180
181 return (OptionDefinitionPtr());
182}
183
184 OptionDefinitionPtr
185LibDHCP::getRuntimeOptionDef(const std::string& space, const uint16_t code) {
186 OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
187 const OptionDefContainerTypeIndex& index = container->get<1>();
188 const OptionDefContainerTypeRange& range = index.equal_range(code);
189 if (range.first != range.second) {
190 return (*range.first);
191 }
192
193 return (OptionDefinitionPtr());
194}
195
196 OptionDefinitionPtr
197 LibDHCP::getRuntimeOptionDef(const std::string& space, const std::string& name) {
198 OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
199 const OptionDefContainerNameIndex& index = container->get<2>();
200 const OptionDefContainerNameRange& range = index.equal_range(name);
201 if (range.first != range.second) {
202 return (*range.first);
203 }
204
205 return (OptionDefinitionPtr());
206}
207
208 OptionDefContainerPtr
209LibDHCP::getRuntimeOptionDefs(const std::string& space) {
210 return (runtime_option_defs_.getValue().getItems(space));
211}
212
213void
214LibDHCP::setRuntimeOptionDefs(const OptionDefSpaceContainer& defs) {
215 OptionDefSpaceContainer defs_copy;
216 std::list<std::string> option_space_names = defs.getOptionSpaceNames();
217 for (auto const& name : option_space_names) {
218 OptionDefContainerPtr container = defs.getItems(name);
219 for (auto const& def : *container) {
220 OptionDefinitionPtr def_copy(new OptionDefinition(*def));
221 defs_copy.addItem(def_copy);
222 }
223 }
224 runtime_option_defs_ = defs_copy;
225}
226
227void
228LibDHCP::clearRuntimeOptionDefs() {
229 runtime_option_defs_.reset();
230}
231
232void
233LibDHCP::revertRuntimeOptionDefs() {
234 runtime_option_defs_.revert();
235}
236
237void
238LibDHCP::commitRuntimeOptionDefs() {
239 runtime_option_defs_.commit();
240}
241
242 OptionDefinitionPtr
243LibDHCP::getLastResortOptionDef(const std::string& space, const uint16_t code) {
244 OptionDefContainerPtr container = getLastResortOptionDefs(space);
245 const OptionDefContainerTypeIndex& index = container->get<1>();
246 const OptionDefContainerTypeRange& range = index.equal_range(code);
247 if (range.first != range.second) {
248 return (*range.first);
249 }
250
251 return (OptionDefinitionPtr());
252}
253
254 OptionDefinitionPtr
255 LibDHCP::getLastResortOptionDef(const std::string& space, const std::string& name) {
256 OptionDefContainerPtr container = getLastResortOptionDefs(space);
257 const OptionDefContainerNameIndex& index = container->get<2>();
258 const OptionDefContainerNameRange& range = index.equal_range(name);
259 if (range.first != range.second) {
260 return (*range.first);
261 }
262
263 return (OptionDefinitionPtr());
264}
265
266 OptionDefContainerPtr
267LibDHCP::getLastResortOptionDefs(const std::string& space) {
268 if (space == DHCP4_OPTION_SPACE) {
269 return getOptionDefs(LAST_RESORT_V4_OPTION_SPACE);
270 }
271
272 return (null_option_def_container_);
273}
274
275bool
276LibDHCP::shouldDeferOptionUnpack(const std::string& space, const uint16_t code) {
277 return ((space == DHCP4_OPTION_SPACE) &&
278 ((code == DHO_VENDOR_ENCAPSULATED_OPTIONS) ||
279 ((code >= 224) && (code <= 254))));
280}
281
282 OptionPtr
283LibDHCP::optionFactory(Option::Universe u,
284 uint16_t type,
285 const OptionBuffer& buf) {
286 FactoryMap::iterator it;
287 if (u == Option::V4) {
288 it = v4factories_.find(type);
289 if (it == v4factories_.end()) {
290 isc_throw(BadValue, "factory function not registered "
291 "for DHCP v4 option type " << type);
292 }
293 } else if (u == Option::V6) {
294 it = v6factories_.find(type);
295 if (it == v6factories_.end()) {
296 isc_throw(BadValue, "factory function not registered "
297 "for DHCPv6 option type " << type);
298 }
299 } else {
300 isc_throw(BadValue, "invalid universe specified (expected "
301 "Option::V4 or Option::V6");
302 }
303 return (it->second(u, type, buf));
304}
305
306
307size_t
308LibDHCP::unpackOptions6(const OptionBuffer& buf,
309 const std::string& option_space,
310 isc::dhcp::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 = isc::util::readUint16(&buf[offset], 2);
346 offset += 2;
347
348 uint16_t opt_len = isc::util::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.
395 OptionDefContainerTypeRange range;
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,
458 const std::string& option_space,
459 isc::dhcp::OptionCollection& options,
460 std::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.
544 OptionDefContainerTypeRange range;
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 OptionPtr opt;
579 if (num_defs > 1) {
580 // Multiple options of the same code are not supported right now!
581 isc_throw(isc::Unexpected, "Internal error: multiple option"
582 " definitions for option type " <<
583 static_cast<int>(opt_type) <<
584 " returned. Currently it is not supported to initialize"
585 " multiple option definitions for the same option code."
586 " This will be supported once support for option spaces"
587 " is implemented");
588 } else if (num_defs == 0) {
589 opt = OptionPtr(new Option(Option::V4, opt_type,
590 buf.begin() + offset,
591 buf.begin() + offset + opt_len));
592 opt->setEncapsulatedSpace(DHCP4_OPTION_SPACE);
593 } else {
594 try {
595 // The option definition has been found. Use it to create
596 // the option instance from the provided buffer chunk.
597 const OptionDefinitionPtr& def = *(range.first);
598 isc_throw_assert(def);
599 opt = def->optionFactory(Option::V4, opt_type,
600 buf.begin() + offset,
601 buf.begin() + offset + opt_len);
602 } catch (const SkipThisOptionError&) {
603 opt.reset();
604 }
605 }
606
607 // If we have the option, insert it
608 if (opt) {
609 options.insert(std::make_pair(opt_type, opt));
610 }
611
612 offset += opt_len;
613 }
614 last_offset = offset;
615 return (last_offset);
616}
617
618bool
619LibDHCP::fuseOptions4(OptionCollection& options) {
620 bool result = false;
621 // We need to loop until all options have been fused.
622 for (;;) {
623 uint32_t found = 0;
624 bool found_suboptions = false;
625 // Iterate over all options in the container.
626 for (auto const& option : options) {
627 OptionPtr candidate = option.second;
628 OptionCollection& sub_options = candidate->getMutableOptions();
629 // Fuse suboptions recursively, if any.
630 if (sub_options.size()) {
631 // Fusing suboptions might result in new options with multiple
632 // options having the same code, so we need to iterate again
633 // until no option needs fusing.
634 found_suboptions = LibDHCP::fuseOptions4(sub_options);
635 if (found_suboptions) {
636 result = true;
637 }
638 }
639 OptionBuffer data;
640 OptionCollection suboptions;
641 // Make a copy of the options so we can safely iterate over the
642 // old container.
643 OptionCollection copy = options;
644 for (auto const& old_option : copy) {
645 if (old_option.first == option.first) {
646 // Copy the option data to the buffer.
647 data.insert(data.end(), old_option.second->getData().begin(),
648 old_option.second->getData().end());
649 suboptions.insert(old_option.second->getOptions().begin(),
650 old_option.second->getOptions().end());
651 // Other options might need fusing, so we need to iterate
652 // again until no options needs fusing.
653 found++;
654 }
655 }
656 if (found > 1) {
657 result = true;
658 // Erase the old options from the new container so that only the
659 // new option is present.
660 copy.erase(option.first);
661 // Create new option with entire data.
662 OptionPtr new_option(new Option(candidate->getUniverse(),
663 candidate->getType(), data));
664 // Recreate suboptions container.
665 new_option->getMutableOptions() = suboptions;
666 // Add the new option to the new container.
667 copy.insert(make_pair(candidate->getType(), new_option));
668 // After all options have been fused and new option added,
669 // update the option container with the new container.
670 options = copy;
671 break;
672 } else {
673 found = 0;
674 }
675 }
676 // No option needs fusing, so we can exit the loop.
677 if ((found <= 1) && !found_suboptions) {
678 break;
679 }
680 }
681 return (result);
682}
683
684size_t
685LibDHCP::unpackVendorOptions6(const uint32_t vendor_id,
686 const OptionBuffer& buf,
687 isc::dhcp::OptionCollection& options) {
688 size_t offset = 0;
689 size_t length = buf.size();
690
691 // Get the list of option definitions for this particular vendor-id
692 const OptionDefContainerPtr& option_defs =
693 LibDHCP::getVendorOptionDefs(Option::V6, vendor_id);
694
695 // Get the search index #1. It allows to search for option definitions
696 // using option code. If there's no such vendor-id space, we're out of luck
697 // anyway.
698 const OptionDefContainerTypeIndex* idx = NULL;
699 if (option_defs) {
700 idx = &(option_defs->get<1>());
701 }
702
703 // The buffer being read comprises a set of options, each starting with
704 // a two-byte type code and a two-byte length field.
705 while (offset < length) {
706 if (offset + 4 > length) {
707 isc_throw(SkipRemainingOptionsError,
708 "Vendor option parse failed: truncated header");
709 }
710
711 uint16_t opt_type = isc::util::readUint16(&buf[offset], 2);
712 offset += 2;
713
714 uint16_t opt_len = isc::util::readUint16(&buf[offset], 2);
715 offset += 2;
716
717 if (offset + opt_len > length) {
718 isc_throw(SkipRemainingOptionsError,
719 "Vendor option parse failed. Tried to parse "
720 << offset + opt_len << " bytes from " << length
721 << "-byte long buffer.");
722 }
723
724 OptionPtr opt;
725 opt.reset();
726
727 // If there is a definition for such a vendor option...
728 if (idx) {
729 // Get all definitions with the particular option
730 // code. Note that option code is non-unique within this
731 // container however at this point we expect to get one
732 // option definition with the particular code. If more are
733 // returned we report an error.
734 const OptionDefContainerTypeRange& range =
735 idx->equal_range(opt_type);
736 // Get the number of returned option definitions for the
737 // option code.
738 size_t num_defs = std::distance(range.first, range.second);
739
740 if (num_defs > 1) {
741 // Multiple options of the same code are not supported
742 // right now!
743 isc_throw(isc::Unexpected, "Internal error: multiple option"
744 " definitions for option type " << opt_type <<
745 " returned. Currently it is not supported to"
746 " initialize multiple option definitions for the"
747 " same option code. This will be supported once"
748 " support for option spaces is implemented");
749 } else if (num_defs == 1) {
750 // The option definition has been found. Use it to create
751 // the option instance from the provided buffer chunk.
752 const OptionDefinitionPtr& def = *(range.first);
753 isc_throw_assert(def);
754 opt = def->optionFactory(Option::V6, opt_type,
755 buf.begin() + offset,
756 buf.begin() + offset + opt_len);
757 }
758 }
759
760 // This can happen in one of 2 cases:
761 // 1. we do not have definitions for that vendor-space
762 // 2. we do have definitions, but that particular option was
763 // not defined
764
765 if (!opt) {
766 opt = OptionPtr(new Option(Option::V6, opt_type,
767 buf.begin() + offset,
768 buf.begin() + offset + opt_len));
769 }
770
771 // add option to options
772 if (opt) {
773 options.insert(std::make_pair(opt_type, opt));
774 }
775 offset += opt_len;
776 }
777
778 return (offset);
779}
780
781size_t
782LibDHCP::unpackVendorOptions4(const uint32_t vendor_id, const OptionBuffer& buf,
783 isc::dhcp::OptionCollection& options) {
784 size_t offset = 0;
785
786 // Get the list of standard option definitions.
787 const OptionDefContainerPtr& option_defs =
788 LibDHCP::getVendorOptionDefs(Option::V4, vendor_id);
789 // Get the search index #1. It allows to search for option definitions
790 // using option code.
791 const OptionDefContainerTypeIndex* idx = NULL;
792 if (option_defs) {
793 idx = &(option_defs->get<1>());
794 }
795
796 // The buffer being read comprises a set of options, each starting with
797 // a one-byte type code and a one-byte length field.
798 while (offset < buf.size()) {
799 // Note that Vendor-Specific info option (RFC3925) has a
800 // different option format than Vendor-Spec info for
801 // DHCPv6. (there's additional layer of data-length)
802 uint8_t data_len = buf[offset++];
803
804 if (offset + data_len > buf.size()) {
805 // The option is truncated.
806 isc_throw(SkipRemainingOptionsError,
807 "Attempt to parse truncated vendor option");
808 }
809
810 uint8_t offset_end = offset + data_len;
811
812 // beginning of data-chunk parser
813 while (offset < offset_end) {
814 uint8_t opt_type = buf[offset++];
815
816 // No DHO_END or DHO_PAD in vendor options
817
818 if (offset + 1 > offset_end) {
819 // opt_type must be cast to integer so as it is not
820 // treated as unsigned char value (a number is
821 // presented in error message).
822 isc_throw(SkipRemainingOptionsError,
823 "Attempt to parse truncated vendor option "
824 << static_cast<int>(opt_type));
825 }
826
827 uint8_t opt_len = buf[offset++];
828 if (offset + opt_len > offset_end) {
829 isc_throw(SkipRemainingOptionsError,
830 "Option parse failed. Tried to parse "
831 << offset + opt_len << " bytes from " << buf.size()
832 << "-byte long buffer.");
833 }
834
835 OptionPtr opt;
836 opt.reset();
837
838 if (idx) {
839 // Get all definitions with the particular option
840 // code. Note that option code is non-unique within
841 // this container however at this point we expect to
842 // get one option definition with the particular
843 // code. If more are returned we report an error.
844 const OptionDefContainerTypeRange& range =
845 idx->equal_range(opt_type);
846 // Get the number of returned option definitions for
847 // the option code.
848 size_t num_defs = std::distance(range.first, range.second);
849
850 if (num_defs > 1) {
851 // Multiple options of the same code are not
852 // supported right now!
853 isc_throw(isc::Unexpected, "Internal error: multiple"
854 " option definitions for option type "
855 << opt_type << " returned. Currently it is"
856 " not supported to initialize multiple option"
857 " definitions for the same option code."
858 " This will be supported once support for"
859 " option spaces is implemented");
860 } else if (num_defs == 1) {
861 // The option definition has been found. Use it to create
862 // the option instance from the provided buffer chunk.
863 const OptionDefinitionPtr& def = *(range.first);
864 isc_throw_assert(def);
865 opt = def->optionFactory(Option::V4, opt_type,
866 buf.begin() + offset,
867 buf.begin() + offset + opt_len);
868 }
869 }
870
871 if (!opt) {
872 opt = OptionPtr(new Option(Option::V4, opt_type,
873 buf.begin() + offset,
874 buf.begin() + offset + opt_len));
875 }
876
877 options.insert(std::make_pair(opt_type, opt));
878 offset += opt_len;
879
880 } // end of data-chunk
881
882 break; // end of the vendor block.
883 }
884 return (offset);
885}
886
887void
888LibDHCP::packOptions4(isc::util::OutputBuffer& buf,
889 const OptionCollection& options,
890 bool top, bool check) {
891 OptionCollection agent;
892 OptionPtr end;
893
894 // We only look for type when we're the top level
895 // call that starts packing for options for a packet.
896 // This way we avoid doing type logic in all ensuing
897 // recursive calls.
898 if (top) {
899 auto x = options.find(DHO_DHCP_MESSAGE_TYPE);
900 if (x != options.end()) {
901 x->second->pack(buf, check);
902 }
903 }
904
905 for (auto const& option : options) {
906 // TYPE is already done, RAI and END options must be last.
907 switch (option.first) {
908 case DHO_DHCP_MESSAGE_TYPE:
909 break;
910 case DHO_DHCP_AGENT_OPTIONS:
911 agent.insert(make_pair(DHO_DHCP_AGENT_OPTIONS, option.second));
912 break;
913 case DHO_END:
914 end = option.second;
915 break;
916 default:
917 option.second->pack(buf, check);
918 break;
919 }
920 }
921
922 // Add the RAI option if it exists.
923 for (auto const& option : agent) {
924 option.second->pack(buf, check);
925 }
926
927 // And at the end the END option.
928 if (end) {
929 end->pack(buf, check);
930 }
931}
932
933bool
934LibDHCP::splitOptions4(OptionCollection& options,
935 ScopedOptionsCopyContainer& scoped_options,
936 uint32_t used) {
937 bool result = false;
938 // We need to loop until all options have been split.
939 for (;;) {
940 bool found = false;
941 // Make a copy of the options so we can safely iterate over the
942 // old container.
943 OptionCollection copy = options;
944 // Iterate over all options in the container.
945 for (auto const& option : options) {
946 OptionPtr candidate = option.second;
947 OptionCollection& sub_options = candidate->getMutableOptions();
948 // Split suboptions recursively, if any.
949 OptionCollection distinct_options;
950 bool updated = false;
951 bool found_suboptions = false;
952 if (sub_options.size()) {
953 ScopedOptionsCopyPtr candidate_scoped_options(new ScopedSubOptionsCopy(candidate));
954 found_suboptions = LibDHCP::splitOptions4(sub_options, scoped_options,
955 used + candidate->getHeaderLen());
956 // Also split if the overflow is caused by adding the suboptions
957 // to the option data.
958 if (found_suboptions || candidate->len() > 255) {
959 updated = true;
960 scoped_options.push_back(candidate_scoped_options);
961 // Erase the old options from the new container so that only
962 // the new options are present.
963 copy.erase(option.first);
964 result = true;
965 // If there are suboptions which have been split, one parent
966 // option will be created for each of the chunk of the
967 // suboptions. If the suboptions have not been split,
968 // but they cause overflow when added to the option data,
969 // one parent option will contain the option data and one
970 // parent option will be created for each suboption.
971 // This will guarantee that none of the options plus
972 // suboptions will have more than 255 bytes.
973 for (auto sub_option : candidate->getMutableOptions()) {
974 OptionPtr data_sub_option(new Option(candidate->getUniverse(),
975 candidate->getType(),
976 OptionBuffer(0)));
977 data_sub_option->addOption(sub_option.second);
978 distinct_options.insert(make_pair(candidate->getType(), data_sub_option));
979 }
980 }
981 }
982 // Create a new option containing only data that needs to be split
983 // and no suboptions (which are inserted in completely separate
984 // options which are added at the end).
985 OptionPtr data_option(new Option(candidate->getUniverse(),
986 candidate->getType(),
987 OptionBuffer(candidate->getData().begin(),
988 candidate->getData().end())));
989 OutputBuffer buf(0);
990 data_option->pack(buf, false);
991 uint32_t header_len = candidate->getHeaderLen();
992 // At least 1 + header length bytes must be available.
993 if (used >= 255 - header_len) {
994 isc_throw(BadValue, "there is no space left to split option "
995 << candidate->getType() << " after parent already used "
996 << used);
997 }
998 // Maximum option buffer size is 255 - header size - buffer size
999 // already used by parent options.
1000 uint8_t len = 255 - header_len - used;
1001 // Current option size after split is the sum of the data and the
1002 // header size. The suboptions are serialized in separate options.
1003 // The header is duplicated in all new options, but the rest of the
1004 // data must be split and serialized.
1005 uint32_t size = buf.getLength() - header_len;
1006 // Only split if data does not fit in the current option.
1007 if (size > len) {
1008 // Erase the old option from the new container so that only new
1009 // options are present.
1010 if (!updated) {
1011 updated = true;
1012 // Erase the old options from the new container so that only
1013 // the new options are present.
1014 copy.erase(option.first);
1015 result = true;
1016 }
1017 uint32_t offset = 0;
1018 // Drain the option buffer in multiple new options until all
1019 // data is serialized.
1020 for (; offset != size;) {
1021 // Adjust the data length of the new option if remaining
1022 // data is less than the 255 - header size (for the last
1023 // option).
1024 if (size - offset < len) {
1025 len = size - offset;
1026 }
1027 // Create new option with data starting from offset and
1028 // containing truncated length.
1029 const uint8_t* data = static_cast<const uint8_t*>(buf.getData());
1030 data += header_len;
1031 OptionPtr new_option(new Option(candidate->getUniverse(),
1032 candidate->getType(),
1033 OptionBuffer(data + offset,
1034 data + offset + len)));
1035 // Adjust the offset for remaining data to be written to the
1036 // next new option.
1037 offset += len;
1038 // Add the new option to the new container.
1039 copy.insert(make_pair(candidate->getType(), new_option));
1040 }
1041 } else if (candidate->len() > 255 && size) {
1042 // Also split if the overflow is caused by adding the suboptions
1043 // to the option data (which should be of non zero size).
1044 // Add the new option to the new container.
1045 copy.insert(make_pair(candidate->getType(), data_option));
1046 }
1047 if (updated) {
1048 // Add the new options containing the split suboptions, if any,
1049 // to the new container.
1050 copy.insert(distinct_options.begin(), distinct_options.end());
1051 // After all new options have been split and added, update the
1052 // option container with the new container.
1053 options = copy;
1054 // Other options might need splitting, so we need to iterate
1055 // again until no option needs splitting.
1056 found = true;
1057 break;
1058 }
1059 }
1060 // No option needs splitting, so we can exit the loop.
1061 if (!found) {
1062 break;
1063 }
1064 }
1065 return (result);
1066}
1067
1068void
1069LibDHCP::packOptions6(isc::util::OutputBuffer& buf,
1070 const OptionCollection& options) {
1071 for (auto const& option : options) {
1072 option.second->pack(buf);
1073 }
1074}
1075
1076void
1077LibDHCP::OptionFactoryRegister(Option::Universe u,
1078 uint16_t opt_type,
1079 Option::Factory* factory) {
1080 switch (u) {
1081 case Option::V6:
1082 {
1083 if (v6factories_.find(opt_type) != v6factories_.end()) {
1084 isc_throw(BadValue, "There is already DHCPv6 factory registered "
1085 << "for option type " << opt_type);
1086 }
1087 v6factories_[opt_type] = factory;
1088 return;
1089 }
1090 case Option::V4:
1091 {
1092 // Option 0 is special (a one octet-long, equal 0) PAD option. It is never
1093 // instantiated as an Option object, but rather consumed during packet parsing.
1094 if (opt_type == 0) {
1095 isc_throw(BadValue, "Cannot redefine PAD option (code=0)");
1096 }
1097 // Option 255 is never instantiated as an option object. It is special
1098 // (a one-octet equal 255) option that is added at the end of all options
1099 // during packet assembly. It is also silently consumed during packet parsing.
1100 if (opt_type > 254) {
1101 isc_throw(BadValue, "Too big option type for DHCPv4, only 0-254 allowed.");
1102 }
1103 if (v4factories_.find(opt_type) != v4factories_.end()) {
1104 isc_throw(BadValue, "There is already DHCPv4 factory registered "
1105 << "for option type " << opt_type);
1106 }
1107 v4factories_[opt_type] = factory;
1108 return;
1109 }
1110 default:
1111 isc_throw(BadValue, "Invalid universe type specified.");
1112 }
1113
1114 return;
1115}
1116
1117bool
1118LibDHCP::initOptionDefs() {
1119 for (uint32_t i = 0; OPTION_DEF_PARAMS[i].optionDefParams; ++i) {
1120 std::string space = OPTION_DEF_PARAMS[i].space;
1121 option_defs_[space] = OptionDefContainerPtr(new OptionDefContainer);
1122 initOptionSpace(option_defs_[space],
1123 OPTION_DEF_PARAMS[i].optionDefParams,
1124 OPTION_DEF_PARAMS[i].size);
1125 }
1126
1127 return (true);
1128}
1129
1130uint32_t
1131LibDHCP::optionSpaceToVendorId(const std::string& option_space) {
1132 // 8 is a minimal length of "vendor-X" format
1133 if ((option_space.size() < 8) || (option_space.substr(0,7) != "vendor-")) {
1134 return (0);
1135 }
1136
1137 int64_t check;
1138 try {
1139 // text after "vendor-", supposedly numbers only
1140 std::string x = option_space.substr(7);
1141
1142 check = boost::lexical_cast<int64_t>(x);
1143 } catch (const boost::bad_lexical_cast &) {
1144 return (0);
1145 }
1146
1147 if ((check < 0) || (check > std::numeric_limits<uint32_t>::max())) {
1148 return (0);
1149 }
1150
1151 // value is small enough to fit
1152 return (static_cast<uint32_t>(check));
1153}
1154
1155void
1156initOptionSpace(OptionDefContainerPtr& defs,
1157 const OptionDefParams* params,
1158 size_t params_size) {
1159 // Container holding vendor options is typically not initialized, as it
1160 // is held in map of null pointers. We need to initialize here in this
1161 // case.
1162 if (!defs) {
1163 defs.reset(new OptionDefContainer());
1164 } else {
1165 defs->clear();
1166 }
1167
1168 for (size_t i = 0; i < params_size; ++i) {
1169 std::string encapsulates(params[i].encapsulates);
1170 if (!encapsulates.empty() && params[i].array) {
1171 isc_throw(isc::BadValue, "invalid standard option definition: "
1172 << "option with code '" << params[i].code
1173 << "' may not encapsulate option space '"
1174 << encapsulates << "' because the definition"
1175 << " indicates that this option comprises an array"
1176 << " of values");
1177 }
1178
1179 // Depending whether an option encapsulates an option space or not
1180 // we pick different constructor to create an instance of the option
1181 // definition.
1182 OptionDefinitionPtr definition;
1183 if (encapsulates.empty()) {
1184 // Option does not encapsulate any option space.
1185 definition.reset(new OptionDefinition(params[i].name,
1186 params[i].code,
1187 params[i].space,
1188 params[i].type,
1189 params[i].array));
1190 } else {
1191 // Option does encapsulate an option space.
1192 definition.reset(new OptionDefinition(params[i].name,
1193 params[i].code,
1194 params[i].space,
1195 params[i].type,
1196 params[i].encapsulates));
1197
1198 }
1199
1200 for (size_t rec = 0; rec < params[i].records_size; ++rec) {
1201 definition->addRecordField(params[i].records[rec]);
1202 }
1203
1204 try {
1205 definition->validate();
1206 } catch (const isc::Exception&) {
1207 // This is unlikely event that validation fails and may
1208 // be only caused by programming error. To guarantee the
1209 // data consistency we clear all option definitions that
1210 // have been added so far and pass the exception forward.
1211 defs->clear();
1212 throw;
1213 }
1214
1215 // option_defs is a multi-index container with no unique indexes
1216 // so push_back can't fail).
1217 static_cast<void>(defs->push_back(definition));
1218 }
1219}
buffer.h
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::Exception
This is a base class for exceptions thrown from the DNS library module.
Definition: exceptions/exceptions.h:23
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition: exceptions/exceptions.h:153
isc::dhcp::LibDHCP::unpackOptions4
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
isc::dhcp::LibDHCP::OptionFactoryRegister
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:1077
isc::dhcp::LibDHCP::unpackVendorOptions6
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:685
isc::dhcp::LibDHCP::getOptionDefs
static const OptionDefContainerPtr getOptionDefs(const std::string &space)
Returns collection of option definitions.
Definition: libdhcp++.cc:95
isc::dhcp::LibDHCP::shouldDeferOptionUnpack
static bool shouldDeferOptionUnpack(const std::string &space, const uint16_t code)
Checks if an option unpacking has to be deferred.
Definition: libdhcp++.cc:276
isc::dhcp::LibDHCP::optionFactory
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:283
isc::dhcp::LibDHCP::setRuntimeOptionDefs
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
Definition: libdhcp++.cc:214
isc::dhcp::LibDHCP::getOptionDef
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:122
isc::dhcp::LibDHCP::getVendorOptionDef
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:164
isc::dhcp::LibDHCP::getLastResortOptionDefs
static OptionDefContainerPtr getLastResortOptionDefs(const std::string &space)
Returns last resort option definitions for specified option space name.
Definition: libdhcp++.cc:267
isc::dhcp::LibDHCP::getRuntimeOptionDefs
static OptionDefContainerPtr getRuntimeOptionDefs(const std::string &space)
Returns runtime (non-standard) option definitions for specified option space name.
Definition: libdhcp++.cc:209
isc::dhcp::LibDHCP::commitRuntimeOptionDefs
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
Definition: libdhcp++.cc:238
isc::dhcp::LibDHCP::clearRuntimeOptionDefs
static void clearRuntimeOptionDefs()
Removes runtime option definitions.
Definition: libdhcp++.cc:228
isc::dhcp::LibDHCP::packOptions4
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:888
isc::dhcp::LibDHCP::splitOptions4
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:934
isc::dhcp::LibDHCP::revertRuntimeOptionDefs
static void revertRuntimeOptionDefs()
Reverts uncommitted changes to runtime option definitions.
Definition: libdhcp++.cc:233
isc::dhcp::LibDHCP::getVendorOptionDefs
static const OptionDefContainerPtr getVendorOptionDefs(Option::Universe u, const uint32_t vendor_id)
Returns option definitions for given universe and vendor.
Definition: libdhcp++.cc:105
isc::dhcp::LibDHCP::optionSpaceToVendorId
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:1131
isc::dhcp::LibDHCP::getRuntimeOptionDef
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:185
isc::dhcp::LibDHCP::unpackOptions6
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:308
isc::dhcp::LibDHCP::packOptions6
static void packOptions6(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options)
Stores DHCPv6 options in a buffer.
Definition: libdhcp++.cc:1069
isc::dhcp::LibDHCP::getLastResortOptionDef
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition: libdhcp++.cc:243
isc::dhcp::LibDHCP::fuseOptions4
static bool fuseOptions4(isc::dhcp::OptionCollection &options)
Fuse multiple options with the same option code in long options (RFC3396).
Definition: libdhcp++.cc:619
isc::dhcp::LibDHCP::unpackVendorOptions4
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:782
isc::dhcp::OptionDefSpaceContainer
Class of option definition space container.
Definition: option_definition.h:850
isc::dhcp::OptionDefSpaceContainer::addItem
void addItem(const OptionDefinitionPtr &def)
Adds a new option definition to the container.
Definition: option_definition.h:861
isc::dhcp::OptionDefinition
Base class representing a DHCP option definition.
Definition: option_definition.h:138
isc::dhcp::OptionSpaceContainer::getOptionSpaceNames
std::list< Selector > getOptionSpaceNames() const
Get a list of existing option spaces.
Definition: option_space_container.h:83
isc::dhcp::OptionSpaceContainer::getItems
ItemsContainerPtr getItems(const Selector &option_space) const
Get all items for the particular option space.
Definition: option_space_container.h:67
isc::dhcp::OptionVendor
This class represents vendor-specific information option.
Definition: option_vendor.h:30
isc::dhcp::Option
Definition: option.h:74
isc::dhcp::Option::Universe
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
isc::dhcp::Option::V6
@ V6
Definition: option.h:83
isc::dhcp::Option::V4
@ V4
Definition: option.h:83
isc::dhcp::Option::Factory
OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer &buf)
a factory function prototype
Definition: option.h:96
isc::dhcp::ScopedSubOptionsCopy
RAII object enabling duplication of the stored options and restoring the original options on destruct...
Definition: pkt.h:811
isc::dhcp::SkipRemainingOptionsError
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Definition: option.h:52
isc::dhcp::SkipThisOptionError
Exception thrown during option unpacking This exception is thrown when an error has occurred unpackin...
Definition: option.h:67
isc::util::OutputBuffer
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
isc::util::OutputBuffer::getLength
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
isc::util::OutputBuffer::getData
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:401
isc::util::StagedValue
This class implements set/commit mechanism for a single object.
Definition: staged_value.h:32
dhcp4.h
dhcp6.h
D6O_RELAY_MSG
@ D6O_RELAY_MSG
Definition: dhcp6.h:29
D6O_VENDOR_OPTS
@ D6O_VENDOR_OPTS
Definition: dhcp6.h:37
docsis3_option_defs.h
DOCSIS3_V6_OPTION_SPACE
#define DOCSIS3_V6_OPTION_SPACE
Definition: docsis3_option_defs.h:15
VENDOR_ID_CABLE_LABS
#define VENDOR_ID_CABLE_LABS
Definition: docsis3_option_defs.h:20
DOCSIS3_V4_OPTION_SPACE
#define DOCSIS3_V4_OPTION_SPACE
global docsis3 option spaces
Definition: docsis3_option_defs.h:14
exceptions.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:210
isc_assert.h
isc_throw_assert
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition: isc_assert.h:18
initOptionSpace
void initOptionSpace(OptionDefContainerPtr &defs, const OptionDefParams *params, size_t params_size)
Definition: libdhcp++.cc:1156
null_option_def_container_
const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer())
libdhcp++.h
isc::data::copy
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1360
isc::dhcp
Definition: dhcp4/client_handler.cc:20
isc::dhcp::DHO_DHCP_MESSAGE_TYPE
@ DHO_DHCP_MESSAGE_TYPE
Definition: dhcp4.h:122
isc::dhcp::DHO_HOST_NAME
@ DHO_HOST_NAME
Definition: dhcp4.h:81
isc::dhcp::DHO_END
@ DHO_END
Definition: dhcp4.h:228
isc::dhcp::DHO_PAD
@ DHO_PAD
Definition: dhcp4.h:69
isc::dhcp::DHO_DHCP_AGENT_OPTIONS
@ DHO_DHCP_AGENT_OPTIONS
Definition: dhcp4.h:151
isc::dhcp::DHO_VENDOR_ENCAPSULATED_OPTIONS
@ DHO_VENDOR_ENCAPSULATED_OPTIONS
Definition: dhcp4.h:112
isc::dhcp::OptionCollection
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition: option.h:40
isc::dhcp::DOCSIS3_V4_OPTION_DEFINITIONS
const OptionDefParams DOCSIS3_V4_OPTION_DEFINITIONS[]
Definitions of standard DHCPv4 options.
Definition: docsis3_option_defs.h:26
isc::dhcp::DOCSIS3_CLASS_EROUTER
const char * DOCSIS3_CLASS_EROUTER
The class as specified in vendor-class option by the devices.
Definition: libdhcp++.cc:84
isc::dhcp::OptionDefinitionPtr
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
Definition: option_definition.h:52
isc::dhcp::DOCSIS3_V6_OPTION_DEFINITIONS_SIZE
const int DOCSIS3_V6_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
Definition: docsis3_option_defs.h:79
isc::dhcp::OptionDefContainerNameRange
std::pair< OptionDefContainerNameIndex::const_iterator, OptionDefContainerNameIndex::const_iterator > OptionDefContainerNameRange
Pair of iterators to represent the range of options definitions having the same option name.
Definition: option_definition.h:842
isc::dhcp::DOCSIS3_CLASS_MODEM
const char * DOCSIS3_CLASS_MODEM
DOCSIS3.0 compatible cable modem.
Definition: libdhcp++.cc:81
isc::dhcp::OptionDefContainers
std::map< std::string, OptionDefContainerPtr > OptionDefContainers
Container that holds option definitions for various option spaces.
Definition: option_definition.h:821
isc::dhcp::ScopedOptionsCopyPtr
std::shared_ptr< ScopedSubOptionsCopy > ScopedOptionsCopyPtr
A pointer to a ScopedSubOptionsCopy object.
Definition: libdhcp++.h:30
isc::dhcp::OptionDefContainerNameIndex
OptionDefContainer::nth_index< 2 >::type OptionDefContainerNameIndex
Type of the index #2 - option name.
Definition: option_definition.h:836
isc::dhcp::OptionBuffer
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
isc::dhcp::OptionDefContainerTypeRange
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.
Definition: option_definition.h:833
isc::dhcp::OptionDefContainer
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.
Definition: option_definition.h:815
isc::dhcp::DOCSIS3_V4_OPTION_DEFINITIONS_SIZE
const int DOCSIS3_V4_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
Definition: docsis3_option_defs.h:34
isc::dhcp::OptionDefContainerTypeIndex
OptionDefContainer::nth_index< 1 >::type OptionDefContainerTypeIndex
Type of the index #1 - option type.
Definition: option_definition.h:827
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
isc::dhcp::ScopedOptionsCopyContainer
std::vector< ScopedOptionsCopyPtr > ScopedOptionsCopyContainer
A container of ScopedOptionsCopyPtr objects.
Definition: libdhcp++.h:32
isc::dhcp::DOCSIS3_V6_OPTION_DEFINITIONS
const OptionDefParams DOCSIS3_V6_OPTION_DEFINITIONS[]
Definitions of standard DHCPv6 options.
Definition: docsis3_option_defs.h:54
isc::dhcp::OptionDefContainerPtr
boost::shared_ptr< OptionDefContainer > OptionDefContainerPtr
Pointer to an option definition container.
Definition: option_definition.h:818
isc::util
Definition: edns.h:19
isc::util::readUint16
uint16_t readUint16(const void *buffer, size_t length)
Read Unsigned 16-Bit Integer from Buffer.
Definition: io_utilities.h:28
isc
Defines the logger used by the top-level component of kea-lfc.
Definition: agent_parser.cc:143
option6_ia.h
option6_iaaddr.h
option.h
option_definition.h
option_int_array.h
option_vendor.h
std_option_defs.h
V4V6_BIND_OPTION_SPACE
#define V4V6_BIND_OPTION_SPACE
Definition: std_option_defs.h:23
LAST_RESORT_V4_OPTION_SPACE
#define LAST_RESORT_V4_OPTION_SPACE
Definition: std_option_defs.h:24
DHCP4_OPTION_SPACE
#define DHCP4_OPTION_SPACE
global std option spaces
Definition: std_option_defs.h:16
ISC_V6_OPTION_SPACE
#define ISC_V6_OPTION_SPACE
Definition: std_option_defs.h:18
V4V6_RULE_OPTION_SPACE
#define V4V6_RULE_OPTION_SPACE
Definition: std_option_defs.h:22
MAPE_V6_OPTION_SPACE
#define MAPE_V6_OPTION_SPACE
Definition: std_option_defs.h:19
LW_V6_OPTION_SPACE
#define LW_V6_OPTION_SPACE
Definition: std_option_defs.h:21
DHCP6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
Definition: std_option_defs.h:17
MAPT_V6_OPTION_SPACE
#define MAPT_V6_OPTION_SPACE
Definition: std_option_defs.h:20
isc::dhcp::OptionDefParamsEncapsulation
Encapsulation of option definition parameters and the structure size.
Definition: option_data_types.h:80
isc::dhcp::OptionDefParams
Parameters being used to make up an option definition.
Definition: option_data_types.h:67
isc::dhcp::OptionDefParams::array
bool array
Definition: option_data_types.h:72
isc::dhcp::OptionDefParams::records_size
size_t records_size
Definition: option_data_types.h:74