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,
191 size_t rec_level)
const {
200 OptionPtr option = factorySpecialFormatOption(u, begin, end,
223 return (array_type_ ?
226 begin, end, rec_level));
229 return (array_type_ ?
232 begin, end, rec_level));
235 return (array_type_ ?
238 begin, end, rec_level));
241 return (array_type_ ?
244 begin, end, rec_level));
247 return (array_type_ ?
250 begin, end, rec_level));
253 return (array_type_ ?
256 begin, end, rec_level));
312 const std::vector<std::string>& values)
const {
315 if (values.empty()) {
331 std::ostringstream stream;
333 for (
auto val : values) {
334 boost::algorithm::replace_all(val,
",",
"\\,");
349 for (
size_t i = 0; i < values.size(); ++i) {
354 if (records.size() > values.size()) {
356 <<
" type '" <<
getCode() <<
"' is greater than number"
357 <<
" of values provided.");
359 for (
size_t i = 0; i < records.size(); ++i) {
362 if (array_type_ && (values.size() > records.size())) {
363 for (
size_t i = records.size(); i < values.size(); ++i) {
365 records.back(), buf);
375 using namespace boost::algorithm;
377 std::ostringstream err_str;
382 if (!all(name_, boost::is_from_range(
'a',
'z') ||
383 boost::is_from_range(
'A',
'Z') ||
385 boost::is_any_of(std::string(
"-_"))) ||
389 all(find_head(name_, 1), boost::is_any_of(std::string(
"-_"))) ||
390 all(find_tail(name_, 1), boost::is_any_of(std::string(
"-_")))) {
391 err_str <<
"invalid option name '" << name_ <<
"'";
394 err_str <<
"invalid option space name: '"
395 << option_space_name_ <<
"'";
397 }
else if (!encapsulated_space_.empty() &&
399 err_str <<
"invalid encapsulated option space name: '"
400 << encapsulated_space_ <<
"'";
404 err_str <<
"option type " << type_ <<
" not supported.";
410 err_str <<
"invalid number of data fields: "
412 <<
" specified for the option of type 'record'. Expected at"
413 <<
" least 2 fields.";
422 it != fields.end(); ++it) {
424 it < fields.end() - 1) {
425 err_str <<
"string data field can't be laid before data"
426 <<
" fields of other types.";
430 it < fields.end() - 1) {
431 err_str <<
"binary data field can't be laid before data"
432 <<
" fields of other types.";
437 err_str <<
"empty data type can't be stored as a field in"
438 <<
" an option record.";
443 err_str <<
"internal data type can't be stored as a field in"
444 <<
" an option record.";
449 if (err_str.str().empty() && array_type_) {
453 <<
"array of strings is not a valid option definition.";
455 err_str <<
"array of binary values is not a valid option "
462 }
else if (array_type_) {
467 err_str <<
"array of strings is not a valid option definition.";
469 err_str <<
"array of binary values is not"
470 <<
" a valid option definition.";
473 err_str <<
"array of empty value is not"
474 <<
" a valid option definition.";
477 err_str <<
"array of internal type value is not"
478 <<
" a valid option definition.";
485 if (!err_str.str().empty()) {
491OptionDefinition::haveCompressedFqdnListFormat()
const {
496OptionDefinition::convertToBool(
const std::string& value_str)
const {
498 if (boost::iequals(value_str,
"true")) {
501 }
else if (boost::iequals(value_str,
"false")) {
510 result = boost::lexical_cast<int>(value_str);
512 }
catch (
const boost::bad_lexical_cast&) {
513 isc_throw(BadDataTypeCast,
"unable to covert the value '"
514 << value_str <<
"' to boolean data type");
519 if (result != 1 && result != 0) {
520 isc_throw(BadDataTypeCast,
"unable to convert '" << value_str
521 <<
"' to boolean data type");
523 return (
static_cast<bool>(result));
528OptionDefinition::lexicalCastWithRangeCheck(
const std::string& value_str)
534 "must not convert '" << value_str
535 <<
"' to non-integer data type");
545 result = boost::lexical_cast<int64_t>(value_str);
547 }
catch (
const boost::bad_lexical_cast&) {
550 std::stringstream ss;
551 ss << std::hex << value_str;
553 if (ss.fail() || !ss.eof()) {
554 isc_throw(BadDataTypeCast,
"unable to convert the value '"
555 << value_str <<
"' to integer data type");
560 if (result > numeric_limits<T>::max() ||
561 result < numeric_limits<T>::min()) {
562 isc_throw(BadDataTypeCast,
"unable to convert '"
563 << value_str <<
"' to numeric type. This value is "
564 "expected to be in the range of "
565 << +numeric_limits<T>::min() <<
".."
566 << +numeric_limits<T>::max());
569 return (
static_cast<T
>(result));
574 const std::string& value,
593 (lexicalCastWithRangeCheck<int8_t>(value),
598 (lexicalCastWithRangeCheck<int16_t>(value),
603 (lexicalCastWithRangeCheck<int32_t>(value),
608 (lexicalCastWithRangeCheck<uint8_t>(value),
613 (lexicalCastWithRangeCheck<uint16_t>(value),
618 (lexicalCastWithRangeCheck<uint32_t>(value),
624 asiolink::IOAddress address(value);
625 if (!address.isV4() && !address.isV6()) {
626 isc_throw(BadDataTypeCast,
"provided address "
628 <<
" is not a valid IPv4 or IPv6 address.");
635 std::string txt = value;
638 boost::erase_all(txt,
" ");
639 boost::erase_all(txt,
"\t");
642 size_t pos = txt.find(
"/");
644 if (pos == string::npos) {
645 isc_throw(BadDataTypeCast,
"provided address/prefix "
647 <<
" is not valid.");
650 std::string txt_address = txt.substr(0, pos);
651 isc::asiolink::IOAddress address = isc::asiolink::IOAddress(txt_address);
652 if (!address.
isV6()) {
653 isc_throw(BadDataTypeCast,
"provided address "
655 <<
" is not a valid IPv4 or IPv6 address.");
658 std::string txt_prefix = txt.substr(pos + 1);
662 len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
664 isc_throw(BadDataTypeCast,
"provided prefix "
666 <<
" is not valid.");
676 std::string txt = value;
679 boost::erase_all(txt,
" ");
680 boost::erase_all(txt,
"\t");
683 size_t pos = txt.find(
"/");
685 if (pos == string::npos) {
686 isc_throw(BadDataTypeCast,
"provided PSID value "
687 << value <<
" is not valid");
690 const std::string txt_psid = txt.substr(0, pos);
691 const std::string txt_psid_len = txt.substr(pos + 1);
694 uint8_t psid_len = 0;
697 psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
699 isc_throw(BadDataTypeCast,
"provided PSID "
700 << txt_psid <<
" is not valid");
704 psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
706 isc_throw(BadDataTypeCast,
"provided PSID length "
707 << txt_psid_len <<
" is not valid");
737 isc_throw(isc::BadValue,
"attempt to write invalid option data field type"
738 " into the option buffer: " << type);
746 boost::shared_ptr<Option4AddrLst> option(
new Option4AddrLst(type, begin,
755 boost::shared_ptr<Option6AddrLst> option(
new Option6AddrLst(type, begin,
785 boost::shared_ptr<Option6IA> option(
new Option6IA(type, begin, end, rec_level));
796 "input option buffer has invalid size, expected at least "
799 boost::shared_ptr<Option6IAAddr> option(
new Option6IAAddr(type, begin,
811 "input option buffer has invalid size, expected at least "
814 boost::shared_ptr<Option6IAPrefix> option(
new Option6IAPrefix(type, begin,
825 boost::shared_ptr<OptionOpaqueDataTuples>
837 boost::shared_ptr<OptionOpaqueDataTuples>
848 const std::vector<uint8_t>
data(begin, end);
853 std::vector<uint8_t> out_buf;
854 out_buf.reserve(
data.size());
855 while (in_buf.getPosition() < in_buf.getLength()) {
861 if (labels.getDataLength() > 0) {
863 const uint8_t* label = labels.getData(&read_len);
864 out_buf.insert(out_buf.end(), label, label + read_len);
866 }
catch (
const isc::Exception& ex) {
869 "invalid FQDN list content: " << ex.
what());
875 return OptionPtr(
new OptionCustom(*
this, u,
876 out_buf.begin(), out_buf.end()));
883 bool convenient_notation,
884 size_t rec_level)
const {
902 return (
OptionPtr(
new Option6ClientFqdn(begin, end)));
917 return (
OptionPtr(
new Option6StatusCode(begin, end)));
927 return (
OptionPtr(
new Option6PDExclude(begin, end)));
930 return (
OptionPtr(
new Option6Dnr(begin, end, convenient_notation)));
939 return (
OptionPtr(
new Option4SlpServiceScope(begin, end)));
943 return (
OptionPtr(
new Option4ClientFqdn(begin, end)));
946 return (
OptionPtr(
new OptionClasslessStaticRoute(begin, end, convenient_notation)));
964 return (
OptionPtr(
new Option4Dnr(begin, end, convenient_notation)));
970 if ((u ==
Option::V4) && haveCompressedFqdnListFormat()) {
971 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...
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 void writeInt(const T value, std::vector< uint8_t > &buf)
Append integer or unsigned integer value to 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.
uint16_t getCode() const
Return option code.
static OptionPtr factoryInteger(Option::Universe u, uint16_t type, const std::string &encapsulated_space, OptionBufferConstIter begin, OptionBufferConstIter end, size_t rec_level=0)
Factory function to create option with integer value.
static OptionPtr factoryEmpty(Option::Universe u, uint16_t type)
Empty option factory.
static OptionPtr factoryIntegerArray(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory function to create option with array of integer values.
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 factoryIAPrefix6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end, size_t rec_level=0)
Factory for IAPREFIX-type of option.
static OptionPtr factoryIA6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end, size_t rec_level=0)
Factory for IA-type of option.
static OptionPtr factoryAddrList6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
Factory to create option with address list.
OptionPtr optionFactory(Option::Universe u, uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end, bool convenient_notation=false, size_t rec_level=0) const
Option factory.
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, size_t rec_level=0)
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.
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
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
OptionDataType
Data types of DHCP option fields.
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