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>
44 OptionDefinition::OptionDefinition(
const std::string& name,
46 const std::string& space,
47 const std::string& type,
48 const bool array_type )
52 array_type_(array_type),
53 encapsulated_space_(
""),
56 option_space_name_(space) {
65 const std::string& space,
67 const bool array_type )
71 array_type_(array_type),
72 encapsulated_space_(
""),
73 option_space_name_(space){
78 const std::string& space,
79 const std::string& type,
80 const char* encapsulated_space)
88 encapsulated_space_(encapsulated_space),
91 option_space_name_(space) {
96 const std::string& space,
98 const char* encapsulated_space)
103 encapsulated_space_(encapsulated_space),
106 option_space_name_(space) {
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));
121 const std::string& space,
123 const bool array_type) {
124 return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
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));
139 const std::string& space,
141 const char* encapsulated_space) {
142 return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
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_);
166 "'record' option type must be used instead of '"
168 <<
"' to add data fields to the record");
174 "attempted to add invalid data type '"
176 <<
"' to the record.");
178 record_fields_.push_back(data_type);
193 OptionPtr option = factorySpecialFormatOption(u, begin, end);
210 return (array_type_ ?
211 factoryIntegerArray<uint8_t>(u, type, begin, end) :
216 return (array_type_ ?
217 factoryIntegerArray<int8_t>(u, type, begin, end) :
222 return (array_type_ ?
223 factoryIntegerArray<uint16_t>(u, type, begin, end) :
228 return (array_type_ ?
229 factoryIntegerArray<uint16_t>(u, type, begin, end) :
234 return (array_type_ ?
235 factoryIntegerArray<uint32_t>(u, type, begin, end) :
240 return (array_type_ ?
241 factoryIntegerArray<uint32_t>(u, type, begin, end) :
299 const std::vector<std::string>& values)
const {
302 if (values.empty()) {
310 for (
size_t i = 0; i < values.size(); ++i) {
315 if (records.size() > values.size()) {
317 <<
" type '" <<
getCode() <<
"' is greater than number"
318 <<
" of values provided.");
320 for (
size_t i = 0; i < records.size(); ++i) {
323 if (array_type_ && (values.size() > records.size())) {
324 for (
size_t i = records.size(); i < values.size(); ++i) {
326 records.back(), buf);
336 using namespace boost::algorithm;
338 std::ostringstream err_str;
343 if (!all(
name_, boost::is_from_range(
'a',
'z') ||
344 boost::is_from_range(
'A',
'Z') ||
346 boost::is_any_of(std::string(
"-_"))) ||
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_ <<
"'";
355 err_str <<
"invalid option space name: '"
356 << option_space_name_ <<
"'";
358 }
else if (!encapsulated_space_.empty() &&
360 err_str <<
"invalid encapsulated option space name: '"
361 << encapsulated_space_ <<
"'";
365 err_str <<
"option type " << type_ <<
" not supported.";
371 err_str <<
"invalid number of data fields: "
373 <<
" specified for the option of type 'record'. Expected at"
374 <<
" least 2 fields.";
383 it != fields.end(); ++it) {
385 it < fields.end() - 1) {
386 err_str <<
"string data field can't be laid before data"
387 <<
" fields of other types.";
391 it < fields.end() - 1) {
392 err_str <<
"binary data field can't be laid before data"
393 <<
" fields of other types.";
398 err_str <<
"empty data type can't be stored as a field in"
399 <<
" an option record.";
404 if (err_str.str().empty() && array_type_) {
408 <<
"array of strings is not a valid option definition.";
410 err_str <<
"array of binary values is not a valid option "
417 }
else if (array_type_) {
422 err_str <<
"array of strings is not a valid option definition.";
424 err_str <<
"array of binary values is not"
425 <<
" a valid option definition.";
428 err_str <<
"array of empty value is not"
429 <<
" a valid option definition.";
436 if (!err_str.str().empty()) {
442 OptionDefinition::haveCompressedFqdnListFormat()
const {
447 OptionDefinition::convertToBool(
const std::string& value_str)
const {
449 if (boost::iequals(value_str,
"true")) {
452 }
else if (boost::iequals(value_str,
"false")) {
461 result = boost::lexical_cast<
int>(value_str);
463 }
catch (
const boost::bad_lexical_cast&) {
464 isc_throw(BadDataTypeCast,
"unable to covert the value '"
465 << value_str <<
"' to boolean data type");
470 if (result != 1 && result != 0) {
471 isc_throw(BadDataTypeCast,
"unable to convert '" << value_str
472 <<
"' to boolean data type");
474 return (static_cast<bool>(result));
479 OptionDefinition::lexicalCastWithRangeCheck(
const std::string& value_str)
483 if (!OptionDataTypeTraits<T>::integer_type) {
485 "must not convert '" << value_str
486 <<
"' to non-integer data type");
496 result = boost::lexical_cast<int64_t>(value_str);
498 }
catch (
const boost::bad_lexical_cast&) {
501 std::stringstream ss;
502 ss << std::hex << value_str;
504 if (ss.fail() || !ss.eof()) {
505 isc_throw(BadDataTypeCast,
"unable to convert the value '"
506 << value_str <<
"' to integer data type");
510 if (OptionDataTypeTraits<T>::integer_type) {
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());
520 return (static_cast<T>(result));
525 const std::string& value,
543 OptionDataTypeUtil::writeInt<uint8_t>
544 (lexicalCastWithRangeCheck<int8_t>(value),
548 OptionDataTypeUtil::writeInt<uint16_t>
549 (lexicalCastWithRangeCheck<int16_t>(value),
553 OptionDataTypeUtil::writeInt<uint32_t>
554 (lexicalCastWithRangeCheck<int32_t>(value),
558 OptionDataTypeUtil::writeInt<uint8_t>
559 (lexicalCastWithRangeCheck<uint8_t>(value),
563 OptionDataTypeUtil::writeInt<uint16_t>
564 (lexicalCastWithRangeCheck<uint16_t>(value),
568 OptionDataTypeUtil::writeInt<uint32_t>
569 (lexicalCastWithRangeCheck<uint32_t>(value),
575 asiolink::IOAddress address(value);
576 if (!address.isV4() && !address.isV6()) {
577 isc_throw(BadDataTypeCast,
"provided address "
579 <<
" is not a valid IPv4 or IPv6 address.");
586 std::string txt = value;
589 boost::erase_all(txt,
" ");
590 boost::erase_all(txt,
"\t");
593 size_t pos = txt.find(
"/");
595 if (pos == string::npos) {
596 isc_throw(BadDataTypeCast,
"provided address/prefix "
598 <<
" is not valid.");
601 std::string txt_address = txt.substr(0, pos);
603 if (!address.
isV6()) {
604 isc_throw(BadDataTypeCast,
"provided address "
606 <<
" is not a valid IPv4 or IPv6 address.");
609 std::string txt_prefix = txt.substr(pos + 1);
613 len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
615 isc_throw(BadDataTypeCast,
"provided prefix "
617 <<
" is not valid.");
627 std::string txt = value;
630 boost::erase_all(txt,
" ");
631 boost::erase_all(txt,
"\t");
634 size_t pos = txt.find(
"/");
636 if (pos == string::npos) {
637 isc_throw(BadDataTypeCast,
"provided PSID value "
638 << value <<
" is not valid");
641 const std::string txt_psid = txt.substr(0, pos);
642 const std::string txt_psid_len = txt.substr(pos + 1);
645 uint8_t psid_len = 0;
648 psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
650 isc_throw(BadDataTypeCast,
"provided PSID "
651 << txt_psid <<
" is not valid");
655 psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
657 isc_throw(BadDataTypeCast,
"provided PSID length "
658 << txt_psid_len <<
" is not valid");
685 " into the option buffer: " << type);
693 boost::shared_ptr<Option4AddrLst> option(
new Option4AddrLst(type, begin,
702 boost::shared_ptr<Option6AddrLst> option(
new Option6AddrLst(type, begin,
731 boost::shared_ptr<Option6IA> option(
new Option6IA(type, begin, end));
741 "input option buffer has invalid size, expected at least "
744 boost::shared_ptr<Option6IAAddr> option(
new Option6IAAddr(type, begin,
755 "input option buffer has invalid size, expected at least "
758 boost::shared_ptr<Option6IAPrefix> option(
new Option6IAPrefix(type, begin,
768 boost::shared_ptr<OptionOpaqueDataTuples>
779 const std::vector<uint8_t> data(begin, end);
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()) {
792 if (labels.getDataLength() > 0) {
794 const uint8_t* label = labels.getData(&read_len);
795 out_buf.insert(out_buf.end(), label, label + read_len);
801 return OptionPtr(
new OptionCustom(*
this, u,
802 out_buf.begin(), out_buf.end()));
826 return (
OptionPtr(
new Option6ClientFqdn(begin, end)));
841 return (
OptionPtr(
new Option6StatusCode(begin, end)));
851 return (
OptionPtr(
new Option6PDExclude(begin, end)));
860 return (
OptionPtr(
new Option4SlpServiceScope(begin, end)));
864 return (
OptionPtr(
new Option4ClientFqdn(begin, end)));
880 if ((u ==
Option::V4) && haveCompressedFqdnListFormat()) {
881 return (factoryFqdnList(
Option::V4, begin, end));
bool getArrayType() const
Return array type indicator.
The Name class encapsulates DNS names.
static const size_t OPTION6_IAADDR_LEN
length of the fixed part of the IAADDR option
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.
Exception to be thrown when invalid option value has been specified for a particular option definitio...
OptionPtr optionFactory(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end) const
Option factory.
Base class representing a DHCP option definition.
std::vector< OptionDataType > RecordFieldsCollection
List of fields within the record.
static OptionPtr factoryAddrList4(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with address list.
static void writePsid(const PSIDLen &psid_len, const PSID &psid, std::vector< uint8_t > &buf)
Append PSID length/value into a buffer.
static const std::string & getDataTypeName(const OptionDataType data_type)
Return option data type name from the data type enumerator.
Exception thrown during option unpacking This exception is thrown when an error has occurred...
DHCPv4 Option class for handling list of IPv4 addresses.
Utility class for option data types.
static bool validateName(const std::string &name)
Checks that the provided option space name is valid.
static void writeBool(const bool value, std::vector< uint8_t > &buf)
Append boolean value into a buffer.
boost::shared_ptr< Option > OptionPtr
static void writeFqdn(const std::string &fqdn, std::vector< uint8_t > &buf, const bool downcase=false)
Append FQDN into a buffer.
Universe
defines option universe DHCPv4 or DHCPv6
static void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, std::vector< uint8_t > &buf)
Append prefix into a buffer.
DHCPv6 Option class for handling list of IPv6 addresses.
static OptionPtr factoryEmpty(Option::Universe u, uint16_t type)
Empty option factory.
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 factoryIA6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IA-type of option.
bool equals(const OptionDefinition &other) const
Check if option definition is equal to other.
static OptionPtr factoryOpaqueDataTuples(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with tuple list.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
static OptionPtr factoryIAPrefix6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IAPREFIX-type of option.
static void writeTuple(const std::string &value, OpaqueDataTuple::LengthFieldType lengthfieldtype, std::vector< uint8_t > &buf)
Append length and string tuple to a buffer.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static OptionDataType getDataType(const std::string &data_type)
Return option data type from its name.
OptionDataType
Data types of DHCP option fields.
static OptionPtr factoryAddrList6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with address list.
void validate() const
Check if the option definition is valid.
uint16_t getCode() const
Return option code.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
LengthFieldType
Size of the length field in the tuple.
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-dhcp-ddns.
const RecordFieldsCollection & getRecordFields() const
Return list of record fields.
static OptionPtr factoryGeneric(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create generic option.
std::string getEncapsulatedSpace() const
Return name of the encapsulated option space.
static const size_t OPTION6_IAPREFIX_LEN
length of the fixed part of the IAPREFIX option
#define DHCP6_OPTION_SPACE
void addRecordField(const std::string &data_type_name)
Adds data field to the record.
A generic exception that is thrown if a function is called in a prohibited way.
static void writeAddress(const asiolink::IOAddress &address, std::vector< uint8_t > &buf)
Append IPv4 or IPv6 address to a buffer.
#define DHCP4_OPTION_SPACE
global std option spaces
static void writeBinary(const std::string &hex_str, std::vector< uint8_t > &buf)
Append hex-encoded binary values to a buffer.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
Exception thrown during option unpacking This exception is thrown when an error has occurred unpackin...
std::vector< OptionDataType >::const_iterator RecordFieldsConstIter
Const iterator for record data fields.
bool isV6() const
Convenience function to check for an IPv6 address.
string trim(const string &instring)
Trim Leading and Trailing Spaces.
static const size_t OPTION6_IA_LEN
Length of IA_NA and IA_PD content.
static OptionPtr factoryIAAddr6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory for IAADDR-type of option.
This class encapsulates a collection of data tuples and could be used by multiple options...
The IOAddress class represents an IP addresses (version agnostic)
Class that represents IAPREFIX option in DHCPv6.
Option with defined data fields represented as buffers that can be accessed using data field index...
static void writeString(const std::string &value, std::vector< uint8_t > &buf)
Write UTF8-encoded string into a buffer.
Class which represents an option carrying a single string value.
Light-weight Accessor to Name data.