option_definition.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef OPTION_DEFINITION_H
  15. #define OPTION_DEFINITION_H
  16. #include <dhcp/option.h>
  17. #include <dhcp/option_data_types.h>
  18. #include <boost/multi_index/hashed_index.hpp>
  19. #include <boost/multi_index/mem_fun.hpp>
  20. #include <boost/multi_index/sequenced_index.hpp>
  21. #include <boost/multi_index_container.hpp>
  22. #include <boost/shared_ptr.hpp>
  23. namespace isc {
  24. namespace dhcp {
  25. /// @brief Exception to be thrown when invalid option value has been
  26. /// specified for a particular option definition.
  27. class InvalidOptionValue : public Exception {
  28. public:
  29. InvalidOptionValue(const char* file, size_t line, const char* what) :
  30. isc::Exception(file, line, what) { };
  31. };
  32. /// @brief Exception to be thrown when option definition is invalid.
  33. class MalformedOptionDefinition : public Exception {
  34. public:
  35. MalformedOptionDefinition(const char* file, size_t line, const char* what) :
  36. isc::Exception(file, line, what) { };
  37. };
  38. /// @brief Forward declaration to OptionDefinition.
  39. class OptionDefinition;
  40. /// @brief Pointer to option definition object.
  41. typedef boost::shared_ptr<OptionDefinition> OptionDefinitionPtr;
  42. /// @brief Forward declaration to OptionInt.
  43. ///
  44. /// This forward declaration is needed to access OptionInt class
  45. /// without having to include option_int.h header. This is because
  46. /// this header includes libdhcp++.h and this causes circular
  47. /// inclusion between libdhcp++.h, option_definition.h and
  48. /// option6_int.h.
  49. template<typename T>
  50. class OptionInt;
  51. /// @brief Forward declaration to OptionIntArray.
  52. ///
  53. /// This forward declaration is needed to access OptionIntArray class
  54. /// without having to include option_int_array.h header. This is because
  55. /// this header includes libdhcp++.h and this causes circular
  56. /// inclusion between libdhcp++.h, option_definition.h and
  57. /// option_int_array.h.
  58. template<typename T>
  59. class OptionIntArray;
  60. /// @brief Base class representing a DHCP option definition.
  61. ///
  62. /// This is a base class representing a DHCP option definition, which describes
  63. /// the format of the option. In particular, it defines:
  64. /// - option name,
  65. /// - option code,
  66. /// - data fields order and their types,
  67. /// - sub options space that the particular option encapsulates.
  68. ///
  69. /// The option type specifies the data type(s) which an option conveys. If
  70. /// this is a single value the option type points to the data type of the
  71. /// value. For example, DHCPv6 option 8 comprises a two-byte option code, a
  72. /// two-byte option length and two-byte field that carries a uint16 value
  73. /// (RFC 3315 - http://ietf.org/rfc/rfc3315.txt). In such a case, the option
  74. /// type is defined as "uint16".
  75. ///
  76. /// When the option has a more complex structure, the option type may be
  77. /// defined as "array", "record" or even "array of records".
  78. ///
  79. /// Array types should be used when the option contains multiple contiguous
  80. /// data values of the same type laid. For example, DHCPv6 option 6 includes
  81. /// multiple fields holding uint16 codes of requested DHCPv6 options (RFC 3315).
  82. /// Such an option can be represented with this class by setting the option
  83. /// type to "uint16" and the array indicator (array_type) to true. The number
  84. /// of elements in the array is effectively unlimited (although it is actually
  85. /// limited by the maximal DHCPv6 option length).
  86. ///
  87. /// Should the option comprise data fields of different types, the "record"
  88. /// option type is used. In such cases the data field types within the record
  89. /// are specified using \ref OptionDefinition::addRecordField.
  90. ///
  91. /// When the OptionDefinition object has been sucessfully created, it can be
  92. /// queried to return the appropriate option factory function for the specified
  93. /// specified option format. There are a number of "standard" factory functions
  94. /// that cover well known (common) formats. If the particular format does not
  95. /// match any common format the generic factory function is returned.
  96. ///
  97. /// The following data type strings are supported:
  98. /// - "empty" (option does not contain data fields)
  99. /// - "boolean"
  100. /// - "int8"
  101. /// - "int16"
  102. /// - "int32"
  103. /// - "uint8"
  104. /// - "uint16"
  105. /// - "uint32"
  106. /// - "ipv4-address" (IPv4 Address)
  107. /// - "ipv6-address" (IPV6 Address)
  108. /// - "string"
  109. /// - "fqdn" (fully qualified name)
  110. /// - "record" (set of data fields of different types)
  111. ///
  112. /// @todo Extend the comment to describe "generic factories".
  113. /// @todo Extend this class to use custom namespaces.
  114. /// @todo Extend this class with more factory functions.
  115. class OptionDefinition {
  116. public:
  117. /// List of fields within the record.
  118. typedef std::vector<OptionDataType> RecordFieldsCollection;
  119. /// Const iterator for record data fields.
  120. typedef std::vector<OptionDataType>::const_iterator RecordFieldsConstIter;
  121. /// @brief Constructor.
  122. ///
  123. /// @param name option name.
  124. /// @param code option code.
  125. /// @param type option data type as string.
  126. /// @param array_type array indicator, if true it indicates that the
  127. /// option fields are the array.
  128. OptionDefinition(const std::string& name,
  129. const uint16_t code,
  130. const std::string& type,
  131. const bool array_type = false);
  132. /// @brief Constructor.
  133. ///
  134. /// @param name option name.
  135. /// @param code option code.
  136. /// @param type option data type.
  137. /// @param array_type array indicator, if true it indicates that the
  138. /// option fields are the array.
  139. OptionDefinition(const std::string& name,
  140. const uint16_t code,
  141. const OptionDataType type,
  142. const bool array_type = false);
  143. /// @brief Adds data field to the record.
  144. ///
  145. /// @param data_type_name name of the data type for the field.
  146. ///
  147. /// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
  148. /// @throw isc::BadValue if specified invalid data type.
  149. void addRecordField(const std::string& data_type_name);
  150. /// @brief Adds data field to the record.
  151. ///
  152. /// @param data_type data type for the field.
  153. ///
  154. /// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
  155. /// @throw isc::BadValue if specified invalid data type.
  156. void addRecordField(const OptionDataType data_type);
  157. /// @brief Return array type indicator.
  158. ///
  159. /// The method returns the bool value to indicate whether the option is a
  160. /// a single value or an array of values.
  161. ///
  162. /// @return true if option comprises an array of values.
  163. bool getArrayType() const { return (array_type_); }
  164. /// @brief Return option code.
  165. ///
  166. /// @return option code.
  167. uint16_t getCode() const { return (code_); }
  168. /// @brief Return option name.
  169. ///
  170. /// @return option name.
  171. const std::string& getName() const { return (name_); }
  172. /// @brief Return list of record fields.
  173. ///
  174. /// @return list of record fields.
  175. const RecordFieldsCollection& getRecordFields() const { return (record_fields_); }
  176. /// @brief Return option data type.
  177. ///
  178. /// @return option data type.
  179. OptionDataType getType() const { return (type_); };
  180. /// @brief Check if the option definition is valid.
  181. ///
  182. /// @throw MalformedOptionDefinition option definition is invalid.
  183. void validate() const;
  184. /// @brief Check if specified format is IA_NA option format.
  185. ///
  186. /// @return true if specified format is IA_NA option format.
  187. bool haveIA6Format() const;
  188. /// @brief Check if specified format is IAADDR option format.
  189. ///
  190. /// @return true if specified format is IAADDR option format.
  191. bool haveIAAddr6Format() const;
  192. /// @brief Option factory.
  193. ///
  194. /// This function creates an instance of DHCP option using
  195. /// provided chunk of buffer. This function may be used to
  196. /// create option which is to be sent in the outgoing packet.
  197. ///
  198. /// @param u option universe (V4 or V6).
  199. /// @param type option type.
  200. /// @param begin beginning of the option buffer.
  201. /// @param end end of the option buffer.
  202. ///
  203. /// @return instance of the DHCP option.
  204. /// @throw MalformedOptionDefinition if option definition is invalid.
  205. /// @throw InvalidOptionValue if data for the option is invalid.
  206. OptionPtr optionFactory(Option::Universe u, uint16_t type,
  207. OptionBufferConstIter begin,
  208. OptionBufferConstIter end) const;
  209. /// @brief Option factory.
  210. ///
  211. /// This function creates an instance of DHCP option using
  212. /// whole provided buffer. This function may be used to
  213. /// create option which is to be sent in the outgoing packet.
  214. ///
  215. /// @param u option universe (V4 or V6).
  216. /// @param type option type.
  217. /// @param buf option buffer.
  218. ///
  219. /// @return instance of the DHCP option.
  220. /// @throw MalformedOptionDefinition if option definition is invalid.
  221. /// @throw InvalidOptionValue if data for the option is invalid.
  222. OptionPtr optionFactory(Option::Universe u, uint16_t type,
  223. const OptionBuffer& buf = OptionBuffer()) const;
  224. /// @brief Option factory.
  225. ///
  226. /// This function creates an instance of DHCP option using the vector
  227. /// of strings which carry data values for option data fields.
  228. /// The order of values in the vector corresponds to the order of data
  229. /// fields in the option. The supplied string values are cast to
  230. /// their actual data types which are determined based on the
  231. /// option definition. If cast fails due to type mismatch, an exception
  232. /// is thrown. This factory function can be used to create option
  233. /// instance when user specified option value in the <b>comma separated
  234. /// values</b> format in the configuration database. Provided string
  235. /// must be tokenized into the vector of string values and this vector
  236. /// can be supplied to this function.
  237. ///
  238. /// @param u option universe (V4 or V6).
  239. /// @param type option type.
  240. /// @param values a vector of values to be used to set data for an option.
  241. ///
  242. /// @return instance of the DHCP option.
  243. /// @throw MalformedOptionDefinition if option definition is invalid.
  244. /// @throw InvalidOptionValue if data for the option is invalid.
  245. OptionPtr optionFactory(Option::Universe u, uint16_t type,
  246. const std::vector<std::string>& values) const;
  247. /// @brief Factory to create option with address list.
  248. ///
  249. /// @param type option type.
  250. /// @param begin iterator pointing to the beginning of the buffer
  251. /// with a list of IPv4 addresses.
  252. /// @param end iterator pointing to the end of the buffer with
  253. /// a list of IPv4 addresses.
  254. ///
  255. /// @throw isc::OutOfRange if length of the provided option buffer
  256. /// is not multiple of IPV4 address length.
  257. static OptionPtr factoryAddrList4(uint16_t type,
  258. OptionBufferConstIter begin,
  259. OptionBufferConstIter end);
  260. /// @brief Factory to create option with address list.
  261. ///
  262. /// @param type option type.
  263. /// @param begin iterator pointing to the beginning of the buffer
  264. /// with a list of IPv6 addresses.
  265. /// @param end iterator pointing to the end of the buffer with
  266. /// a list of IPv6 addresses.
  267. ///
  268. /// @throw isc::OutOfaRange if length of provided option buffer
  269. /// is not multiple of IPV6 address length.
  270. static OptionPtr factoryAddrList6(uint16_t type,
  271. OptionBufferConstIter begin,
  272. OptionBufferConstIter end);
  273. /// @brief Empty option factory.
  274. ///
  275. /// @param u universe (V6 or V4).
  276. /// @param type option type.
  277. static OptionPtr factoryEmpty(Option::Universe u, uint16_t type);
  278. /// @brief Factory to create generic option.
  279. ///
  280. /// @param u universe (V6 or V4).
  281. /// @param type option type.
  282. /// @param begin iterator pointing to the beginning of the buffer.
  283. /// @param end iterator pointing to the end of the buffer.
  284. static OptionPtr factoryGeneric(Option::Universe u, uint16_t type,
  285. OptionBufferConstIter begin,
  286. OptionBufferConstIter end);
  287. /// @brief Factory for IA-type of option.
  288. ///
  289. /// @param type option type.
  290. /// @param begin iterator pointing to the beginning of the buffer.
  291. /// @param end iterator pointing to the end of the buffer.
  292. ///
  293. /// @throw isc::OutOfRange if provided option buffer is too short or
  294. /// too long. Expected size is 12 bytes.
  295. /// @throw isc::BadValue if specified universe value is not V6.
  296. static OptionPtr factoryIA6(uint16_t type,
  297. OptionBufferConstIter begin,
  298. OptionBufferConstIter end);
  299. /// @brief Factory for IAADDR-type of option.
  300. ///
  301. /// @param type option type.
  302. /// @param begin iterator pointing to the beginning of the buffer.
  303. /// @param end iterator pointing to the end of the buffer.
  304. ///
  305. /// @throw isc::OutOfRange if provided option buffer is too short or
  306. /// too long. Expected size is 24 bytes.
  307. /// @throw isc::BadValue if specified universe value is not V6.
  308. static OptionPtr factoryIAAddr6(uint16_t type,
  309. OptionBufferConstIter begin,
  310. OptionBufferConstIter end);
  311. /// @brief Factory function to create option with integer value.
  312. ///
  313. /// @param u universe (V4 or V6).
  314. /// @param type option type.
  315. /// @param begin iterator pointing to the beginning of the buffer.
  316. /// @param end iterator pointing to the end of the buffer.
  317. /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
  318. ///
  319. /// @throw isc::OutOfRange if provided option buffer length is invalid.
  320. template<typename T>
  321. static OptionPtr factoryInteger(Option::Universe u, uint16_t type,
  322. OptionBufferConstIter begin,
  323. OptionBufferConstIter end) {
  324. OptionPtr option(new OptionInt<T>(u, type, begin, end));
  325. return (option);
  326. }
  327. /// @brief Factory function to create option with array of integer values.
  328. ///
  329. /// @param type option type.
  330. /// @param begin iterator pointing to the beginning of the buffer.
  331. /// @param end iterator pointing to the end of the buffer.
  332. /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
  333. ///
  334. /// @throw isc::OutOfRange if provided option buffer length is invalid.
  335. template<typename T>
  336. static OptionPtr factoryIntegerArray(uint16_t type,
  337. OptionBufferConstIter begin,
  338. OptionBufferConstIter end) {
  339. OptionPtr option(new OptionIntArray<T>(type, begin, end));
  340. return (option);
  341. }
  342. private:
  343. /// @brief Check if specified option format is a record with 3 fields
  344. /// where first one is custom, and two others are uint32.
  345. ///
  346. /// This is a helper function for functions that detect IA_NA and IAAddr
  347. /// option formats.
  348. ///
  349. /// @param first_type type of the first data field.
  350. ///
  351. /// @return true if actual option format matches expected format.
  352. bool haveIAx6Format(const OptionDataType first_type) const;
  353. /// @brief Check if specified type matches option definition type.
  354. ///
  355. /// @return true if specified type matches option definition type.
  356. inline bool haveType(const OptionDataType type) const {
  357. return (type == type_);
  358. }
  359. /// @brief Perform lexical cast of the value and validate its range.
  360. ///
  361. /// This function performs lexical cast of a string value to integer
  362. /// or boolean value and checks if the resulting value is within a
  363. /// range of a target type. Note that range checks are not performed
  364. /// on boolean values. The target type should be one of the supported
  365. /// integer types or bool.
  366. ///
  367. /// @param value_str input value given as string.
  368. /// @tparam T target type for lexical cast.
  369. ///
  370. /// @return cast value.
  371. /// @throw BadDataTypeCast if cast was not successful.
  372. template<typename T>
  373. T lexicalCastWithRangeCheck(const std::string& value_str) const;
  374. /// @brief Write the string value into the provided buffer.
  375. ///
  376. /// This method writes the given value to the specified buffer.
  377. /// The provided string value may represent data of different types.
  378. /// The actual data type is specified with the second argument.
  379. /// Based on a value of this argument, this function will first
  380. /// try to cast the string value to the particular data type and
  381. /// if it is successful it will store the data in the buffer
  382. /// in a binary format.
  383. ///
  384. /// @param value string representation of the value to be written.
  385. /// @param type the actual data type to be stored.
  386. /// @param [in, out] buf buffer where the value is to be stored.
  387. ///
  388. /// @throw BadDataTypeCast if data write was unsuccessful.
  389. void writeToBuffer(const std::string& value, const OptionDataType type,
  390. OptionBuffer& buf) const;
  391. /// @brief Sanity check universe value.
  392. ///
  393. /// @param expected_universe expected universe value.
  394. /// @param actual_universe actual universe value.
  395. ///
  396. /// @throw isc::BadValue if expected universe and actual universe don't match.
  397. static inline void sanityCheckUniverse(const Option::Universe expected_universe,
  398. const Option::Universe actual_universe);
  399. /// Option name.
  400. std::string name_;
  401. /// Option code.
  402. uint16_t code_;
  403. /// Option data type.
  404. OptionDataType type_;
  405. /// Indicates wheter option is a single value or array.
  406. bool array_type_;
  407. /// Collection of data fields within the record.
  408. RecordFieldsCollection record_fields_;
  409. };
  410. /// @brief Multi index container for DHCP option definitions.
  411. ///
  412. /// This container allows to search for DHCP option definition
  413. /// using two indexes:
  414. /// - sequenced: used to access elements in the order they have
  415. /// been added to the container
  416. /// - option code: used to search defintions of options
  417. /// with a specified option code (aka option type).
  418. /// Note that this container can hold multiple options with the
  419. /// same code. For this reason, the latter index can be used to
  420. /// obtain a range of options for a particular option code.
  421. ///
  422. /// @todo: need an index to search options using option space name
  423. /// once option spaces are implemented.
  424. typedef boost::multi_index_container<
  425. // Container comprises elements of OptionDefinition type.
  426. OptionDefinitionPtr,
  427. // Here we start enumerating various indexes.
  428. boost::multi_index::indexed_by<
  429. // Sequenced index allows accessing elements in the same way
  430. // as elements in std::list. Sequenced is an index #0.
  431. boost::multi_index::sequenced<>,
  432. // Start definition of index #1.
  433. boost::multi_index::hashed_non_unique<
  434. // Use option type as the index key. The type is held
  435. // in OptionDefinition object so we have to call
  436. // OptionDefinition::getCode to retrieve this key
  437. // for each element. The option code is non-unique so
  438. // multiple elements with the same option code can
  439. // be returned by this index.
  440. boost::multi_index::const_mem_fun<
  441. OptionDefinition,
  442. uint16_t,
  443. &OptionDefinition::getCode
  444. >
  445. >
  446. >
  447. > OptionDefContainer;
  448. /// Type of the index #1 - option type.
  449. typedef OptionDefContainer::nth_index<1>::type OptionDefContainerTypeIndex;
  450. /// Pair of iterators to represent the range of options definitions
  451. /// having the same option type value. The first element in this pair
  452. /// represents the begining of the range, the second element
  453. /// represents the end.
  454. typedef std::pair<OptionDefContainerTypeIndex::const_iterator,
  455. OptionDefContainerTypeIndex::const_iterator> OptionDefContainerTypeRange;
  456. } // namespace isc::dhcp
  457. } // namespace isc
  458. #endif // OPTION_DEFINITION_H