Kea: libdhcp++.cc Source File

| Kea 3.0.2-git

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