option.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. // Copyright (C) 2011-2015 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_H
  15. #define OPTION_H
  16. #include <util/buffer.h>
  17. #include <boost/function.hpp>
  18. #include <boost/shared_ptr.hpp>
  19. #include <map>
  20. #include <string>
  21. #include <vector>
  22. namespace isc {
  23. namespace dhcp {
  24. /// @brief buffer types used in DHCP code.
  25. ///
  26. /// Dereferencing OptionBuffer iterator will point out to contiguous memory.
  27. typedef std::vector<uint8_t> OptionBuffer;
  28. /// iterator for walking over OptionBuffer
  29. typedef OptionBuffer::iterator OptionBufferIter;
  30. /// const_iterator for walking over OptionBuffer
  31. typedef OptionBuffer::const_iterator OptionBufferConstIter;
  32. /// pointer to a DHCP buffer
  33. typedef boost::shared_ptr<OptionBuffer> OptionBufferPtr;
  34. /// shared pointer to Option object
  35. class Option;
  36. typedef boost::shared_ptr<Option> OptionPtr;
  37. /// A collection of DHCP (v4 or v6) options
  38. typedef std::multimap<unsigned int, OptionPtr> OptionCollection;
  39. /// A pointer to an OptionCollection
  40. typedef boost::shared_ptr<OptionCollection> OptionCollectionPtr;
  41. /// @brief This type describes a callback function to parse options from buffer.
  42. ///
  43. /// @note The last two parameters should be specified in the callback function
  44. /// parameters list only if DHCPv6 options are parsed. Exclude these parameters
  45. /// from the callback function defined to parse DHCPv4 options.
  46. ///
  47. /// @param buffer A buffer holding options to be parsed.
  48. /// @param encapsulated_space A name of the option space to which options being
  49. /// parsed belong.
  50. /// @param [out] options A container to which parsed options should be appended.
  51. /// @param relay_msg_offset A pointer to a size_t value. It indicates the
  52. /// offset to beginning of relay_msg option. This parameter should be specified
  53. /// for DHCPv6 options only.
  54. /// @param relay_msg_len A pointer to a size_t value. It holds the length of
  55. /// of the relay_msg option. This parameter should be specified for DHCPv6
  56. /// options only.
  57. ///
  58. /// @return An offset to the first byte after last parsed option.
  59. typedef boost::function< size_t(const OptionBuffer& buffer,
  60. const std::string encapsulated_space,
  61. OptionCollection& options,
  62. size_t* relay_msg_offset,
  63. size_t* relay_msg_len)
  64. > UnpackOptionsCallback;
  65. class Option {
  66. public:
  67. /// length of the usual DHCPv4 option header (there are exceptions)
  68. const static size_t OPTION4_HDR_LEN = 2;
  69. /// length of any DHCPv6 option header
  70. const static size_t OPTION6_HDR_LEN = 4;
  71. /// defines option universe DHCPv4 or DHCPv6
  72. enum Universe { V4, V6 };
  73. /// @brief a factory function prototype
  74. ///
  75. /// @param u option universe (DHCPv4 or DHCPv6)
  76. /// @param type option type
  77. /// @param buf pointer to a buffer
  78. ///
  79. /// @todo Passing a separate buffer for each option means that a copy
  80. /// was done. We can avoid it by passing 2 iterators.
  81. ///
  82. /// @return a pointer to a created option object
  83. typedef OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer& buf);
  84. /// @brief Factory function to create instance of option.
  85. ///
  86. /// Factory method creates instance of specified option. The option
  87. /// to be created has to have corresponding factory function
  88. /// registered with \ref LibDHCP::OptionFactoryRegister.
  89. ///
  90. /// @param u universe of the option (V4 or V6)
  91. /// @param type option-type
  92. /// @param buf option-buffer
  93. ///
  94. /// @return instance of option.
  95. ///
  96. /// @throw isc::InvalidOperation if there is no factory function
  97. /// registered for specified option type.
  98. static OptionPtr factory(Option::Universe u,
  99. uint16_t type,
  100. const OptionBuffer& buf);
  101. /// @brief Factory function to create instance of option.
  102. ///
  103. /// Factory method creates instance of specified option. The option
  104. /// to be created has to have corresponding factory function
  105. /// registered with \ref LibDHCP::OptionFactoryRegister.
  106. /// This method creates empty \ref OptionBuffer object. Use this
  107. /// factory function if it is not needed to pass custom buffer.
  108. ///
  109. /// @param u universe of the option (V4 or V6)
  110. /// @param type option-type
  111. ///
  112. /// @return instance of option.
  113. ///
  114. /// @throw isc::InvalidOperation if there is no factory function
  115. /// registered for specified option type.
  116. static OptionPtr factory(Option::Universe u, uint16_t type) {
  117. return factory(u, type, OptionBuffer());
  118. }
  119. /// @brief ctor, used for options constructed, usually during transmission
  120. ///
  121. /// @param u option universe (DHCPv4 or DHCPv6)
  122. /// @param type option type
  123. Option(Universe u, uint16_t type);
  124. /// @brief Constructor, used for received options.
  125. ///
  126. /// This constructor takes vector<uint8_t>& which is used in cases
  127. /// when content of the option will be copied and stored within
  128. /// option object. V4 Options follow that approach already.
  129. /// @todo Migrate V6 options to that approach.
  130. ///
  131. /// @param u specifies universe (V4 or V6)
  132. /// @param type option type (0-255 for V4 and 0-65535 for V6)
  133. /// @param data content of the option
  134. Option(Universe u, uint16_t type, const OptionBuffer& data);
  135. /// @brief Constructor, used for received options.
  136. ///
  137. /// This constructor is similar to the previous one, but it does not take
  138. /// the whole vector<uint8_t>, but rather subset of it.
  139. ///
  140. /// @todo This can be templated to use different containers, not just
  141. /// vector. Prototype should look like this:
  142. /// template<typename InputIterator> Option(Universe u, uint16_t type,
  143. /// InputIterator first, InputIterator last);
  144. ///
  145. /// vector<int8_t> myData;
  146. /// Example usage: new Option(V4, 123, myData.begin()+1, myData.end()-1)
  147. /// This will create DHCPv4 option of type 123 that contains data from
  148. /// trimmed (first and last byte removed) myData vector.
  149. ///
  150. /// @param u specifies universe (V4 or V6)
  151. /// @param type option type (0-255 for V4 and 0-65535 for V6)
  152. /// @param first iterator to the first element that should be copied
  153. /// @param last iterator to the next element after the last one
  154. /// to be copied.
  155. Option(Universe u, uint16_t type, OptionBufferConstIter first,
  156. OptionBufferConstIter last);
  157. /// @brief returns option universe (V4 or V6)
  158. ///
  159. /// @return universe type
  160. Universe getUniverse() const { return universe_; };
  161. /// @brief Writes option in wire-format to a buffer.
  162. ///
  163. /// Writes option in wire-format to buffer, returns pointer to first unused
  164. /// byte after stored option (that is useful for writing options one after
  165. /// another).
  166. ///
  167. /// @param buf pointer to a buffer
  168. ///
  169. /// @throw BadValue Universe of the option is neither V4 nor V6.
  170. virtual void pack(isc::util::OutputBuffer& buf);
  171. /// @brief Parses received buffer.
  172. ///
  173. /// @param begin iterator to first byte of option data
  174. /// @param end iterator to end of option data (first byte after option end)
  175. virtual void unpack(OptionBufferConstIter begin,
  176. OptionBufferConstIter end);
  177. /// Returns string representation of the option.
  178. ///
  179. /// @param indent number of spaces before printing text
  180. ///
  181. /// @return string with text representation.
  182. virtual std::string toText(int indent = 0);
  183. /// @brief Returns string representation of the value
  184. ///
  185. /// This is terse repesentation used in cases where client classification
  186. /// refers to a specific option.
  187. ///
  188. /// @return string that represents the value of the option.
  189. virtual std::string toString();
  190. /// @brief Returns binary representation of the option.
  191. ///
  192. /// @param include_header Boolean flag which indicates if the output should
  193. /// also contain header fields. The default is that it shouldn't include
  194. /// header fields.
  195. ///
  196. /// @return Vector holding binary representation of the option.
  197. virtual std::vector<uint8_t> toBinary(const bool include_header = false);
  198. /// @brief Returns string containing hexadecimal representation of option.
  199. ///
  200. /// @param include_header Boolean flag which indicates if the output should
  201. /// also contain header fields. The default is that it shouldn't include
  202. /// header fields.
  203. ///
  204. /// @return String containing hexadecimal representation of the option.
  205. virtual std::string toHexString(const bool include_header = false);
  206. /// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
  207. ///
  208. /// @return option type
  209. uint16_t getType() const { return (type_); }
  210. /// Returns length of the complete option (data length + DHCPv4/DHCPv6
  211. /// option header)
  212. ///
  213. /// @return length of the option
  214. virtual uint16_t len();
  215. /// @brief Returns length of header (2 for v4, 4 for v6)
  216. ///
  217. /// @return length of option header
  218. virtual uint16_t getHeaderLen();
  219. /// returns if option is valid (e.g. option may be truncated)
  220. ///
  221. /// @return true, if option is valid
  222. virtual bool valid();
  223. /// Returns pointer to actual data.
  224. ///
  225. /// @return pointer to actual data (or reference to an empty vector
  226. /// if there is no data)
  227. virtual const OptionBuffer& getData() const { return (data_); }
  228. /// Adds a sub-option.
  229. ///
  230. /// Some DHCPv6 options can have suboptions. This method allows adding
  231. /// options within options.
  232. ///
  233. /// Note: option is passed by value. That is very convenient as it allows
  234. /// downcasting from any derived classes, e.g. shared_ptr<Option6_IA> type
  235. /// can be passed directly, without any casts. That would not be possible
  236. /// with passing by reference. addOption() is expected to be used in
  237. /// many places. Requiring casting is not feasible.
  238. ///
  239. /// @param opt shared pointer to a suboption that is going to be added.
  240. void addOption(OptionPtr opt);
  241. /// Returns shared_ptr to suboption of specific type
  242. ///
  243. /// @param type type of requested suboption
  244. ///
  245. /// @return shared_ptr to requested suoption
  246. OptionPtr getOption(uint16_t type);
  247. /// @brief Returns all encapsulated options.
  248. ///
  249. /// @warning This function returns a reference to the container holding
  250. /// encapsulated options, which is valid as long as the object which
  251. /// returned it exists.
  252. const OptionCollection& getOptions() const {
  253. return (options_);
  254. }
  255. /// Attempts to delete first suboption of requested type
  256. ///
  257. /// @param type Type of option to be deleted.
  258. ///
  259. /// @return true if option was deleted, false if no such option existed
  260. bool delOption(uint16_t type);
  261. /// @brief Returns content of first byte.
  262. ///
  263. /// @throw isc::OutOfRange Thrown if the option has a length of 0.
  264. ///
  265. /// @return value of the first byte
  266. uint8_t getUint8();
  267. /// @brief Returns content of first word.
  268. ///
  269. /// @throw isc::OutOfRange Thrown if the option has a length less than 2.
  270. ///
  271. /// @return uint16_t value stored on first two bytes
  272. uint16_t getUint16();
  273. /// @brief Returns content of first double word.
  274. ///
  275. /// @throw isc::OutOfRange Thrown if the option has a length less than 4.
  276. ///
  277. /// @return uint32_t value stored on first four bytes
  278. uint32_t getUint32();
  279. /// @brief Sets content of this option to singe uint8 value.
  280. ///
  281. /// Option it resized appropriately (to length of 1 octet).
  282. ///
  283. /// @param value value to be set
  284. void setUint8(uint8_t value);
  285. /// @brief Sets content of this option to singe uint16 value.
  286. ///
  287. /// Option it resized appropriately (to length of 2 octets).
  288. ///
  289. /// @param value value to be set
  290. void setUint16(uint16_t value);
  291. /// @brief Sets content of this option to singe uint32 value.
  292. ///
  293. /// Option it resized appropriately (to length of 4 octets).
  294. ///
  295. /// @param value value to be set
  296. void setUint32(uint32_t value);
  297. /// @brief Sets content of this option from buffer.
  298. ///
  299. /// Option will be resized to length of buffer.
  300. ///
  301. /// @param first iterator pointing to beginning of buffer to copy.
  302. /// @param last iterator pointing to end of buffer to copy.
  303. ///
  304. /// @tparam InputIterator type of the iterator representing the
  305. /// limits of the buffer to be assigned to a data_ buffer.
  306. template<typename InputIterator>
  307. void setData(InputIterator first, InputIterator last) {
  308. data_.assign(first, last);
  309. }
  310. /// @brief Sets the name of the option space encapsulated by this option.
  311. ///
  312. /// @param encapsulated_space name of the option space encapsulated by
  313. /// this option.
  314. void setEncapsulatedSpace(const std::string& encapsulated_space) {
  315. encapsulated_space_ = encapsulated_space;
  316. }
  317. /// @brief Returns the name of the option space encapsulated by this option.
  318. ///
  319. /// @return name of the option space encapsulated by this option.
  320. std::string getEncapsulatedSpace() const {
  321. return (encapsulated_space_);
  322. }
  323. /// @brief Set callback function to be used to parse options.
  324. ///
  325. /// @param callback An instance of the callback function or NULL to
  326. /// uninstall callback.
  327. void setCallback(UnpackOptionsCallback callback) {
  328. callback_ = callback;
  329. }
  330. /// just to force that every option has virtual dtor
  331. virtual ~Option();
  332. /// @brief Checks if options are equal.
  333. ///
  334. /// This method calls a virtual @c equals function to compare objects.
  335. /// This method is not meant to be overriden in the derived classes.
  336. /// Instead, the other @c equals function must be overriden.
  337. ///
  338. /// @param other Pointer to the option to compare this option to.
  339. /// @return true if both options are equal, false otherwise.
  340. bool equals(const OptionPtr& other) const;
  341. /// @brief Checks if two options are equal.
  342. ///
  343. /// Equality verifies option type and option content. Care should
  344. /// be taken when using this method. Implementation for derived
  345. /// classes should be provided when this method is expected to be
  346. /// used. It is safe in general, as the first check (different types)
  347. /// will detect differences between base Option and derived
  348. /// objects.
  349. ///
  350. /// @param other Instance of the option to compare to.
  351. ///
  352. /// @return true if options are equal, false otherwise.
  353. virtual bool equals(const Option& other) const;
  354. protected:
  355. /// @brief Store option's header in a buffer.
  356. ///
  357. /// This method writes option's header into a buffer in the
  358. /// on-wire format. The universe set for the particular option
  359. /// is used to determine whether option code and length are
  360. /// stored as 2-byte (for DHCPv6) or single-byte (for DHCPv4)
  361. /// values. For DHCPv4 options, this method checks if the
  362. /// length does not exceed 255 bytes and throws exception if
  363. /// it does.
  364. /// This method is used by derived classes to pack option's
  365. /// header into a buffer. This method should not be called
  366. /// directly by other classes.
  367. ///
  368. /// @param [out] buf output buffer.
  369. void packHeader(isc::util::OutputBuffer& buf);
  370. /// @brief Store sub options in a buffer.
  371. ///
  372. /// This method stores all sub-options defined for a particular
  373. /// option in a on-wire format in output buffer provided.
  374. /// This function is called by pack function in this class or
  375. /// derived classes that override pack.
  376. ///
  377. /// @param [out] buf output buffer.
  378. ///
  379. /// @todo The set of exceptions thrown by this function depend on
  380. /// exceptions thrown by pack methods invoked on objects
  381. /// representing sub options. We should consider whether to aggregate
  382. /// those into one exception which can be documented here.
  383. void packOptions(isc::util::OutputBuffer& buf);
  384. /// @brief Builds a collection of sub options from the buffer.
  385. ///
  386. /// This method parses the provided buffer and builds a collection
  387. /// of objects representing sub options. This function may throw
  388. /// different exceptions when option assembly fails.
  389. ///
  390. /// @param buf buffer to be parsed.
  391. ///
  392. /// @todo The set of exceptions thrown by this function depend on
  393. /// exceptions thrown by unpack methods invoked on objects
  394. /// representing sub options. We should consider whether to aggregate
  395. /// those into one exception which can be documented here.
  396. void unpackOptions(const OptionBuffer& buf);
  397. /// @brief Returns option header in the textual format.
  398. ///
  399. /// This protected method should be called by the derived classes in
  400. /// their respective @c toText implementations.
  401. ///
  402. /// @param indent Number of spaces to insert before the text.
  403. /// @param type_name Option type name. If empty, the option name
  404. /// is omitted.
  405. ///
  406. /// @return Option header in the textual format.
  407. std::string headerToText(const int indent = 0,
  408. const std::string& type_name = "");
  409. /// @brief Returns collection of suboptions in the textual format.
  410. ///
  411. /// This protected method should be called by the derived classes
  412. /// in their respective @c toText implementations to append the
  413. /// suboptions held by this option. Note that there are some
  414. /// option types which don't have suboptions because they contain
  415. /// variable length fields. For such options this method is not
  416. /// called.
  417. ///
  418. /// @param indent Number of spaces to insert before the text.
  419. ///
  420. //// @return Suboptions in the textual format.
  421. std::string suboptionsToText(const int indent = 0) const;
  422. /// @brief A protected method used for option correctness.
  423. ///
  424. /// It is used in constructors. In there are any problems detected
  425. /// (like specifying type > 255 for DHCPv4 option), it will throw
  426. /// BadValue or OutOfRange exceptions.
  427. void check();
  428. /// option universe (V4 or V6)
  429. Universe universe_;
  430. /// option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
  431. uint16_t type_;
  432. /// contains content of this data
  433. OptionBuffer data_;
  434. /// collection for storing suboptions
  435. OptionCollection options_;
  436. /// Name of the option space being encapsulated by this option.
  437. std::string encapsulated_space_;
  438. /// A callback to be called to unpack options from the packet.
  439. UnpackOptionsCallback callback_;
  440. /// @todo probably 2 different containers have to be used for v4 (unique
  441. /// options) and v6 (options with the same type can repeat)
  442. };
  443. } // namespace isc::dhcp
  444. } // namespace isc
  445. #endif // OPTION_H