Kea: libdhcp++.cc Source File

| Kea 3.2.0-git

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