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)
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");
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");
689 " into the option buffer: " << type);
697 boost::shared_ptr<Option4AddrLst> option(
new Option4AddrLst(type, begin,
706 boost::shared_ptr<Option6AddrLst> option(
new Option6AddrLst(type, begin,
735 boost::shared_ptr<Option6IA> option(
new Option6IA(type, begin, end));
745 "input option buffer has invalid size, expected at least "
748 boost::shared_ptr<Option6IAAddr> option(
new Option6IAAddr(type, begin,
759 "input option buffer has invalid size, expected at least "
762 boost::shared_ptr<Option6IAPrefix> option(
new Option6IAPrefix(type, begin,
772 boost::shared_ptr<OptionOpaqueDataTuples>
784 boost::shared_ptr<OptionOpaqueDataTuples>
795 const std::vector<uint8_t> data(begin, end);
799 InputBuffer in_buf(
static_cast<const void*
>(&data[0]), data.size());
800 std::vector<uint8_t> out_buf;
801 out_buf.reserve(data.size());
802 while (in_buf.getPosition() < in_buf.getLength()) {
808 if (labels.getDataLength() > 0) {
810 const uint8_t* label = labels.getData(&read_len);
811 out_buf.insert(out_buf.end(), label, label + read_len);
817 return OptionPtr(
new OptionCustom(*
this, u,
818 out_buf.begin(), out_buf.end()));
842 return (
OptionPtr(
new Option6ClientFqdn(begin, end)));
857 return (
OptionPtr(
new Option6StatusCode(begin, end)));
867 return (
OptionPtr(
new Option6PDExclude(begin, end)));
876 return (
OptionPtr(
new Option4SlpServiceScope(begin, end)));
880 return (
OptionPtr(
new Option4ClientFqdn(begin, end)));
901 if ((u ==
Option::V4) && haveCompressedFqdnListFormat()) {
902 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)
bool isV6() const
Convenience function to check for an IPv6 address.
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.
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.
const RecordFieldsCollection & getRecordFields() const
Return list of record fields.
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.
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.
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.
OptionDataType
Data types of DHCP option fields.
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
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 &instring)
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