Kea 2.5.5
option_definition.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2023 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <dhcp/dhcp4.h>
10#include <dhcp/dhcp6.h>
13#include <dhcp/option4_dnr.h>
16#include <dhcp/option6_dnr.h>
17#include <dhcp/option6_ia.h>
18#include <dhcp/option6_iaaddr.h>
22#include <dhcp/option_custom.h>
24#include <dhcp/option_int.h>
27#include <dhcp/option_string.h>
28#include <dhcp/option_vendor.h>
30#include <util/encode/hex.h>
31#include <dns/labelsequence.h>
32#include <dns/name.h>
33#include <util/strutil.h>
34#include <boost/algorithm/string/classification.hpp>
35#include <boost/algorithm/string/predicate.hpp>
36#include <boost/dynamic_bitset.hpp>
37#include <boost/make_shared.hpp>
38#include <sstream>
39
40using namespace std;
41using namespace isc::util;
42
43namespace isc {
44namespace dhcp {
45
46OptionDefinition::OptionDefinition(const std::string& name,
47 const uint16_t code,
48 const std::string& space,
49 const std::string& type,
50 const bool array_type /* = false */)
51 : name_(name),
52 code_(code),
53 type_(OPT_UNKNOWN_TYPE),
54 array_type_(array_type),
55 encapsulated_space_(""),
56 record_fields_(),
57 user_context_(),
58 option_space_name_(space) {
59 // Data type is held as enum value by this class.
60 // Use the provided option type string to get the
61 // corresponding enum value.
63}
64
65OptionDefinition::OptionDefinition(const std::string& name,
66 const uint16_t code,
67 const std::string& space,
68 const OptionDataType type,
69 const bool array_type /* = false */)
70 : name_(name),
71 code_(code),
72 type_(type),
73 array_type_(array_type),
74 encapsulated_space_(""),
75 option_space_name_(space){
76}
77
78OptionDefinition::OptionDefinition(const std::string& name,
79 const uint16_t code,
80 const std::string& space,
81 const std::string& type,
82 const char* encapsulated_space)
83 : name_(name),
84 code_(code),
85 // Data type is held as enum value by this class.
86 // Use the provided option type string to get the
87 // corresponding enum value.
88 type_(OptionDataTypeUtil::getDataType(type)),
89 array_type_(false),
90 encapsulated_space_(encapsulated_space),
91 record_fields_(),
92 user_context_(),
93 option_space_name_(space) {
94}
95
96OptionDefinition::OptionDefinition(const std::string& name,
97 const uint16_t code,
98 const std::string& space,
99 const OptionDataType type,
100 const char* encapsulated_space)
101 : name_(name),
102 code_(code),
103 type_(type),
104 array_type_(false),
105 encapsulated_space_(encapsulated_space),
106 record_fields_(),
107 user_context_(),
108 option_space_name_(space) {
109}
110
112OptionDefinition::create(const std::string& name,
113 const uint16_t code,
114 const std::string& space,
115 const std::string& type,
116 const bool array_type) {
117 return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
118}
119
121OptionDefinition::create(const std::string& name,
122 const uint16_t code,
123 const std::string& space,
124 const OptionDataType type,
125 const bool array_type) {
126 return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
127}
128
130OptionDefinition::create(const std::string& name,
131 const uint16_t code,
132 const std::string& space,
133 const std::string& type,
134 const char* encapsulated_space) {
135 return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
136}
137
139OptionDefinition::create(const std::string& name,
140 const uint16_t code,
141 const std::string& space,
142 const OptionDataType type,
143 const char* encapsulated_space) {
144 return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
145}
146
147bool
149 return (name_ == other.name_ &&
150 code_ == other.code_ &&
151 type_ == other.type_ &&
152 array_type_ == other.array_type_ &&
153 encapsulated_space_ == other.encapsulated_space_ &&
154 record_fields_ == other.record_fields_ &&
155 option_space_name_ == other.option_space_name_);
156}
157
158void
159OptionDefinition::addRecordField(const std::string& data_type_name) {
160 OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name);
161 addRecordField(data_type);
162}
163
164void
166 if (type_ != OPT_RECORD_TYPE) {
168 "'record' option type must be used instead of '"
170 << "' to add data fields to the record");
171 }
172 if (data_type >= OPT_RECORD_TYPE ||
173 data_type == OPT_ANY_ADDRESS_TYPE ||
174 data_type == OPT_EMPTY_TYPE) {
176 "attempted to add invalid data type '"
178 << "' to the record.");
179 }
180 record_fields_.push_back(data_type);
181}
182
186 OptionBufferConstIter end) const {
187
188 try {
189 // Some of the options are represented by the specialized classes derived
190 // from Option class (e.g. IA_NA, IAADDR). Although, they can be also
191 // represented by the generic classes, we want the object of the specialized
192 // type to be returned. Therefore, we first check that if we are dealing
193 // with such an option. If the instance is returned we just exit at this
194 // point. If not, we will search for a generic option type to return.
195 OptionPtr option = factorySpecialFormatOption(u, begin, end);
196 if (option) {
197 return (option);
198 }
199
200 switch (type_) {
201 case OPT_EMPTY_TYPE:
202 if (getEncapsulatedSpace().empty()) {
203 return (factoryEmpty(u, type));
204 } else {
205 return (OptionPtr(new OptionCustom(*this, u, begin, end)));
206 }
207
208 case OPT_BINARY_TYPE:
209 return (factoryGeneric(u, type, begin, end));
210
211 case OPT_UINT8_TYPE:
212 return (array_type_ ?
213 factoryIntegerArray<uint8_t>(u, type, begin, end) :
214 factoryInteger<uint8_t>(u, type, getEncapsulatedSpace(),
215 begin, end));
216
217 case OPT_INT8_TYPE:
218 return (array_type_ ?
219 factoryIntegerArray<int8_t>(u, type, begin, end) :
220 factoryInteger<int8_t>(u, type, getEncapsulatedSpace(),
221 begin, end));
222
223 case OPT_UINT16_TYPE:
224 return (array_type_ ?
225 factoryIntegerArray<uint16_t>(u, type, begin, end) :
226 factoryInteger<uint16_t>(u, type, getEncapsulatedSpace(),
227 begin, end));
228
229 case OPT_INT16_TYPE:
230 return (array_type_ ?
231 factoryIntegerArray<uint16_t>(u, type, begin, end) :
232 factoryInteger<int16_t>(u, type, getEncapsulatedSpace(),
233 begin, end));
234
235 case OPT_UINT32_TYPE:
236 return (array_type_ ?
237 factoryIntegerArray<uint32_t>(u, type, begin, end) :
238 factoryInteger<uint32_t>(u, type, getEncapsulatedSpace(),
239 begin, end));
240
241 case OPT_INT32_TYPE:
242 return (array_type_ ?
243 factoryIntegerArray<uint32_t>(u, type, begin, end) :
244 factoryInteger<int32_t>(u, type, getEncapsulatedSpace(),
245 begin, end));
246
248 // If definition specifies that an option is an array
249 // of IPv4 addresses we return an instance of specialized
250 // class (OptionAddrLst4). For non-array types there is no
251 // specialized class yet implemented so we drop through
252 // to return an instance of OptionCustom.
253 if (array_type_) {
254 return (factoryAddrList4(type, begin, end));
255 }
256 break;
257
259 // Handle array type only here (see comments for
260 // OPT_IPV4_ADDRESS_TYPE case).
261 if (array_type_) {
262 return (factoryAddrList6(type, begin, end));
263 }
264 break;
265
266 case OPT_STRING_TYPE:
267 return (OptionPtr(new OptionString(u, type, begin, end)));
268
269 case OPT_TUPLE_TYPE:
270 // Handle array type only here (see comments for
271 // OPT_IPV4_ADDRESS_TYPE case).
272 if (array_type_) {
273 return (factoryOpaqueDataTuples(u, type, begin, end));
274 }
275 break;
276
277 default:
278 // Do nothing. We will return generic option a few lines down.
279 ;
280 }
281 return (OptionPtr(new OptionCustom(*this, u, begin, end)));
282 } catch (const SkipThisOptionError&) {
283 // We need to throw this one as is.
284 throw;
285 } catch (const SkipRemainingOptionsError&) {
286 // We need to throw this one as is.
287 throw;
288 } catch (const Exception& ex) {
290 }
291}
292
295 const OptionBuffer& buf) const {
296 return (optionFactory(u, type, buf.begin(), buf.end()));
297}
298
301 const std::vector<std::string>& values) const {
302 OptionBuffer buf;
303 if (!array_type_ && type_ != OPT_RECORD_TYPE) {
304 if (values.empty()) {
305 if (type_ != OPT_EMPTY_TYPE) {
306 isc_throw(InvalidOptionValue, "no option value specified");
307 }
308 } else {
309 writeToBuffer(u, util::str::trim(values[0]), type_, buf);
310 }
311 } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
312 for (size_t i = 0; i < values.size(); ++i) {
313 writeToBuffer(u, util::str::trim(values[i]), type_, buf);
314 }
315 } else if (type_ == OPT_RECORD_TYPE) {
316 const RecordFieldsCollection& records = getRecordFields();
317 if (records.size() > values.size()) {
318 isc_throw(InvalidOptionValue, "number of data fields for the option"
319 << " type '" << getCode() << "' is greater than number"
320 << " of values provided.");
321 }
322 for (size_t i = 0; i < records.size(); ++i) {
323 writeToBuffer(u, util::str::trim(values[i]), records[i], buf);
324 }
325 if (array_type_ && (values.size() > records.size())) {
326 for (size_t i = records.size(); i < values.size(); ++i) {
327 writeToBuffer(u, util::str::trim(values[i]),
328 records.back(), buf);
329 }
330 }
331 }
332 return (optionFactory(u, type, buf.begin(), buf.end()));
333}
334
335void
337
338 using namespace boost::algorithm;
339
340 std::ostringstream err_str;
341
342 // Allowed characters in the option name are: lower or
343 // upper case letters, digits, underscores and hyphens.
344 // Empty option spaces are not allowed.
345 if (!all(name_, boost::is_from_range('a', 'z') ||
346 boost::is_from_range('A', 'Z') ||
347 boost::is_digit() ||
348 boost::is_any_of(std::string("-_"))) ||
349 name_.empty() ||
350 // Hyphens and underscores are not allowed at the beginning
351 // and at the end of the option name.
352 all(find_head(name_, 1), boost::is_any_of(std::string("-_"))) ||
353 all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) {
354 err_str << "invalid option name '" << name_ << "'";
355
356 } else if (!OptionSpace::validateName(option_space_name_)) {
357 err_str << "invalid option space name: '"
358 << option_space_name_ << "'";
359
360 } else if (!encapsulated_space_.empty() &&
361 !OptionSpace::validateName(encapsulated_space_)) {
362 err_str << "invalid encapsulated option space name: '"
363 << encapsulated_space_ << "'";
364
365 } else if (type_ >= OPT_UNKNOWN_TYPE) {
366 // Option definition must be of a known type.
367 err_str << "option type " << type_ << " not supported.";
368
369 } else if (type_ == OPT_RECORD_TYPE) {
370 // At least two data fields should be added to the record. Otherwise
371 // non-record option definition could be used.
372 if (getRecordFields().size() < 2) {
373 err_str << "invalid number of data fields: "
374 << getRecordFields().size()
375 << " specified for the option of type 'record'. Expected at"
376 << " least 2 fields.";
377
378 } else {
379 // If the number of fields is valid we have to check if their order
380 // is valid too. We check that string or binary data fields are not
381 // laid before other fields. But we allow that they are laid at the
382 // end of an option.
383 const RecordFieldsCollection& fields = getRecordFields();
384 for (RecordFieldsConstIter it = fields.begin();
385 it != fields.end(); ++it) {
386 if (*it == OPT_STRING_TYPE &&
387 it < fields.end() - 1) {
388 err_str << "string data field can't be laid before data"
389 << " fields of other types.";
390 break;
391 }
392 if (*it == OPT_BINARY_TYPE &&
393 it < fields.end() - 1) {
394 err_str << "binary data field can't be laid before data"
395 << " fields of other types.";
396 break;
397 }
398 // Empty type is not allowed within a record.
399 if (*it == OPT_EMPTY_TYPE) {
400 err_str << "empty data type can't be stored as a field in"
401 << " an option record.";
402 break;
403 }
404 }
405 // If the array flag is set the last field is an array.
406 if (err_str.str().empty() && array_type_) {
407 const OptionDataType& last_type = fields.back();
408 if (last_type == OPT_STRING_TYPE) {
409 err_str
410 << "array of strings is not a valid option definition.";
411 } else if (last_type == OPT_BINARY_TYPE) {
412 err_str << "array of binary values is not a valid option "
413 "definition.";
414 }
415 // Empty type was already checked.
416 }
417 }
418
419 } else if (array_type_) {
420 if (type_ == OPT_STRING_TYPE) {
421 // Array of strings is not allowed because there is no way
422 // to determine the size of a particular string and thus there
423 // it no way to tell when other data fields begin.
424 err_str << "array of strings is not a valid option definition.";
425 } else if (type_ == OPT_BINARY_TYPE) {
426 err_str << "array of binary values is not"
427 << " a valid option definition.";
428
429 } else if (type_ == OPT_EMPTY_TYPE) {
430 err_str << "array of empty value is not"
431 << " a valid option definition.";
432
433 }
434 }
435
436 // Non-empty error string means that we have hit the error. We throw
437 // exception and include error string.
438 if (!err_str.str().empty()) {
439 isc_throw(MalformedOptionDefinition, err_str.str());
440 }
441}
442
443bool
444OptionDefinition::haveCompressedFqdnListFormat() const {
445 return (haveType(OPT_FQDN_TYPE) && getArrayType());
446}
447
448bool
449OptionDefinition::convertToBool(const std::string& value_str) const {
450 // Case-insensitive check that the input is one of: "true" or "false".
451 if (boost::iequals(value_str, "true")) {
452 return (true);
453
454 } else if (boost::iequals(value_str, "false")) {
455 return (false);
456
457 }
458
459 // The input string is neither "true" nor "false", so let's check
460 // if it is not an integer wrapped in a string.
461 int result;
462 try {
463 result = boost::lexical_cast<int>(value_str);
464
465 } catch (const boost::bad_lexical_cast&) {
466 isc_throw(BadDataTypeCast, "unable to covert the value '"
467 << value_str << "' to boolean data type");
468 }
469 // The boolean value is encoded in DHCP option as 0 or 1. Therefore,
470 // we only allow a user to specify those values for options which
471 // have boolean fields.
472 if (result != 1 && result != 0) {
473 isc_throw(BadDataTypeCast, "unable to convert '" << value_str
474 << "' to boolean data type");
475 }
476 return (static_cast<bool>(result));
477}
478
479template<typename T>
480T
481OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str)
482 const {
483 // The lexical cast should be attempted when converting to an integer
484 // value only.
486 isc_throw(BadDataTypeCast,
487 "must not convert '" << value_str
488 << "' to non-integer data type");
489 }
490
491 // We use the 64-bit value here because it has wider range than
492 // any other type we use here and it allows to detect out of
493 // bounds conditions e.g. negative value specified for uintX_t
494 // data type. Obviously if the value exceeds the limits of int64
495 // this function will not handle that properly.
496 int64_t result = 0;
497 try {
498 result = boost::lexical_cast<int64_t>(value_str);
499
500 } catch (const boost::bad_lexical_cast&) {
501 // boost::lexical_cast does not handle hexadecimal
502 // but stringstream does so do it the hard way.
503 std::stringstream ss;
504 ss << std::hex << value_str;
505 ss >> result;
506 if (ss.fail() || !ss.eof()) {
507 isc_throw(BadDataTypeCast, "unable to convert the value '"
508 << value_str << "' to integer data type");
509 }
510 }
511 // Perform range checks.
513 if (result > numeric_limits<T>::max() ||
514 result < numeric_limits<T>::min()) {
515 isc_throw(BadDataTypeCast, "unable to convert '"
516 << value_str << "' to numeric type. This value is "
517 "expected to be in the range of "
518 << +numeric_limits<T>::min() << ".."
519 << +numeric_limits<T>::max());
520 }
521 }
522 return (static_cast<T>(result));
523}
524
525void
526OptionDefinition::writeToBuffer(Option::Universe u,
527 const std::string& value,
528 const OptionDataType type,
529 OptionBuffer& buf) const {
530 // We are going to write value given by value argument to the buffer.
531 // The actual type of the value is given by second argument. Check
532 // this argument to determine how to write this value to the buffer.
533 switch (type) {
534 case OPT_BINARY_TYPE:
536 return;
537 case OPT_BOOLEAN_TYPE:
538 // We encode the true value as 1 and false as 0 on 8 bits.
539 // That way we actually waste 7 bits but it seems to be the
540 // simpler way to encode boolean.
541 // @todo Consider if any other encode methods can be used.
542 OptionDataTypeUtil::writeBool(convertToBool(value), buf);
543 return;
544 case OPT_INT8_TYPE:
545 OptionDataTypeUtil::writeInt<uint8_t>
546 (lexicalCastWithRangeCheck<int8_t>(value),
547 buf);
548 return;
549 case OPT_INT16_TYPE:
550 OptionDataTypeUtil::writeInt<uint16_t>
551 (lexicalCastWithRangeCheck<int16_t>(value),
552 buf);
553 return;
554 case OPT_INT32_TYPE:
555 OptionDataTypeUtil::writeInt<uint32_t>
556 (lexicalCastWithRangeCheck<int32_t>(value),
557 buf);
558 return;
559 case OPT_UINT8_TYPE:
560 OptionDataTypeUtil::writeInt<uint8_t>
561 (lexicalCastWithRangeCheck<uint8_t>(value),
562 buf);
563 return;
564 case OPT_UINT16_TYPE:
565 OptionDataTypeUtil::writeInt<uint16_t>
566 (lexicalCastWithRangeCheck<uint16_t>(value),
567 buf);
568 return;
569 case OPT_UINT32_TYPE:
570 OptionDataTypeUtil::writeInt<uint32_t>
571 (lexicalCastWithRangeCheck<uint32_t>(value),
572 buf);
573 return;
576 {
577 asiolink::IOAddress address(value);
578 if (!address.isV4() && !address.isV6()) {
579 isc_throw(BadDataTypeCast, "provided address "
580 << address
581 << " is not a valid IPv4 or IPv6 address.");
582 }
584 return;
585 }
587 {
588 std::string txt = value;
589
590 // first let's remove any whitespaces
591 boost::erase_all(txt, " "); // space
592 boost::erase_all(txt, "\t"); // tabulation
593
594 // Is this prefix/len notation?
595 size_t pos = txt.find("/");
596
597 if (pos == string::npos) {
598 isc_throw(BadDataTypeCast, "provided address/prefix "
599 << value
600 << " is not valid.");
601 }
602
603 std::string txt_address = txt.substr(0, pos);
605 if (!address.isV6()) {
606 isc_throw(BadDataTypeCast, "provided address "
607 << txt_address
608 << " is not a valid IPv4 or IPv6 address.");
609 }
610
611 std::string txt_prefix = txt.substr(pos + 1);
612 uint8_t len = 0;
613 try {
614 // start with the first character after /
615 len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
616 } catch (...) {
617 isc_throw(BadDataTypeCast, "provided prefix "
618 << txt_prefix
619 << " is not valid.");
620 }
621
622 // Write a prefix.
623 OptionDataTypeUtil::writePrefix(PrefixLen(len), address, buf);
624
625 return;
626 }
627 case OPT_PSID_TYPE:
628 {
629 std::string txt = value;
630
631 // first let's remove any whitespaces
632 boost::erase_all(txt, " "); // space
633 boost::erase_all(txt, "\t"); // tabulation
634
635 // Is this prefix/len notation?
636 size_t pos = txt.find("/");
637
638 if (pos == string::npos) {
639 isc_throw(BadDataTypeCast, "provided PSID value "
640 << value << " is not valid");
641 }
642
643 const std::string txt_psid = txt.substr(0, pos);
644 const std::string txt_psid_len = txt.substr(pos + 1);
645
646 uint16_t psid = 0;
647 uint8_t psid_len = 0;
648
649 try {
650 psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
651 } catch (...) {
652 isc_throw(BadDataTypeCast, "provided PSID "
653 << txt_psid << " is not valid");
654 }
655
656 try {
657 psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
658 } catch (...) {
659 isc_throw(BadDataTypeCast, "provided PSID length "
660 << txt_psid_len << " is not valid");
661 }
662
663 OptionDataTypeUtil::writePsid(PSIDLen(psid_len), PSID(psid), buf);
664 return;
665 }
666 case OPT_STRING_TYPE:
668 return;
669 case OPT_FQDN_TYPE:
671 return;
672 case OPT_TUPLE_TYPE:
673 {
674 // In case of V4_SZTP_REDIRECT option #143, bootstrap-server-list is formatted
675 // as a list of tuples "uri-length;URI" where uri-length is coded on 2 octets,
676 // which is not typical for V4 Universe.
680 OptionDataTypeUtil::writeTuple(value, lft, buf);
681 return;
682 }
683 default:
684 // We hit this point because invalid option data type has been specified
685 // This may be the case because 'empty' or 'record' data type has been
686 // specified. We don't throw exception here because it will be thrown
687 // at the exit point from this function.
688 ;
689 }
690 isc_throw(isc::BadValue, "attempt to write invalid option data field type"
691 " into the option buffer: " << type);
692
693}
694
699 boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin,
700 end));
701 return (option);
702}
703
708 boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin,
709 end));
710 return (option);
711}
712
713
716 OptionPtr option(new Option(u, type));
717 return (option);
718}
719
724 OptionPtr option(new Option(u, type, begin, end));
725 return (option);
726}
727
732 if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) {
733 isc_throw(isc::OutOfRange, "input option buffer has invalid size,"
734 << " expected at least " << Option6IA::OPTION6_IA_LEN
735 << " bytes");
736 }
737 boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end));
738 return (option);
739}
740
745 if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) {
747 "input option buffer has invalid size, expected at least "
748 << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes");
749 }
750 boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin,
751 end));
752 return (option);
753}
754
759 if (std::distance(begin, end) < Option6IAPrefix::OPTION6_IAPREFIX_LEN) {
761 "input option buffer has invalid size, expected at least "
763 }
764 boost::shared_ptr<Option6IAPrefix> option(new Option6IAPrefix(type, begin,
765 end));
766 return (option);
767}
768
771 uint16_t type,
774 boost::shared_ptr<OptionOpaqueDataTuples>
775 option(new OptionOpaqueDataTuples(u, type, begin, end));
776
777 return (option);
778}
779
782 uint16_t type,
785 OpaqueDataTuple::LengthFieldType length_field_type) {
786 boost::shared_ptr<OptionOpaqueDataTuples>
787 option(new OptionOpaqueDataTuples(u, type, begin, end, length_field_type));
788
789 return (option);
790}
791
793OptionDefinition::factoryFqdnList(Option::Universe u,
795 OptionBufferConstIter end) const {
796
797 const std::vector<uint8_t> data(begin, end);
798 if (data.empty()) {
799 isc_throw(InvalidOptionValue, "FQDN list option has invalid length of 0");
800 }
801 InputBuffer in_buf(static_cast<const void*>(&data[0]), data.size());
802 std::vector<uint8_t> out_buf;
803 out_buf.reserve(data.size());
804 while (in_buf.getPosition() < in_buf.getLength()) {
805 // Reuse readFqdn and writeFqdn code but on the whole buffer
806 // so the DNS name code handles compression for us.
807 try {
808 isc::dns::Name name(in_buf);
809 isc::dns::LabelSequence labels(name);
810 if (labels.getDataLength() > 0) {
811 size_t read_len = 0;
812 const uint8_t* label = labels.getData(&read_len);
813 out_buf.insert(out_buf.end(), label, label + read_len);
814 }
815 } catch (const isc::Exception& ex) {
816 isc_throw(InvalidOptionValue, ex.what());
817 }
818 }
819 return OptionPtr(new OptionCustom(*this, u,
820 out_buf.begin(), out_buf.end()));
821}
822
824OptionDefinition::factorySpecialFormatOption(Option::Universe u,
826 OptionBufferConstIter end) const {
827 if ((u == Option::V6) && haveSpace(DHCP6_OPTION_SPACE)) {
828 switch (getCode()) {
829 case D6O_IA_NA:
830 case D6O_IA_PD:
831 // Record of 3 uint32, no array.
832 return (factoryIA6(getCode(), begin, end));
833
834 case D6O_IAADDR:
835 // Record of an IPv6 address followed by 2 uint32, no array.
836 return (factoryIAAddr6(getCode(), begin, end));
837
838 case D6O_IAPREFIX:
839 // Record of 2 uint32, one uint8 and an IPv6 address, no array.
840 return (factoryIAPrefix6(getCode(), begin, end));
841
842 case D6O_CLIENT_FQDN:
843 // Record of one uint8 and one FQDN, no array.
844 return (OptionPtr(new Option6ClientFqdn(begin, end)));
845
846 case D6O_VENDOR_OPTS:
847 // Type uint32.
848 // Vendor-Specific Information (option code 17).
849 return (OptionPtr(new OptionVendor(Option::V6, begin, end)));
850
851 case D6O_VENDOR_CLASS:
852 // Record of one uint32 and one string.
853 // Vendor Class (option code 16).
854 return (OptionPtr(new OptionVendorClass(Option::V6, begin, end)));
855
856 case D6O_STATUS_CODE:
857 // Record of one uint16 and one string.
858 // Status Code (option code 13).
859 return (OptionPtr(new Option6StatusCode(begin, end)));
860
862 // Array of tuples.
863 // Bootfile params (option code 60).
864 return (factoryOpaqueDataTuples(Option::V6, getCode(), begin, end));
865
866 case D6O_PD_EXCLUDE:
867 // Type IPv6 prefix.
868 // Prefix Exclude (option code 67),
869 return (OptionPtr(new Option6PDExclude(begin, end)));
870
871 case D6O_V6_DNR:
872 return (OptionPtr(new Option6Dnr(begin, end)));
873
874 default:
875 break;
876 }
877 } else if ((u == Option::V4) && haveSpace(DHCP4_OPTION_SPACE)) {
878 switch (getCode()) {
880 // Record of a boolean and a string.
881 return (OptionPtr(new Option4SlpServiceScope(begin, end)));
882
883 case DHO_FQDN:
884 // Record of 3 uint8 and a FQDN, no array.
885 return (OptionPtr(new Option4ClientFqdn(begin, end)));
886
888 // Record of uint32 followed by binary.
889 // V-I Vendor Class (option code 124).
890 return (OptionPtr(new OptionVendorClass(Option::V4, begin, end)));
891
893 // Type uint32.
894 // Vendor-Specific Information (option code 125).
895 return (OptionPtr(new OptionVendor(Option::V4, begin, end)));
896
898 // Array of tuples.
899 // DHCPv4 SZTP Redirect Option (option code 143).
901
902 case DHO_V4_DNR:
903 return (OptionPtr(new Option4Dnr(begin, end)));
904
905 default:
906 break;
907 }
908 }
909 if ((u == Option::V4) && haveCompressedFqdnListFormat()) {
910 return (factoryFqdnList(Option::V4, begin, end));
911 }
912 return (OptionPtr());
913}
914
915} // end of isc::dhcp namespace
916} // end of isc namespace
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Exception to be thrown when invalid option value has been specified for a particular option definitio...
Exception to be thrown when option definition is invalid.
LengthFieldType
Size of the length field in the tuple.
DHCPv4 Option class for handling list of IPv4 addresses.
DHCPv6 Option class for handling list of IPv6 addresses.
static const size_t OPTION6_IAADDR_LEN
length of the fixed part of the IAADDR option
Class that represents IAPREFIX option in DHCPv6.
static const size_t OPTION6_IAPREFIX_LEN
length of the fixed part of the IAPREFIX option
static const size_t OPTION6_IA_LEN
Length of IA_NA and IA_PD content.
Definition: option6_ia.h:26
Option with defined data fields represented as buffers that can be accessed using data field index.
Definition: option_custom.h:32
Utility class for option data types.
static void writeFqdn(const std::string &fqdn, std::vector< uint8_t > &buf, const bool downcase=false)
Append FQDN into a buffer.
static void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, std::vector< uint8_t > &buf)
Append prefix into a buffer.
static const std::string & getDataTypeName(const OptionDataType data_type)
Return option data type name from the data type enumerator.
static OptionDataType getDataType(const std::string &data_type)
Return option data type from its name.
static void writeBinary(const std::string &hex_str, std::vector< uint8_t > &buf)
Append hex-encoded binary values to a buffer.
static void writeAddress(const asiolink::IOAddress &address, std::vector< uint8_t > &buf)
Append IPv4 or IPv6 address to a buffer.
static void writePsid(const PSIDLen &psid_len, const PSID &psid, std::vector< uint8_t > &buf)
Append PSID length/value into a buffer.
static void writeString(const std::string &value, std::vector< uint8_t > &buf)
Write UTF8-encoded string into a buffer.
static void writeTuple(const std::string &value, OpaqueDataTuple::LengthFieldType lengthfieldtype, std::vector< uint8_t > &buf)
Append length and string tuple to a buffer.
static OpaqueDataTuple::LengthFieldType getTupleLenFieldType(Option::Universe u)
Returns Length Field Type for a tuple.
static void writeBool(const bool value, std::vector< uint8_t > &buf)
Append boolean value into a buffer.
Base class representing a DHCP option definition.
uint16_t getCode() const
Return option code.
OptionPtr optionFactory(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end) const
Option factory.
static OptionPtr factoryEmpty(Option::Universe u, uint16_t type)
Empty option factory.
static OptionPtr factoryIAPrefix6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IAPREFIX-type of option.
OptionDefinition(const std::string &name, const uint16_t code, const std::string &space, const std::string &type, const bool array_type=false)
Constructor.
static OptionPtr factoryAddrList6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with address list.
static OptionPtr factoryAddrList4(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with address list.
std::vector< OptionDataType >::const_iterator RecordFieldsConstIter
Const iterator for record data fields.
static OptionPtr factoryIAAddr6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IAADDR-type of option.
void addRecordField(const std::string &data_type_name)
Adds data field to the record.
bool equals(const OptionDefinition &other) const
Check if option definition is equal to other.
const RecordFieldsCollection & getRecordFields() const
Return list of record fields.
void validate() const
Check if the option definition is valid.
std::vector< OptionDataType > RecordFieldsCollection
List of fields within the record.
static OptionPtr factoryIA6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IA-type of option.
std::string getEncapsulatedSpace() const
Return name of the encapsulated option space.
static OptionDefinitionPtr create(const std::string &name, const uint16_t code, const std::string &space, const std::string &type, const bool array_type=false)
Factory function creating an instance of the OptionDefinition.
static OptionPtr factoryOpaqueDataTuples(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with tuple list.
bool getArrayType() const
Return array type indicator.
static OptionPtr factoryGeneric(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create generic option.
This class encapsulates a collection of data tuples and could be used by multiple options.
static bool validateName(const std::string &name)
Checks that the provided option space name is valid.
Definition: option_space.cc:26
Class which represents an option carrying a single string value.
Definition: option_string.h:28
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Definition: option.h:52
Exception thrown during option unpacking This exception is thrown when an error has occurred unpackin...
Definition: option.h:67
Light-weight Accessor to Name data.
Definition: labelsequence.h:35
The Name class encapsulates DNS names.
Definition: name.h:223
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
@ D6O_CLIENT_FQDN
Definition: dhcp6.h:59
@ D6O_VENDOR_OPTS
Definition: dhcp6.h:37
@ D6O_BOOTFILE_PARAM
Definition: dhcp6.h:80
@ D6O_IA_NA
Definition: dhcp6.h:23
@ D6O_PD_EXCLUDE
Definition: dhcp6.h:87
@ D6O_IA_PD
Definition: dhcp6.h:45
@ D6O_V6_DNR
Definition: dhcp6.h:159
@ D6O_IAADDR
Definition: dhcp6.h:25
@ D6O_VENDOR_CLASS
Definition: dhcp6.h:36
@ D6O_STATUS_CODE
Definition: dhcp6.h:33
@ D6O_IAPREFIX
Definition: dhcp6.h:46
const Name & name_
Definition: dns/message.cc:701
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
OptionDataType
Data types of DHCP option fields.
@ DHO_V4_SZTP_REDIRECT
Definition: dhcp4.h:200
@ DHO_SERVICE_SCOPE
Definition: dhcp4.h:148
@ DHO_VIVCO_SUBOPTIONS
Definition: dhcp4.h:189
@ DHO_V4_DNR
Definition: dhcp4.h:218
@ DHO_FQDN
Definition: dhcp4.h:150
@ DHO_VIVSO_SUBOPTIONS
Definition: dhcp4.h:190
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
Definition: option.h:30
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
string trim(const string &instring)
Trim Leading and Trailing Spaces.
Definition: strutil.cc:53
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
uint16_t code_
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE