35#include <boost/algorithm/string/classification.hpp>
36#include <boost/algorithm/string/predicate.hpp>
37#include <boost/algorithm/string/replace.hpp>
38#include <boost/dynamic_bitset.hpp>
39#include <boost/make_shared.hpp>
50 const std::string& space,
51 const std::string& type,
52 const bool array_type )
56 array_type_(array_type),
57 encapsulated_space_(
""),
60 option_space_name_(space) {
69 const std::string& space,
71 const bool array_type )
75 array_type_(array_type),
76 encapsulated_space_(
""),
77 option_space_name_(space){
82 const std::string& space,
83 const std::string& type,
84 const char* encapsulated_space)
92 encapsulated_space_(encapsulated_space),
95 option_space_name_(space) {
100 const std::string& space,
102 const char* encapsulated_space)
107 encapsulated_space_(encapsulated_space),
110 option_space_name_(space) {
116 const std::string& space,
117 const std::string& type,
118 const bool array_type) {
119 return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
125 const std::string& space,
127 const bool array_type) {
128 return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
134 const std::string& space,
135 const std::string& type,
136 const char* encapsulated_space) {
137 return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
143 const std::string& space,
145 const char* encapsulated_space) {
146 return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
151 return (name_ == other.name_ &&
152 code_ == other.code_ &&
153 type_ == other.type_ &&
154 array_type_ == other.array_type_ &&
155 encapsulated_space_ == other.encapsulated_space_ &&
156 record_fields_ == other.record_fields_ &&
157 option_space_name_ == other.option_space_name_);
170 "'record' option type must be used instead of '"
172 <<
"' to add data fields to the record");
178 "attempted to add invalid data type '"
180 <<
"' to the record.");
182 record_fields_.push_back(data_type);
190 bool convenient_notation)
const {
199 OptionPtr option = factorySpecialFormatOption(u, begin, end, convenient_notation);
219 return (array_type_ ?
220 factoryIntegerArray<uint8_t>(u, type, begin, end) :
225 return (array_type_ ?
226 factoryIntegerArray<int8_t>(u, type, begin, end) :
231 return (array_type_ ?
232 factoryIntegerArray<uint16_t>(u, type, begin, end) :
237 return (array_type_ ?
238 factoryIntegerArray<uint16_t>(u, type, begin, end) :
243 return (array_type_ ?
244 factoryIntegerArray<uint32_t>(u, type, begin, end) :
249 return (array_type_ ?
250 factoryIntegerArray<uint32_t>(u, type, begin, end) :
308 const std::vector<std::string>& values)
const {
311 if (values.empty()) {
327 std::ostringstream stream;
329 for (
auto val : values) {
330 boost::algorithm::replace_all(val,
",",
"\\,");
345 for (
size_t i = 0; i < values.size(); ++i) {
350 if (records.size() > values.size()) {
352 <<
" type '" <<
getCode() <<
"' is greater than number"
353 <<
" of values provided.");
355 for (
size_t i = 0; i < records.size(); ++i) {
358 if (array_type_ && (values.size() > records.size())) {
359 for (
size_t i = records.size(); i < values.size(); ++i) {
361 records.back(), buf);
371 using namespace boost::algorithm;
373 std::ostringstream err_str;
378 if (!all(name_, boost::is_from_range(
'a',
'z') ||
379 boost::is_from_range(
'A',
'Z') ||
381 boost::is_any_of(std::string(
"-_"))) ||
385 all(find_head(name_, 1), boost::is_any_of(std::string(
"-_"))) ||
386 all(find_tail(name_, 1), boost::is_any_of(std::string(
"-_")))) {
387 err_str <<
"invalid option name '" << name_ <<
"'";
390 err_str <<
"invalid option space name: '"
391 << option_space_name_ <<
"'";
393 }
else if (!encapsulated_space_.empty() &&
395 err_str <<
"invalid encapsulated option space name: '"
396 << encapsulated_space_ <<
"'";
400 err_str <<
"option type " << type_ <<
" not supported.";
406 err_str <<
"invalid number of data fields: "
408 <<
" specified for the option of type 'record'. Expected at"
409 <<
" least 2 fields.";
418 it != fields.end(); ++it) {
420 it < fields.end() - 1) {
421 err_str <<
"string data field can't be laid before data"
422 <<
" fields of other types.";
426 it < fields.end() - 1) {
427 err_str <<
"binary data field can't be laid before data"
428 <<
" fields of other types.";
433 err_str <<
"empty data type can't be stored as a field in"
434 <<
" an option record.";
439 err_str <<
"internal data type can't be stored as a field in"
440 <<
" an option record.";
445 if (err_str.str().empty() && array_type_) {
449 <<
"array of strings is not a valid option definition.";
451 err_str <<
"array of binary values is not a valid option "
458 }
else if (array_type_) {
463 err_str <<
"array of strings is not a valid option definition.";
465 err_str <<
"array of binary values is not"
466 <<
" a valid option definition.";
469 err_str <<
"array of empty value is not"
470 <<
" a valid option definition.";
473 err_str <<
"array of internal type value is not"
474 <<
" a valid option definition.";
481 if (!err_str.str().empty()) {
487OptionDefinition::haveCompressedFqdnListFormat()
const {
492OptionDefinition::convertToBool(
const std::string& value_str)
const {
494 if (boost::iequals(value_str,
"true")) {
497 }
else if (boost::iequals(value_str,
"false")) {
506 result = boost::lexical_cast<int>(value_str);
508 }
catch (
const boost::bad_lexical_cast&) {
509 isc_throw(BadDataTypeCast,
"unable to covert the value '"
510 << value_str <<
"' to boolean data type");
515 if (result != 1 && result != 0) {
516 isc_throw(BadDataTypeCast,
"unable to convert '" << value_str
517 <<
"' to boolean data type");
519 return (
static_cast<bool>(result));
524OptionDefinition::lexicalCastWithRangeCheck(
const std::string& value_str)
530 "must not convert '" << value_str
531 <<
"' to non-integer data type");
541 result = boost::lexical_cast<int64_t>(value_str);
543 }
catch (
const boost::bad_lexical_cast&) {
546 std::stringstream ss;
547 ss << std::hex << value_str;
549 if (ss.fail() || !ss.eof()) {
550 isc_throw(BadDataTypeCast,
"unable to convert the value '"
551 << value_str <<
"' to integer data type");
556 if (result > numeric_limits<T>::max() ||
557 result < numeric_limits<T>::min()) {
558 isc_throw(BadDataTypeCast,
"unable to convert '"
559 << value_str <<
"' to numeric type. This value is "
560 "expected to be in the range of "
561 << +numeric_limits<T>::min() <<
".."
562 << +numeric_limits<T>::max());
565 return (
static_cast<T
>(result));
570 const std::string& value,
588 OptionDataTypeUtil::writeInt<uint8_t>
589 (lexicalCastWithRangeCheck<int8_t>(value),
593 OptionDataTypeUtil::writeInt<uint16_t>
594 (lexicalCastWithRangeCheck<int16_t>(value),
598 OptionDataTypeUtil::writeInt<uint32_t>
599 (lexicalCastWithRangeCheck<int32_t>(value),
603 OptionDataTypeUtil::writeInt<uint8_t>
604 (lexicalCastWithRangeCheck<uint8_t>(value),
608 OptionDataTypeUtil::writeInt<uint16_t>
609 (lexicalCastWithRangeCheck<uint16_t>(value),
613 OptionDataTypeUtil::writeInt<uint32_t>
614 (lexicalCastWithRangeCheck<uint32_t>(value),
621 if (!address.isV4() && !address.isV6()) {
622 isc_throw(BadDataTypeCast,
"provided address "
624 <<
" is not a valid IPv4 or IPv6 address.");
631 std::string txt = value;
634 boost::erase_all(txt,
" ");
635 boost::erase_all(txt,
"\t");
638 size_t pos = txt.find(
"/");
640 if (pos == string::npos) {
641 isc_throw(BadDataTypeCast,
"provided address/prefix "
643 <<
" is not valid.");
646 std::string txt_address = txt.substr(0, pos);
648 if (!address.isV6()) {
649 isc_throw(BadDataTypeCast,
"provided address "
651 <<
" is not a valid IPv4 or IPv6 address.");
654 std::string txt_prefix = txt.substr(pos + 1);
658 len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
660 isc_throw(BadDataTypeCast,
"provided prefix "
662 <<
" is not valid.");
672 std::string txt = value;
675 boost::erase_all(txt,
" ");
676 boost::erase_all(txt,
"\t");
679 size_t pos = txt.find(
"/");
681 if (pos == string::npos) {
682 isc_throw(BadDataTypeCast,
"provided PSID value "
683 << value <<
" is not valid");
686 const std::string txt_psid = txt.substr(0, pos);
687 const std::string txt_psid_len = txt.substr(pos + 1);
690 uint8_t psid_len = 0;
693 psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
695 isc_throw(BadDataTypeCast,
"provided PSID "
696 << txt_psid <<
" is not valid");
700 psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
702 isc_throw(BadDataTypeCast,
"provided PSID length "
703 << txt_psid_len <<
" is not valid");
734 " into the option buffer: " << type);
742 boost::shared_ptr<Option4AddrLst> option(
new Option4AddrLst(type, begin,
751 boost::shared_ptr<Option6AddrLst> option(
new Option6AddrLst(type, begin,
780 boost::shared_ptr<Option6IA> option(
new Option6IA(type, begin, end));
790 "input option buffer has invalid size, expected at least "
793 boost::shared_ptr<Option6IAAddr> option(
new Option6IAAddr(type, begin,
804 "input option buffer has invalid size, expected at least "
807 boost::shared_ptr<Option6IAPrefix> option(
new Option6IAPrefix(type, begin,
817 boost::shared_ptr<OptionOpaqueDataTuples>
829 boost::shared_ptr<OptionOpaqueDataTuples>
840 const std::vector<uint8_t> data(begin, end);
844 InputBuffer in_buf(
static_cast<const void*
>(&data[0]), data.size());
845 std::vector<uint8_t> out_buf;
846 out_buf.reserve(data.size());
847 while (in_buf.getPosition() < in_buf.getLength()) {
853 if (labels.getDataLength() > 0) {
855 const uint8_t* label = labels.getData(&read_len);
856 out_buf.insert(out_buf.end(), label, label + read_len);
861 "invalid FQDN list content: " << ex.what());
864 isc_throw(InvalidOptionValue, ex.what());
867 return OptionPtr(
new OptionCustom(*
this, u,
868 out_buf.begin(), out_buf.end()));
875 bool convenient_notation)
const {
893 return (
OptionPtr(
new Option6ClientFqdn(begin, end)));
908 return (
OptionPtr(
new Option6StatusCode(begin, end)));
918 return (
OptionPtr(
new Option6PDExclude(begin, end)));
921 return (
OptionPtr(
new Option6Dnr(begin, end, convenient_notation)));
930 return (
OptionPtr(
new Option4SlpServiceScope(begin, end)));
934 return (
OptionPtr(
new Option4ClientFqdn(begin, end)));
937 return (
OptionPtr(
new OptionClasslessStaticRoute(begin, end, convenient_notation)));
955 return (
OptionPtr(
new Option4Dnr(begin, end, convenient_notation)));
961 if ((u ==
Option::V4) && haveCompressedFqdnListFormat()) {
962 return (factoryFqdnList(
Option::V4, begin, end));
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...
The IOAddress class represents an IP addresses (version agnostic)
Exception to be thrown when invalid option value has been specified for a particular option definitio...
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.
Option with defined data fields represented as buffers that can be accessed using data field index.
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.
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.
OptionPtr optionFactory(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end, bool convenient_notation=false) const
Option factory.
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.
Class which represents an option carrying a single string value.
static bool lenient_parsing_
Governs whether options should be parsed less strictly.
Universe
defines option universe DHCPv4 or DHCPv6
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Exception thrown during option unpacking This exception is thrown when an error has occurred unpackin...
Light-weight Accessor to Name data.
The Name class encapsulates DNS names.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
@ DHO_CLASSLESS_STATIC_ROUTE
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
OptionDataType
Data types of DHCP option fields.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
boost::shared_ptr< Option > OptionPtr
string trim(const string &input)
Trim leading and trailing spaces.
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE
static const bool integer_type