24 #include <boost/lexical_cast.hpp> 25 #include <boost/shared_array.hpp> 26 #include <boost/shared_ptr.hpp> 44 { STANDARD_V4_OPTION_DEFINITIONS, STANDARD_V4_OPTION_DEFINITIONS_SIZE,
DHCP4_OPTION_SPACE },
45 { STANDARD_V6_OPTION_DEFINITIONS, STANDARD_V6_OPTION_DEFINITIONS_SIZE,
DHCP6_OPTION_SPACE },
65 map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
68 map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
93 bool LibDHCP::initialized_ = LibDHCP::initOptionDefs();
96 LibDHCP::getOptionDefs(
const string& space) {
97 auto const& container = option_defs_.find(space);
98 if (container != option_defs_.end()) {
99 return (container->second);
107 if (Option::V4 == u) {
111 }
else if (Option::V6 == u) {
114 }
else if (ENTERPRISE_ID_ISC == vendor_id) {
123 LibDHCP::getOptionDef(
const string& space,
const uint16_t code) {
127 if (range.first != range.second) {
128 return (*range.first);
135 LibDHCP::getOptionDef(
const string& space,
const string& name) {
139 if (range.first != range.second) {
140 return (*range.first);
148 const string& name) {
157 if (range.first != range.second) {
158 return (*range.first);
166 const uint16_t code) {
178 if (range.first != range.second) {
179 return (*range.first);
186 LibDHCP::getRuntimeOptionDef(
const string& space,
const uint16_t code) {
190 if (range.first != range.second) {
191 return (*range.first);
198 LibDHCP::getRuntimeOptionDef(
const string& space,
const string& name) {
202 if (range.first != range.second) {
203 return (*range.first);
210 LibDHCP::getRuntimeOptionDefs(
const string& space) {
211 return (runtime_option_defs_.getValue().getItems(space));
218 for (
auto const& name : option_space_names) {
220 for (
auto const& def : *container) {
225 runtime_option_defs_ = defs_copy;
229 LibDHCP::clearRuntimeOptionDefs() {
230 runtime_option_defs_.reset();
234 LibDHCP::revertRuntimeOptionDefs() {
235 runtime_option_defs_.revert();
239 LibDHCP::commitRuntimeOptionDefs() {
240 runtime_option_defs_.commit();
244 LibDHCP::getLastResortOptionDef(
const string& space,
const uint16_t code) {
248 if (range.first != range.second) {
249 return (*range.first);
256 LibDHCP::getLastResortOptionDef(
const string& space,
const string& name) {
260 if (range.first != range.second) {
261 return (*range.first);
268 LibDHCP::getLastResortOptionDefs(
const string& space) {
277 LibDHCP::shouldDeferOptionUnpack(
const string& space,
const uint16_t code) {
280 ((code >= 224) && (code <= 254))));
287 FactoryMap::iterator it;
288 if (u == Option::V4) {
289 it = v4factories_.find(type);
290 if (it == v4factories_.end()) {
292 "for DHCP v4 option type " << type);
294 }
else if (u == Option::V6) {
295 it = v6factories_.find(type);
296 if (it == v6factories_.end()) {
298 "for DHCPv6 option type " << type);
302 "Option::V4 or Option::V6");
304 return (it->second(u, type, buf));
308 LibDHCP::unpackOptions6(
const OptionBuffer& buf,
const string& option_space,
310 size_t* relay_msg_offset ,
311 size_t* relay_msg_len ) {
313 size_t length = buf.size();
314 size_t last_offset = 0;
333 while (offset < length) {
335 last_offset = offset;
338 if (offset + 4 > length) {
340 return (last_offset);
344 uint16_t opt_type =
readUint16(&buf[offset], 2);
347 uint16_t opt_len =
readUint16(&buf[offset], 2);
350 if (offset + opt_len > length) {
359 return (last_offset);
362 if (opt_type ==
D6O_RELAY_MSG && relay_msg_offset && relay_msg_len) {
364 *relay_msg_offset = offset;
365 *relay_msg_len = opt_len;
373 if (offset + 4 > length) {
377 return (last_offset);
382 buf.begin() + offset + opt_len));
383 options.insert(std::make_pair(opt_type, vendor_opt));
400 range = idx.equal_range(opt_type);
401 num_defs = std::distance(range.first, range.second);
407 range = runtime_idx.equal_range(opt_type);
408 num_defs = std::distance(range.first, range.second);
415 " definitions for option type " << opt_type <<
416 " returned. Currently it is not supported to initialize" 417 " multiple option definitions for the same option code." 418 " This will be supported once support for option spaces" 420 }
else if (num_defs == 0) {
427 buf.begin() + offset,
428 buf.begin() + offset + opt_len));
435 opt = def->optionFactory(Option::V6, opt_type,
436 buf.begin() + offset,
437 buf.begin() + offset + opt_len);
445 options.insert(std::make_pair(opt_type, opt));
451 last_offset = offset;
452 return (last_offset);
456 LibDHCP::unpackOptions4(
const OptionBuffer& buf,
const string& option_space,
460 size_t last_offset = 0;
477 bool flex_pad = (check && (runtime_idx.count(
DHO_PAD) == 0));
478 bool flex_end = (check && (runtime_idx.count(
DHO_END) == 0));
482 while (offset < buf.size()) {
484 last_offset = offset;
487 uint8_t opt_type = buf[offset++];
492 if ((opt_type ==
DHO_END) && (space_is_dhcp4 || flex_end)) {
496 return (last_offset);
503 if ((opt_type ==
DHO_PAD) && (space_is_dhcp4 || flex_pad)) {
507 if (offset + 1 > buf.size()) {
515 return (last_offset);
518 uint8_t opt_len = buf[offset++];
519 if (offset + opt_len > buf.size()) {
524 return (last_offset);
532 if (space_is_dhcp4 && opt_len == 0 && opt_type ==
DHO_HOST_NAME) {
548 range = idx.equal_range(opt_type);
549 num_defs = std::distance(range.first, range.second);
555 range = runtime_idx.equal_range(opt_type);
556 num_defs = std::distance(range.first, range.second);
560 if (shouldDeferOptionUnpack(option_space, opt_type)) {
564 for (
auto const& existing : deferred) {
565 if (existing == opt_type) {
571 deferred.push_back(opt_type);
583 " definitions for option type " <<
584 static_cast<int>(opt_type) <<
585 " returned. Currently it is not supported to initialize" 586 " multiple option definitions for the same option code." 587 " This will be supported once support for option spaces" 589 }
else if (num_defs == 0) {
591 buf.begin() + offset,
592 buf.begin() + offset + opt_len));
600 opt = def->optionFactory(Option::V4, opt_type,
601 buf.begin() + offset,
602 buf.begin() + offset + opt_len);
610 options.insert(std::make_pair(opt_type, opt));
615 last_offset = offset;
616 return (last_offset);
625 bool found_suboptions =
false;
627 for (
auto const& option : options) {
631 if (sub_options.size()) {
635 found_suboptions = LibDHCP::fuseOptions4(sub_options);
636 if (found_suboptions) {
645 for (
auto const& old_option : copy) {
646 if (old_option.first == option.first) {
648 data.insert(data.end(), old_option.second->getData().begin(),
649 old_option.second->getData().end());
650 suboptions.insert(old_option.second->getOptions().begin(),
651 old_option.second->getOptions().end());
661 copy.erase(option.first);
664 candidate->getType(), data));
666 new_option->getMutableOptions() = suboptions;
668 copy.insert(make_pair(candidate->getType(), new_option));
678 if ((found <= 1) && !found_suboptions) {
687 map<uint32_t, OptionCollection> vendors_data;
689 for (
auto it = range.first; it != range.second; ++it) {
691 auto const& data = it->second->getData();
693 while ((size = data.size() - offset) != 0) {
694 if (size <
sizeof(uint32_t)) {
697 "Truncated vendor-specific information option" 698 <<
", length=" << size);
700 uint32_t vendor_id =
readUint32(&data[offset], data.size());
702 const OptionBuffer vendor_buffer(data.begin() + offset, data.end());
704 offset += LibDHCP::unpackVendorOptions4(vendor_id, vendor_buffer,
705 vendors_data[vendor_id]);
715 if (vendors_data.empty()) {
721 for (
auto const& vendor : vendors_data) {
723 for (
auto const& option : vendor.second) {
724 vendor_opt->addOption(option.second);
733 LibDHCP::unpackVendorOptions6(
const uint32_t vendor_id,
const OptionBuffer& buf,
736 size_t length = buf.size();
740 LibDHCP::getVendorOptionDefs(Option::V6, vendor_id);
747 idx = &(option_defs->get<1>());
752 while (offset < length) {
753 if (offset + 4 > length) {
755 "Vendor option parse failed: truncated header");
758 uint16_t opt_type =
readUint16(&buf[offset], 2);
761 uint16_t opt_len =
readUint16(&buf[offset], 2);
764 if (offset + opt_len > length) {
766 "Vendor option parse failed. Tried to parse " 767 << offset + opt_len <<
" bytes from " << length
768 <<
"-byte long buffer.");
782 idx->equal_range(opt_type);
785 size_t num_defs = std::distance(range.first, range.second);
791 " definitions for option type " << opt_type <<
792 " returned. Currently it is not supported to" 793 " initialize multiple option definitions for the" 794 " same option code. This will be supported once" 795 " support for option spaces is implemented");
796 }
else if (num_defs == 1) {
801 opt = def->optionFactory(Option::V6, opt_type,
802 buf.begin() + offset,
803 buf.begin() + offset + opt_len);
814 buf.begin() + offset,
815 buf.begin() + offset + opt_len));
820 options.insert(std::make_pair(opt_type, opt));
829 LibDHCP::unpackVendorOptions4(
const uint32_t vendor_id,
const OptionBuffer& buf,
835 LibDHCP::getVendorOptionDefs(Option::V4, vendor_id);
840 idx = &(option_defs->get<1>());
845 while (offset < buf.size()) {
849 uint8_t data_len = buf[offset++];
851 if (offset + data_len > buf.size()) {
854 "Attempt to parse truncated vendor option");
857 uint8_t offset_end = offset + data_len;
860 while (offset < offset_end) {
861 uint8_t opt_type = buf[offset++];
865 if (offset + 1 > offset_end) {
870 "Attempt to parse truncated vendor option " 871 << static_cast<int>(opt_type));
874 uint8_t opt_len = buf[offset++];
875 if (offset + opt_len > offset_end) {
877 "Option parse failed. Tried to parse " 878 << offset + opt_len <<
" bytes from " << buf.size()
879 <<
"-byte long buffer.");
892 idx->equal_range(opt_type);
895 size_t num_defs = std::distance(range.first, range.second);
901 " option definitions for option type " 902 << opt_type <<
" returned. Currently it is" 903 " not supported to initialize multiple option" 904 " definitions for the same option code." 905 " This will be supported once support for" 906 " option spaces is implemented");
907 }
else if (num_defs == 1) {
912 opt = def->optionFactory(Option::V4, opt_type,
913 buf.begin() + offset,
914 buf.begin() + offset + opt_len);
920 buf.begin() + offset,
921 buf.begin() + offset + opt_len));
924 options.insert(std::make_pair(opt_type, opt));
936 bool top,
bool check) {
946 if (x != options.end()) {
947 x->second->pack(buf, check);
951 for (
auto const& option : options) {
953 switch (option.first) {
963 option.second->pack(buf, check);
969 for (
auto const& option : agent) {
970 option.second->pack(buf, check);
975 end->pack(buf, check);
991 for (
auto const& option : options) {
996 bool updated =
false;
997 bool found_suboptions =
false;
998 if (sub_options.size()) {
1000 found_suboptions = LibDHCP::splitOptions4(sub_options, scoped_options,
1001 used + candidate->getHeaderLen());
1004 if (found_suboptions || candidate->len() > 255) {
1006 scoped_options.push_back(candidate_scoped_options);
1009 copy.erase(option.first);
1019 for (
auto sub_option : candidate->getMutableOptions()) {
1021 candidate->getType(),
1023 data_sub_option->addOption(sub_option.second);
1024 distinct_options.insert(make_pair(candidate->getType(), data_sub_option));
1032 candidate->getType(),
1034 candidate->getData().end())));
1036 data_option->pack(buf,
false);
1037 uint32_t header_len = candidate->getHeaderLen();
1039 if (used >= 255 - header_len) {
1041 << candidate->getType() <<
" after parent already used " 1046 uint8_t len = 255 - header_len - used;
1051 uint32_t size = buf.getLength() - header_len;
1060 copy.erase(option.first);
1063 uint32_t offset = 0;
1066 for (; offset != size;) {
1070 if (size - offset < len) {
1071 len = size - offset;
1075 const uint8_t* data =
static_cast<const uint8_t*
>(buf.getData());
1078 candidate->getType(),
1080 data + offset + len)));
1085 copy.insert(make_pair(candidate->getType(), new_option));
1087 }
else if (candidate->len() > 255 && size) {
1091 copy.insert(make_pair(candidate->getType(), data_option));
1096 copy.insert(distinct_options.begin(), distinct_options.end());
1116 for (
auto const& option : options) {
1117 option.second->pack(buf);
1123 Option::Factory* factory) {
1127 if (v6factories_.find(opt_type) != v6factories_.end()) {
1129 <<
"for option type " << opt_type);
1131 v6factories_[opt_type] = factory;
1138 if (opt_type == 0) {
1144 if (opt_type > 254) {
1147 if (v4factories_.find(opt_type) != v4factories_.end()) {
1149 <<
"for option type " << opt_type);
1151 v4factories_[opt_type] = factory;
1162 LibDHCP::initOptionDefs() {
1163 for (uint32_t i = 0; OPTION_DEF_PARAMS[i].optionDefParams; ++i) {
1164 string space = OPTION_DEF_PARAMS[i].space;
1167 OPTION_DEF_PARAMS[i].optionDefParams,
1168 OPTION_DEF_PARAMS[i].size);
1175 LibDHCP::optionSpaceToVendorId(
const string& option_space) {
1177 if ((option_space.size() < 8) || (option_space.substr(0,7) !=
"vendor-")) {
1184 string x = option_space.substr(7);
1186 check = boost::lexical_cast<int64_t>(x);
1187 }
catch (
const boost::bad_lexical_cast &) {
1191 if ((check < 0) || (check > std::numeric_limits<uint32_t>::max())) {
1196 return (static_cast<uint32_t>(check));
1201 size_t params_size) {
1211 for (
size_t i = 0; i < params_size; ++i) {
1212 string encapsulates(params[i].encapsulates);
1213 if (!encapsulates.empty() && params[i].
array) {
1215 <<
"option with code '" << params[i].code
1216 <<
"' may not encapsulate option space '" 1217 << encapsulates <<
"' because the definition" 1218 <<
" indicates that this option comprises an array" 1226 if (encapsulates.empty()) {
1239 params[i].encapsulates));
1243 for (
size_t rec = 0; rec < params[i].
records_size; ++rec) {
1244 definition->addRecordField(params[i].records[rec]);
1248 definition->validate();
1260 static_cast<void>(defs->push_back(definition));
Encapsulation of option definition parameters and the structure size.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Base class representing a DHCP option definition.
void addItem(const OptionDefinitionPtr &def)
Adds a new option definition to the container.
ItemsContainerPtr getItems(const Selector &option_space) const
Get all items for the particular option space.
#define V4V6_BIND_OPTION_SPACE
Exception thrown during option unpacking This exception is thrown when an error has occurred...
#define V4V6_RULE_OPTION_SPACE
std::list< Selector > getOptionSpaceNames() const
Get a list of existing option spaces.
OptionDefContainer::nth_index< 1 >::type OptionDefContainerTypeIndex
Type of the index #1 - option type.
boost::shared_ptr< Option > OptionPtr
Universe
defines option universe DHCPv4 or DHCPv6
Parameters being used to make up an option definition.
#define DOCSIS3_V4_OPTION_SPACE
global docsis3 option spaces
std::vector< ScopedOptionsCopyPtr > ScopedOptionsCopyContainer
A container of ScopedOptionsCopyPtr objects.
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.
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...
#define LW_V6_OPTION_SPACE
Class of option definition space container.
const OptionDefParams DOCSIS3_V6_OPTION_DEFINITIONS[]
Definitions of standard DHCPv6 options.
#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...
#define MAPT_V6_OPTION_SPACE
#define MAPE_V6_OPTION_SPACE
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
const char * DOCSIS3_CLASS_MODEM
DOCSIS3.0 compatible cable modem.
A generic exception that is thrown when an unexpected error condition occurs.
#define ISC_V6_OPTION_SPACE
#define DHCP_AGENT_OPTION_SPACE
encapsulated option spaces
const char * DOCSIS3_CLASS_EROUTER
The class as specified in vendor-class option by the devices.
#define LAST_RESORT_V4_OPTION_SPACE
boost::shared_ptr< OptionDefContainer > OptionDefContainerPtr
Pointer to an option definition container.
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
uint32_t readUint32(const uint8_t *buffer, size_t length)
Read Unsigned 32-Bit Integer from Buffer.
const OptionDefParams DOCSIS3_V4_OPTION_DEFINITIONS[]
Definitions of standard DHCPv4 options.
std::map< std::string, OptionDefContainerPtr > OptionDefContainers
Container that holds option definitions for various option spaces.
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-lfc.
const int DOCSIS3_V6_OPTION_DEFINITIONS_SIZE
Number of option definitions defined.
uint16_t readUint16(const void *buffer, size_t length)
Read Unsigned 16-Bit Integer from Buffer.
#define DHCP6_OPTION_SPACE
#define DHCP4_OPTION_SPACE
global std option spaces
std::shared_ptr< ScopedSubOptionsCopy > ScopedOptionsCopyPtr
A pointer to a ScopedSubOptionsCopy object.
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...
#define DOCSIS3_V6_OPTION_SPACE
boost::shared_ptr< OptionVendor > OptionVendorPtr
Pointer to a vendor option.
RAII object enabling duplication of the stored options and restoring the original options on destruct...
const OptionDefContainerPtr null_option_def_container_(new OptionDefContainer())
#define VENDOR_ID_CABLE_LABS
This class implements set/commit mechanism for a single object.
This class represents vendor-specific information option.
void initOptionSpace(OptionDefContainerPtr &defs, const OptionDefParams *params, size_t params_size)
OptionDefContainer::nth_index< 2 >::type OptionDefContainerNameIndex
Type of the index #2 - option name.
const int DOCSIS3_V4_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...