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