26#include <boost/foreach.hpp>
27#include <boost/lexical_cast.hpp>
28#include <boost/shared_array.hpp>
29#include <boost/shared_ptr.hpp>
47 { STANDARD_V4_OPTION_DEFINITIONS, STANDARD_V4_OPTION_DEFINITIONS_SIZE,
DHCP4_OPTION_SPACE },
48 { STANDARD_V6_OPTION_DEFINITIONS, STANDARD_V6_OPTION_DEFINITIONS_SIZE,
DHCP6_OPTION_SPACE },
68map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
71map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
96bool LibDHCP::initialized_ = LibDHCP::initOptionDefs();
100 auto const& container = option_defs_.find(space);
101 if (container != option_defs_.end()) {
102 return (container->second);
117 }
else if (ENTERPRISE_ID_ISC == vendor_id) {
130 if (range.first != range.second) {
131 return (*range.first);
142 if (range.first != range.second) {
143 return (*range.first);
151 const string& name) {
160 if (range.first != range.second) {
161 return (*range.first);
169 const uint16_t code) {
181 if (range.first != range.second) {
182 return (*range.first);
193 if (range.first != range.second) {
194 return (*range.first);
205 if (range.first != range.second) {
206 return (*range.first);
214 return (runtime_option_defs_.getValue().getItems(space));
221 for (
auto const& name : option_space_names) {
223 for (
auto const& def : *container) {
228 runtime_option_defs_ = defs_copy;
233 runtime_option_defs_.reset();
238 runtime_option_defs_.revert();
243 runtime_option_defs_.commit();
251 if (range.first != range.second) {
252 return (*range.first);
263 if (range.first != range.second) {
264 return (*range.first);
283 ((code >= 224) && (code <= 254))));
290 FactoryMap::iterator it;
292 it = v4factories_.find(type);
293 if (it == v4factories_.end()) {
295 "for DHCP v4 option type " << type);
298 it = v6factories_.find(type);
299 if (it == v6factories_.end()) {
301 "for DHCPv6 option type " << type);
305 "Option::V4 or Option::V6");
307 return (it->second(u, type, buf));
313 size_t* relay_msg_offset ,
314 size_t* relay_msg_len ) {
316 size_t length = buf.size();
317 size_t last_offset = 0;
336 while (offset < length) {
338 last_offset = offset;
341 if (offset + 4 > length) {
343 return (last_offset);
347 uint16_t opt_type =
readUint16(&buf[offset], 2);
350 uint16_t opt_len =
readUint16(&buf[offset], 2);
353 if (offset + opt_len > length) {
362 return (last_offset);
365 if (opt_type ==
D6O_RELAY_MSG && relay_msg_offset && relay_msg_len) {
367 *relay_msg_offset = offset;
368 *relay_msg_len = opt_len;
376 if (offset + 4 > length) {
380 return (last_offset);
385 buf.begin() + offset + opt_len));
386 options.insert(std::make_pair(opt_type, vendor_opt));
403 range = idx.equal_range(opt_type);
404 num_defs = std::distance(range.first, range.second);
410 range = runtime_idx.equal_range(opt_type);
411 num_defs = std::distance(range.first, range.second);
418 " definitions for option type " << opt_type <<
419 " returned. Currently it is not supported to initialize"
420 " multiple option definitions for the same option code."
421 " This will be supported once support for option spaces"
423 }
else if (num_defs == 0) {
430 buf.begin() + offset,
431 buf.begin() + offset + opt_len));
438 opt = def->optionFactory(
Option::V6, opt_type,
439 buf.begin() + offset,
440 buf.begin() + offset + opt_len);
448 options.insert(std::make_pair(opt_type, opt));
454 last_offset = offset;
455 return (last_offset);
463 size_t last_offset = 0;
480 bool flex_pad = (check && (runtime_idx.count(
DHO_PAD) == 0));
481 bool flex_end = (check && (runtime_idx.count(
DHO_END) == 0));
485 while (offset < buf.size()) {
487 last_offset = offset;
490 uint8_t opt_type = buf[offset++];
495 if ((opt_type ==
DHO_END) && (space_is_dhcp4 || flex_end)) {
499 return (last_offset);
506 if ((opt_type ==
DHO_PAD) && (space_is_dhcp4 || flex_pad)) {
510 if (offset + 1 > buf.size()) {
518 return (last_offset);
521 uint8_t opt_len = buf[offset++];
522 if (offset + opt_len > buf.size()) {
527 return (last_offset);
535 if (space_is_dhcp4 && opt_len == 0 && opt_type ==
DHO_HOST_NAME) {
551 range = idx.equal_range(opt_type);
552 num_defs = std::distance(range.first, range.second);
558 range = runtime_idx.equal_range(opt_type);
559 num_defs = std::distance(range.first, range.second);
567 for (
auto const& existing : deferred) {
568 if (existing == opt_type) {
574 deferred.push_back(opt_type);
578 if (space_is_dhcp4 &&
588 " definitions for option type " <<
589 static_cast<int>(opt_type) <<
590 " returned. Currently it is not supported to initialize"
591 " multiple option definitions for the same option code."
592 " This will be supported once support for option spaces"
594 }
else if (num_defs == 0) {
596 buf.begin() + offset,
597 buf.begin() + offset + opt_len));
605 opt = def->optionFactory(
Option::V4, opt_type,
606 buf.begin() + offset,
607 buf.begin() + offset + opt_len);
615 options.insert(std::make_pair(opt_type, opt));
620 last_offset = offset;
621 return (last_offset);
630 bool found_suboptions =
false;
632 for (
auto const& option : options) {
636 if (sub_options.size()) {
641 if (found_suboptions) {
650 for (
auto const& old_option :
copy) {
651 if (old_option.first == option.first) {
653 data.insert(data.end(), old_option.second->getData().begin(),
654 old_option.second->getData().end());
655 suboptions.insert(old_option.second->getOptions().begin(),
656 old_option.second->getOptions().end());
666 copy.erase(option.first);
669 candidate->getType(), data));
671 new_option->getMutableOptions() = suboptions;
673 copy.insert(make_pair(candidate->getType(), new_option));
683 if ((found <= 1) && !found_suboptions) {
696 typedef vector<OpaqueDataTuple> TuplesCollection;
697 map<uint32_t, TuplesCollection> vendors_tuples;
699 BOOST_FOREACH(
auto const& it, range) {
701 auto const& data = it.second->getData();
703 while ((size = data.size() - offset) != 0) {
704 if (size <
sizeof(uint32_t)) {
707 "Truncated vendor-class information option"
708 <<
", length=" << size);
710 uint32_t vendor_id =
readUint32(&data[offset], data.size());
715 data.begin() + offset, data.end());
716 vendors_tuples[vendor_id].push_back(tuple);
717 offset += tuple.getTotalLength();
727 if (vendors_tuples.empty()) {
733 for (
auto const& vendor : vendors_tuples) {
734 if (vendor.second.empty()) {
739 for (
size_t i = 0; i < vendor.second.size(); ++i) {
741 vendor_opt->setTuple(0, vendor.second[0]);
743 vendor_opt->addTuple(vendor.second[i]);
756 map<uint32_t, OptionCollection> vendors_data;
758 BOOST_FOREACH(
auto const& it, range) {
760 auto const& data = it.second->getData();
762 while ((size = data.size() - offset) != 0) {
763 if (size <
sizeof(uint32_t)) {
766 "Truncated vendor-specific information option"
767 <<
", length=" << size);
769 uint32_t vendor_id =
readUint32(&data[offset], data.size());
771 const OptionBuffer vendor_buffer(data.begin() + offset, data.end());
774 vendors_data[vendor_id]);
784 if (vendors_data.empty()) {
790 for (
auto const& vendor : vendors_data) {
792 for (
auto const& option : vendor.second) {
793 vendor_opt->addOption(option.second);
805 extendVivco(options);
806 extendVivso(options);
813 size_t length = buf.size();
824 idx = &(option_defs->get<1>());
829 while (offset < length) {
830 if (offset + 4 > length) {
832 "Vendor option parse failed: truncated header");
835 uint16_t opt_type =
readUint16(&buf[offset], 2);
838 uint16_t opt_len =
readUint16(&buf[offset], 2);
841 if (offset + opt_len > length) {
843 "Vendor option parse failed. Tried to parse "
844 << offset + opt_len <<
" bytes from " << length
845 <<
"-byte long buffer.");
859 idx->equal_range(opt_type);
862 size_t num_defs = std::distance(range.first, range.second);
868 " definitions for option type " << opt_type <<
869 " returned. Currently it is not supported to"
870 " initialize multiple option definitions for the"
871 " same option code. This will be supported once"
872 " support for option spaces is implemented");
873 }
else if (num_defs == 1) {
878 opt = def->optionFactory(
Option::V6, opt_type,
879 buf.begin() + offset,
880 buf.begin() + offset + opt_len);
891 buf.begin() + offset,
892 buf.begin() + offset + opt_len));
897 options.insert(std::make_pair(opt_type, opt));
917 idx = &(option_defs->get<1>());
922 while (offset < buf.size()) {
926 uint8_t data_len = buf[offset++];
928 if (offset + data_len > buf.size()) {
931 "Attempt to parse truncated vendor option");
934 uint8_t offset_end = offset + data_len;
937 while (offset < offset_end) {
938 uint8_t opt_type = buf[offset++];
942 if (offset + 1 > offset_end) {
947 "Attempt to parse truncated vendor option "
948 <<
static_cast<int>(opt_type));
951 uint8_t opt_len = buf[offset++];
952 if (offset + opt_len > offset_end) {
954 "Option parse failed. Tried to parse "
955 << offset + opt_len <<
" bytes from " << buf.size()
956 <<
"-byte long buffer.");
969 idx->equal_range(opt_type);
972 size_t num_defs = std::distance(range.first, range.second);
978 " option definitions for option type "
979 << opt_type <<
" returned. Currently it is"
980 " not supported to initialize multiple option"
981 " definitions for the same option code."
982 " This will be supported once support for"
983 " option spaces is implemented");
984 }
else if (num_defs == 1) {
989 opt = def->optionFactory(
Option::V4, opt_type,
990 buf.begin() + offset,
991 buf.begin() + offset + opt_len);
997 buf.begin() + offset,
998 buf.begin() + offset + opt_len));
1001 options.insert(std::make_pair(opt_type, opt));
1013 bool top,
bool check) {
1023 if (x != options.end()) {
1024 x->second->pack(buf, check);
1028 for (
auto const& option : options) {
1030 switch (option.first) {
1037 end = option.second;
1040 option.second->pack(buf, check);
1046 for (
auto const& option : agent) {
1047 option.second->pack(buf, check);
1052 end->pack(buf, check);
1060 bool result =
false;
1066 if (tries == std::numeric_limits<uint16_t>::max()) {
1068 << tries <<
" times.");
1075 for (
auto const& option : options) {
1080 bool updated =
false;
1081 bool found_suboptions =
false;
1096 if (sub_options.size()) {
1100 used + candidate->getHeaderLen());
1115 if (found_suboptions || candidate->len() > (255 - used)) {
1118 scoped_options.push_back(candidate_scoped_options);
1121 copy.erase(option.first);
1131 for (
auto const& sub_option : candidate->getMutableOptions()) {
1133 candidate->getType(),
1135 data_sub_option->addOption(sub_option.second);
1136 distinct_options.insert(make_pair(candidate->getType(), data_sub_option));
1145 candidate->getType(),
1147 candidate->getData().end())));
1149 data_option->pack(buf,
false);
1150 uint32_t header_len = candidate->getHeaderLen();
1152 if (used >= 255 - header_len) {
1154 << candidate->getType() <<
" after parent already used "
1159 uint8_t len = 255 - header_len - used;
1164 uint32_t size = buf.
getLength() - header_len;
1182 copy.erase(option.first);
1185 uint32_t offset = 0;
1188 for (; offset != size;) {
1192 if (size - offset < len) {
1193 len = size - offset;
1197 const uint8_t* data = buf.
getData();
1200 candidate->getType(),
1202 data + offset + len)));
1207 copy.insert(make_pair(candidate->getType(), new_option));
1209 }
else if ((candidate->len() > (255 - used)) && size) {
1214 copy.insert(make_pair(candidate->getType(), data_option));
1219 copy.insert(distinct_options.begin(), distinct_options.end());
1239 for (
auto const& option : options) {
1240 option.second->pack(buf);
1250 if (v6factories_.find(opt_type) != v6factories_.end()) {
1252 <<
"for option type " << opt_type);
1254 v6factories_[opt_type] = factory;
1261 if (opt_type == 0) {
1267 if (opt_type > 254) {
1270 if (v4factories_.find(opt_type) != v4factories_.end()) {
1272 <<
"for option type " << opt_type);
1274 v4factories_[opt_type] = factory;
1285LibDHCP::initOptionDefs() {
1286 for (uint32_t i = 0; OPTION_DEF_PARAMS[i].optionDefParams; ++i) {
1287 string space = OPTION_DEF_PARAMS[i].space;
1290 OPTION_DEF_PARAMS[i].optionDefParams,
1291 OPTION_DEF_PARAMS[i].size);
1300 if ((option_space.size() < 8) || (option_space.substr(0,7) !=
"vendor-")) {
1307 string x = option_space.substr(7);
1309 check = boost::lexical_cast<int64_t>(x);
1310 }
catch (
const boost::bad_lexical_cast &) {
1314 if ((check < 0) || (check > std::numeric_limits<uint32_t>::max())) {
1319 return (
static_cast<uint32_t
>(check));
1324 size_t params_size) {
1334 for (
size_t i = 0; i < params_size; ++i) {
1335 string encapsulates(params[i].encapsulates);
1336 if (!encapsulates.empty() && params[i].
array) {
1338 <<
"option with code '" << params[i].code
1339 <<
"' may not encapsulate option space '"
1340 << encapsulates <<
"' because the definition"
1341 <<
" indicates that this option comprises an array"
1349 if (encapsulates.empty()) {
1362 params[i].encapsulates));
1366 for (
size_t rec = 0; rec < params[i].
records_size; ++rec) {
1367 definition->addRecordField(params[i].records[rec]);
1371 definition->validate();
1383 static_cast<void>(defs->push_back(definition));
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.
A generic exception that is thrown when an unexpected error condition occurs.
static size_t unpackOptions4(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, std::list< uint16_t > &deferred, bool flexible_pad_end=false)
Parses provided buffer as DHCPv4 options and creates Option objects.
static void OptionFactoryRegister(Option::Universe u, uint16_t type, Option::Factory *factory)
Registers factory method that produces options of specific option types.
static size_t unpackVendorOptions6(const uint32_t vendor_id, const OptionBuffer &buf, isc::dhcp::OptionCollection &options)
Parses provided buffer as DHCPv6 vendor options and creates Option objects.
static const OptionDefContainerPtr getOptionDefs(const std::string &space)
Returns collection of option definitions.
static bool shouldDeferOptionUnpack(const std::string &space, const uint16_t code)
Checks if an option unpacking has to be deferred.
static isc::dhcp::OptionPtr optionFactory(isc::dhcp::Option::Universe u, uint16_t type, const OptionBuffer &buf)
Factory function to create instance of option.
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id, const uint16_t code)
Returns vendor option definition for a given vendor-id and code.
static OptionDefContainerPtr getLastResortOptionDefs(const std::string &space)
Returns last resort option definitions for specified option space name.
static OptionDefContainerPtr getRuntimeOptionDefs(const std::string &space)
Returns runtime (non-standard) option definitions for specified option space name.
static void commitRuntimeOptionDefs()
Commits runtime option definitions.
static void clearRuntimeOptionDefs()
Removes runtime option definitions.
static void extendVendorOptions4(isc::dhcp::OptionCollection &options)
Extend vendor options from fused options in multiple OptionVendor or OptionVendorClass options and ad...
static void packOptions4(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options, bool top=false, bool check=true)
Stores DHCPv4 options in a buffer.
static bool splitOptions4(isc::dhcp::OptionCollection &options, ScopedOptionsCopyContainer &scopedOptions, uint32_t used=0)
Split long options in multiple options with the same option code (RFC3396).
static void revertRuntimeOptionDefs()
Reverts uncommitted changes to runtime option definitions.
static const OptionDefContainerPtr getVendorOptionDefs(Option::Universe u, const uint32_t vendor_id)
Returns option definitions for given universe and vendor.
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
static OptionDefinitionPtr getRuntimeOptionDef(const std::string &space, const uint16_t code)
Returns runtime (non-standard) option definition by space and option code.
static size_t unpackOptions6(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, size_t *relay_msg_offset=0, size_t *relay_msg_len=0)
Parses provided buffer as DHCPv6 options and creates Option objects.
static void packOptions6(isc::util::OutputBuffer &buf, const isc::dhcp::OptionCollection &options)
Stores DHCPv6 options in a buffer.
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
static bool fuseOptions4(isc::dhcp::OptionCollection &options)
Fuse multiple options with the same option code in long options (RFC3396).
static size_t unpackVendorOptions4(const uint32_t vendor_id, const OptionBuffer &buf, isc::dhcp::OptionCollection &options)
Parses provided buffer as DHCPv4 vendor options and creates Option objects.
Exception to be thrown when the operation on OpaqueDataTuple object results in an error.
Represents a single instance of the opaque data preceded by length.
Class of option definition space container.
void addItem(const OptionDefinitionPtr &def)
Adds a new option definition to the container.
Base class representing a DHCP option definition.
std::list< Selector > getOptionSpaceNames() const
Get a list of existing option spaces.
ItemsContainerPtr getItems(const Selector &option_space) const
Get all items for the particular option space.
This class encapsulates DHCPv6 Vendor Class and DHCPv4 V-I Vendor Class options.
This class represents vendor-specific information option.
Universe
defines option universe DHCPv4 or DHCPv6
OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer &buf)
a factory function prototype
RAII object enabling duplication of the stored options and restoring the original options on destruct...
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...
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
size_t getLength() const
Return the length of data written in the buffer.
This class implements set/commit mechanism for a single object.
#define DOCSIS3_V6_OPTION_SPACE
#define VENDOR_ID_CABLE_LABS
#define DOCSIS3_V4_OPTION_SPACE
global docsis3 option spaces
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
void initOptionSpace(OptionDefContainerPtr &defs, const OptionDefParams *params, size_t params_size)
const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer())
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
boost::shared_ptr< OptionVendor > OptionVendorPtr
Pointer to a vendor option.
@ DHO_VENDOR_ENCAPSULATED_OPTIONS
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
const OptionDefParams DOCSIS3_V4_OPTION_DEFINITIONS[]
Definitions of standard DHCPv4 options.
const char * DOCSIS3_CLASS_EROUTER
The class as specified in vendor-class option by the devices.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
const int DOCSIS3_V6_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
std::pair< OptionDefContainerNameIndex::const_iterator, OptionDefContainerNameIndex::const_iterator > OptionDefContainerNameRange
Pair of iterators to represent the range of options definitions having the same option name.
const char * DOCSIS3_CLASS_MODEM
DOCSIS3.0 compatible cable modem.
boost::shared_ptr< OptionVendorClass > OptionVendorClassPtr
Defines a pointer to the OptionVendorClass.
std::map< std::string, OptionDefContainerPtr > OptionDefContainers
Container that holds option definitions for various option spaces.
std::shared_ptr< ScopedSubOptionsCopy > ScopedOptionsCopyPtr
A pointer to a ScopedSubOptionsCopy object.
OptionDefContainer::nth_index< 2 >::type OptionDefContainerNameIndex
Type of the index #2 - option name.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
std::pair< OptionDefContainerTypeIndex::const_iterator, OptionDefContainerTypeIndex::const_iterator > OptionDefContainerTypeRange
Pair of iterators to represent the range of options definitions having the same option type value.
boost::multi_index_container< OptionDefinitionPtr, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::hashed_non_unique< boost::multi_index::const_mem_fun< OptionDefinition, uint16_t, &OptionDefinition::getCode > >, boost::multi_index::hashed_non_unique< boost::multi_index::const_mem_fun< OptionDefinition, std::string, &OptionDefinition::getName > >, boost::multi_index::ordered_non_unique< boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::StampedElement::getModificationTime > >, boost::multi_index::hashed_non_unique< boost::multi_index::tag< OptionIdIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, uint64_t, &data::BaseStampedElement::getId > > > > OptionDefContainer
Multi index container for DHCP option definitions.
const int DOCSIS3_V4_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
OptionDefContainer::nth_index< 1 >::type OptionDefContainerTypeIndex
Type of the index #1 - option type.
boost::shared_ptr< Option > OptionPtr
std::vector< ScopedOptionsCopyPtr > ScopedOptionsCopyContainer
A container of ScopedOptionsCopyPtr objects.
const OptionDefParams DOCSIS3_V6_OPTION_DEFINITIONS[]
Definitions of standard DHCPv6 options.
boost::shared_ptr< OptionDefContainer > OptionDefContainerPtr
Pointer to an option definition container.
uint16_t readUint16(void const *const buffer, size_t const length)
uint16_t wrapper over readUint.
uint32_t readUint32(void const *const buffer, size_t const length)
uint32_t wrapper over readUint.
Defines the logger used by the top-level component of kea-lfc.
#define V4V6_BIND_OPTION_SPACE
#define LAST_RESORT_V4_OPTION_SPACE
#define DHCP4_OPTION_SPACE
global std option spaces
#define ISC_V6_OPTION_SPACE
#define V4V6_RULE_OPTION_SPACE
#define MAPE_V6_OPTION_SPACE
#define DHCP_AGENT_OPTION_SPACE
encapsulated option spaces
#define LW_V6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
#define MAPT_V6_OPTION_SPACE
Encapsulation of option definition parameters and the structure size.
Parameters being used to make up an option definition.