option4_client_fqdn.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. // Copyright (C) 2013 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 OPTION4_CLIENT_FQDN_H
  15. #define OPTION4_CLIENT_FQDN_H
  16. #include <dhcp/option.h>
  17. #include <dns/name.h>
  18. #include <string>
  19. namespace isc {
  20. namespace dhcp {
  21. /// @brief Exception thrown when invalid flags have been specified for
  22. /// DHCPv4 Client FQDN %Option.
  23. class InvalidOption4FqdnFlags : public Exception {
  24. public:
  25. InvalidOption4FqdnFlags(const char* file, size_t line, const char* what) :
  26. isc::Exception(file, line, what) {}
  27. };
  28. /// @brief Exception thrown when invalid domain name is specified.
  29. class InvalidOption4FqdnDomainName : public Exception {
  30. public:
  31. InvalidOption4FqdnDomainName(const char* file, size_t line,
  32. const char* what) :
  33. isc::Exception(file, line, what) {}
  34. };
  35. /// Forward declaration to implementation of @c Option4ClientFqdn class.
  36. class Option4ClientFqdnImpl;
  37. /// @brief Represents DHCPv4 Client FQDN %Option (code 81).
  38. ///
  39. /// This option has been defined in the RFC 4702 and it has a following
  40. /// structure:
  41. /// - Code (1 octet) - option code (always equal to 81).
  42. /// - Len (1 octet) - a length of the option.
  43. /// - Flags (1 octet) - a field carrying "NEOS" flags described below.
  44. /// - RCODE1 (1 octet) - deprecated field which should be set to 0 by the client
  45. /// and set to 255 by the server.
  46. /// - RCODE2 (1 octet) - deprecated, should be used in the same way as RCODE1.
  47. /// - Domain Name - variable length field comprising partial or fully qualified
  48. /// domain name.
  49. ///
  50. /// The flags field has the following structure:
  51. /// @code
  52. /// 0 1 2 3 4 5 6 7
  53. /// +-+-+-+-+-+-+-+-+
  54. /// | MBZ |N|E|O|S|
  55. /// +-+-+-+-+-+-+-+-+
  56. /// @endcode
  57. /// where:
  58. /// - N flag specifies whether server should (0) or should not (1) perform DNS
  59. /// Update,
  60. /// - E flag specifies encoding of the Domain Name field. If this flag is set
  61. /// to 1 it indicates canonical wire format without compression. 0 indicates
  62. /// the deprecated ASCII format.
  63. /// - O flag is set by the server to indicate that it has overridden client's
  64. /// preference set with the S bit.
  65. /// - S flag specifies whether server should (1) or should not (0) perform
  66. /// forward (FQDN-to-address) updates.
  67. ///
  68. /// This class exposes a set of functions to modify flags and check their
  69. /// correctness.
  70. ///
  71. /// Domain names being carried by DHCPv4 Client Fqdn %Option can be fully
  72. /// qualified or partial. Partial domain names are encoded similar to the
  73. /// fully qualified domain names, except that they lack terminating zero
  74. /// at the end of their wire representation (or lack of dot at the end, in
  75. /// case of ASCII encoding). It is also accepted to create an instance of
  76. /// this option which has empty domain-name. Clients use empty domain-names
  77. /// to indicate that server should generate complete fully qualified
  78. /// domain-name.
  79. ///
  80. /// @warning: The RFC4702 section 2.3.1 states that the clients and servers
  81. /// should use character sets specified in RFC952, section 2.1 for ASCII-encoded
  82. /// domain-names. This class doesn't detect the character set violation for
  83. /// ASCII-encoded domain-name. It could be implemented in the future but it is
  84. /// not important now for two reasons:
  85. /// - ASCII encoding is deprecated
  86. /// - clients SHOULD obey restrictions but if they don't, server may still
  87. /// process the option
  88. ///
  89. /// RFC 4702 mandates that the DHCP client sets RCODE1 and RCODE2 to 0 and that
  90. /// server sets them to 255. This class allows to set the value for these
  91. /// fields and both fields are always set to the same value. There is no way
  92. /// to set them separately (e.g. set different value for RCODE1 and RCODE2).
  93. /// However, there are no use cases which would require it.
  94. ///
  95. /// <b>Design choice:</b> This class uses pimpl idiom to separate the interface
  96. /// from implementation specifics. Implementations may use different approaches
  97. /// to handle domain names (mostly validation of the domain-names). The existing
  98. /// @c isc::dns::Name class is a natural (and the simplest) choice to handle
  99. /// domain-names. Use of this class however, implies that libdhcp must be linked
  100. /// with libdns. At some point these libraries may need to be separated, i.e. to
  101. /// support compilation and use of standalone DHCP server. This will require
  102. /// that the part of implementation which deals with domain-names is modified to
  103. /// not use classes from libdns. These changes will be transparent for this
  104. /// interface.
  105. class Option4ClientFqdn : public Option {
  106. public:
  107. ///
  108. /// @name A set of constants used to identify and set bits in the flags field
  109. //@{
  110. static const uint8_t FLAG_S = 0x01; ///< Bit S
  111. static const uint8_t FLAG_O = 0x02; ///< Bit O
  112. static const uint8_t FLAG_E = 0x04; ///< Bit E
  113. static const uint8_t FLAG_N = 0x08; ///< Bit N
  114. //@}
  115. /// @brief Mask which zeroes MBZ flag bits.
  116. static const uint8_t FLAG_MASK = 0xF;
  117. /// @brief Represents the value of one of the RCODE1 or RCODE2 fields.
  118. ///
  119. /// Typically, RCODE values are set to 255 by the server and to 0 by the
  120. /// clients (as per RFC 4702).
  121. class Rcode {
  122. public:
  123. Rcode(const uint8_t rcode)
  124. : rcode_(rcode) { }
  125. /// @brief Returns the value of the RCODE.
  126. ///
  127. /// Returned value can be directly used to create the on-wire format
  128. /// of the DHCPv4 Client FQDN %Option.
  129. uint8_t getCode() const {
  130. return (rcode_);
  131. }
  132. private:
  133. uint8_t rcode_;
  134. };
  135. /// @brief Type of the domain-name: partial or full.
  136. enum DomainNameType {
  137. PARTIAL,
  138. FULL
  139. };
  140. /// @brief The size in bytes of the fixed fields within DHCPv4 Client Fqdn
  141. /// %Option.
  142. ///
  143. /// The fixed fields are:
  144. /// - Flags
  145. /// - RCODE1
  146. /// - RCODE2
  147. static const uint16_t FIXED_FIELDS_LEN = 3;
  148. /// @brief Constructor, creates option instance using flags and domain name.
  149. ///
  150. /// This constructor is used to create an instance of the option which will
  151. /// be included in outgoing messages.
  152. ///
  153. /// Note that the RCODE values are encapsulated by the Rcode object (not a
  154. /// simple uint8_t value). This helps to prevent a caller from confusing the
  155. /// flags value with rcode value (both are uint8_t values). For example:
  156. /// if caller swaps the two, it will be detected in the compilation time.
  157. /// Also, this API encourages the caller to use two predefined functions:
  158. /// @c RCODE_SERVER and @c RCODE_CLIENT to set the value of RCODE. These
  159. /// functions generate objects which represent the only valid values to be
  160. /// be passed to the constructor (255 and 0 respectively). Other
  161. /// values should not be used. However, it is still possible that the other
  162. /// entity (client or server) sends the option with invalid value. Although,
  163. /// the RCODE values are ignored, there should be a way to represent such
  164. /// invalid RCODE value. The Rcode class is capable of representing it.
  165. ///
  166. /// @param flags a combination of flags to be stored in flags field.
  167. /// @param rcode @c Rcode object representing a value for RCODE1 and RCODE2
  168. /// fields of the option. Both fields are assigned the same value
  169. /// encapsulated by the parameter.
  170. /// @param domain_name a name to be stored in the domain-name field.
  171. /// @param domain_name_type indicates if the domain name is partial
  172. /// or full.
  173. /// @throw InvalidOption4FqdnFlags if value of the flags field is wrong.
  174. /// @throw InvalidOption4FqdnDomainName if the domain-name is invalid.
  175. explicit Option4ClientFqdn(const uint8_t flags,
  176. const Rcode& rcode,
  177. const std::string& domain_name,
  178. const DomainNameType domain_name_type = FULL);
  179. /// @brief Constructor, creates option instance with empty domain name.
  180. ///
  181. /// This constructor creates an instance of the option with empty
  182. /// domain-name. This domain-name is marked partial.
  183. ///
  184. /// @param flags a combination of flags to be stored in flags field.
  185. /// @param rcode @c Rcode object representing a value for RCODE1 and RCODE2
  186. /// fields. Both fields are assigned the same value encapsulated by this
  187. /// parameter.
  188. /// @throw InvalidOption4FqdnFlags if value of the flags field is invalid.
  189. Option4ClientFqdn(const uint8_t flags, const Rcode& rcode);
  190. /// @brief Constructor, creates an option instance from part of the buffer.
  191. ///
  192. /// This constructor is mainly used to parse options in the received
  193. /// messages. Function parameters specify buffer bounds from which the
  194. /// option should be created. The size of the buffer chunk, specified by
  195. /// the constructor's parameters should be equal or larger than the size
  196. /// of the option. Otherwise, constructor will throw an exception.
  197. ///
  198. /// @param first the lower bound of the buffer to create option from.
  199. /// @param last the upper bound of the buffer to create option from.
  200. /// @throw InvalidOption4FqdnFlags if value of the flags field is invalid.
  201. /// @throw InvalidOption4FqdnDomainName if the domain-name carried by the
  202. /// option is invalid.
  203. /// @throw OutOfRange if the option is truncated.
  204. explicit Option4ClientFqdn(OptionBufferConstIter first,
  205. OptionBufferConstIter last);
  206. /// @brief Copy constructor
  207. Option4ClientFqdn(const Option4ClientFqdn& source);
  208. /// @brief Destructor
  209. virtual ~Option4ClientFqdn();
  210. /// @brief Assignment operator
  211. Option4ClientFqdn& operator=(const Option4ClientFqdn& source);
  212. /// @brief Checks if the specified flag of the DHCPv4 Client FQDN %Option
  213. /// is set.
  214. ///
  215. /// @param flag A value specifying a bit within flags field to be checked.
  216. /// It must be one of the following @c FLAG_S, @c FLAG_E, @c FLAG_O,
  217. /// @c FLAG_N.
  218. ///
  219. /// @return true if the bit of the specified flags bit is set, false
  220. /// otherwise.
  221. /// @throw InvalidOption4ClientFlags if specified flag which value is to be
  222. /// returned is invalid (is not one of the FLAG_S, FLAG_N, FLAG_O).
  223. bool getFlag(const uint8_t flag) const;
  224. /// @brief Modifies the value of the specified DHCPv4 Client Fqdn %Option
  225. /// flag.
  226. ///
  227. /// @param flag A value specifying a bit within flags field to be set. It
  228. /// must be one of the following @c FLAG_S, @c FLAG_E, @c FLAG_O, @c FLAG_N.
  229. /// @param set a boolean value which indicates whether flag should be
  230. /// set (true), or cleared (false).
  231. /// @throw InvalidOption4ClientFlags if specified flag which value is to be
  232. /// set is invalid (is not one of the FLAG_S, FLAG_N, FLAG_O).
  233. void setFlag(const uint8_t flag, const bool set);
  234. /// @brief Sets the flag field value to 0.
  235. void resetFlags();
  236. /// @brief Set Rcode value.
  237. ///
  238. /// @param rcode An @c Rcode object representing value of RCODE1 and RCODE2.
  239. /// Both fields are assigned the same value.
  240. void setRcode(const Rcode& rcode);
  241. /// @brief Returns the domain-name in the text format.
  242. ///
  243. /// If domain-name is partial, it lacks the dot at the end (e.g. myhost).
  244. /// If domain-name is fully qualified, it has the dot at the end (e.g.
  245. /// myhost.example.com.).
  246. ///
  247. /// @return domain-name in the text format.
  248. std::string getDomainName() const;
  249. /// @brief Writes domain-name in the wire format into a buffer.
  250. ///
  251. /// The data being written are appended at the end of the buffer.
  252. ///
  253. /// @param [out] buf buffer where domain-name will be written.
  254. void packDomainName(isc::util::OutputBuffer& buf) const;
  255. /// @brief Set new domain-name.
  256. ///
  257. /// @param domain_name domain name field value in the text format.
  258. /// @param domain_name_type type of the domain name: partial or fully
  259. /// qualified.
  260. /// @throw InvalidOption4FqdnDomainName if the specified domain-name is
  261. /// invalid.
  262. void setDomainName(const std::string& domain_name,
  263. const DomainNameType domain_name_type);
  264. /// @brief Set empty domain-name.
  265. ///
  266. /// This function is equivalent to @c Option6ClientFqdn::setDomainName
  267. /// with empty partial domain-name. It is exception safe.
  268. void resetDomainName();
  269. /// @brief Returns enumerator value which indicates whether domain-name is
  270. /// partial or full.
  271. ///
  272. /// @return An enumerator value indicating whether domain-name is partial
  273. /// or full.
  274. DomainNameType getDomainNameType() const;
  275. /// @brief Writes option in the wire format into a buffer.
  276. ///
  277. /// @param [out] buf output buffer where option data will be stored.
  278. virtual void pack(isc::util::OutputBuffer& buf);
  279. /// @brief Parses option from the received buffer.
  280. ///
  281. /// Method creates an instance of the DHCPv4 Client FQDN %Option from the
  282. /// wire format. Parameters specify the bounds of the buffer to read option
  283. /// data from. The size of the buffer limited by the specified parameters
  284. /// should be equal or larger than size of the option (including its
  285. /// header). Otherwise exception will be thrown.
  286. ///
  287. /// @param first lower bound of the buffer to parse option from.
  288. /// @param last upper bound of the buffer to parse option from.
  289. virtual void unpack(OptionBufferConstIter first,
  290. OptionBufferConstIter last);
  291. /// @brief Returns string representation of the option.
  292. ///
  293. /// The string returned by the method comprises the bit value of each
  294. /// option flag and the domain-name.
  295. ///
  296. /// @param indent number of spaces before printed text.
  297. ///
  298. /// @return string with text representation.
  299. virtual std::string toText(int indent = 0);
  300. /// @brief Returns length of the complete option (data length +
  301. /// DHCPv4 option header).
  302. ///
  303. /// @return length of the option.
  304. virtual uint16_t len();
  305. ///
  306. /// @name Well known Rcode declarations for DHCPv4 Client FQDN %Option
  307. ///
  308. //@{
  309. /// @brief Rcode being set by the server.
  310. inline static const Rcode& RCODE_SERVER() {
  311. static Rcode rcode(255);
  312. return (rcode);
  313. }
  314. /// @brief Rcode being set by the client.
  315. inline static const Rcode& RCODE_CLIENT() {
  316. static Rcode rcode(0);
  317. return (rcode);
  318. }
  319. //@}
  320. private:
  321. /// @brief A pointer to the implementation.
  322. Option4ClientFqdnImpl* impl_;
  323. };
  324. /// A pointer to the @c Option4ClientFqdn object.
  325. typedef boost::shared_ptr<Option4ClientFqdn> Option4ClientFqdnPtr;
  326. } // namespace isc::dhcp
  327. } // namespace isc
  328. #endif // OPTION4_CLIENT_FQDN_H