edns.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // Copyright (C) 2010 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 __EDNS_H
  15. #define __EDNS_H 1
  16. #include <stdint.h>
  17. #include <boost/shared_ptr.hpp>
  18. #include <ostream>
  19. #include <dns/rdata.h>
  20. namespace isc {
  21. namespace util {
  22. namespace io {
  23. class OutputBuffer;
  24. }
  25. }
  26. namespace dns {
  27. class EDNS;
  28. class Name;
  29. class MessageRenderer;
  30. class RRClass;
  31. class RRTTL;
  32. class RRType;
  33. class Rcode;
  34. /// \brief A pointer-like type pointing to an \c EDNS object.
  35. typedef boost::shared_ptr<EDNS> EDNSPtr;
  36. /// \brief A pointer-like type pointing to an immutable \c EDNS object.
  37. typedef boost::shared_ptr<const EDNS> ConstEDNSPtr;
  38. /// The \c EDNS class represents the %EDNS OPT RR defined in RFC2671.
  39. ///
  40. /// This class encapsulates various optional features of %EDNS such as
  41. /// the UDP payload size or the DNSSEC DO bit, and provides interfaces
  42. /// to manage these features. It is also responsible for conversion
  43. /// to and from wire-format OPT RR.
  44. /// One important exception is about the extended RCODE:
  45. /// The \c EDNS class is only responsible for extracting the 8-bit part
  46. /// of the 12-bit extended RCODE from the OPT RR's TTL field of an
  47. /// incoming message, and for setting the 8-bit part into the OPT RR TTL
  48. /// of an outgoing message. It's not supposed to know how to construct the
  49. /// complete RCODE, much less maintain the RCODE in it.
  50. /// It is the caller's responsibility (typically the \c Message class).
  51. ///
  52. /// When converting wire-format OPT RR into an \c EDNS object, it normalizes
  53. /// the information, i.e., unknown flags will be ignored on construction.
  54. ///
  55. /// This class is also supposed to support %EDNS options such as NSID,
  56. /// but the initial implementation does not include it. This is a near term
  57. /// TODO item.
  58. ///
  59. /// <b>Notes to developers</b>
  60. ///
  61. /// The rest of the description is for developers who need to or want to
  62. /// understand the design of this API.
  63. ///
  64. /// Representing %EDNS is tricky. An OPT RR is no different from other RRs
  65. /// in terms of the wire format syntax, and in that sense we could use the
  66. /// generic \c RRset class to represent an OPT RR (BIND 9 adopts this
  67. /// approach). But the resulting interface would be inconvenient for
  68. /// developers. For example, the developer would need to know that the
  69. /// UDP size is encoded in the RR Class field. It's better to provide
  70. /// a more abstract interface along with the special semantics of OPT RR.
  71. ///
  72. /// Another approach would be to realize each optional feature of EDNS
  73. /// as an attribute of the DNS message.
  74. /// NLnet Labs' ldns takes this approach.
  75. /// This way an operation for specifying the UDP size would be written
  76. /// like this:
  77. /// \code message->setUDPSize(4096); \endcode
  78. /// which should be more intuitive.
  79. /// A drawback of this approach is that OPT RR is itself optional and the
  80. /// separate parameters may not necessarily indicate whether to include an
  81. /// OPT RR per se.
  82. /// For example, consider what should be done with this code:
  83. /// \code message->setUDPSize(512); \endcode
  84. /// Since the payload size of 512 is the default, it may mean the OPT RR
  85. /// should be skipped. But it might also mean the caller intentionally
  86. /// (for some reason) wants to insert an OPT RR specifying the default UDP
  87. /// size explicitly.
  88. ///
  89. /// So, we use a separate class that encapsulates the EDNS semantics and
  90. /// knows the mapping between the semantics and the wire format representation.
  91. /// This way the interface can be semantics-based and is intuitive:
  92. /// \code edns->setUDPSize(4096); \endcode
  93. /// while we can explicitly specify whether to include an OPT RR by setting
  94. /// (or not setting) an \c EDNS object in a message:
  95. /// \code message->setEDNS(edns); // unless we do this OPT RR is skipped
  96. /// \endcode
  97. ///
  98. /// There is still a non trivial point: How to manage extended RCODEs.
  99. /// An OPT RR encodes the upper 8 bits of extended 12-bit RCODE.
  100. /// In general, it would be better to provide a unified interface to get
  101. /// access to RCODEs whether or not they are traditional 4 bit codes or
  102. /// extended ones that have non 0 upper bits.
  103. /// However, since an OPT RR may not appear in a message the RCODE cannot be
  104. /// maintained in the \c EDNS class.
  105. /// But it would not be desirable to maintain the extended RCODEs completely
  106. /// in the \c Message class, either, because we wanted to hide the mapping
  107. /// between %EDNS semantics and its wire format representation within the
  108. /// \c EDNS class; if we moved the responsibility about RCODEs to the
  109. /// \c Message class, it would have to parse and render the upper 8 bits of
  110. /// the RCODEs, dealing with wire representation of OPT RR.
  111. /// This is suboptimal in the sense of encapsulation.
  112. ///
  113. /// As a compromise, our decision is to separate the knowledge about the
  114. /// relationship with RCODE from the knowledge about the wire format as
  115. /// noted in the beginning of this description.
  116. ///
  117. /// This decoupling is based on the observation that the extended RCODE
  118. /// is a very special case where %EDNS only has partial information.
  119. /// If a future version of the %EDNS protocol introduces further relationship
  120. /// between the message and the %EDNS, we might reconsider the interface,
  121. /// probably with higher abstraction.
  122. class EDNS {
  123. public:
  124. ///
  125. /// \name Constructors and Destructor
  126. ///
  127. /// We use the default copy constructor, default copy assignment operator,
  128. /// and default destructors intentionally.
  129. ///
  130. /// Note about copyability: This version of this class is copyable,
  131. /// but we may want to change it once we support EDNS options, when
  132. /// we want to revise this class using the pimpl idiom.
  133. /// But we should be careful about that: the python binding currently
  134. /// assumes this class is copyable.
  135. //@{
  136. /// Constructor with the EDNS version.
  137. /// An application would use this constructor to specify EDNS parameters
  138. /// and/or options for outgoing DNS messages.
  139. ///
  140. /// All other parameters than the version number will be initialized to
  141. /// reasonable defaults.
  142. /// Specifically, the UDP payload size is set to
  143. /// \c Message::DEFAULT_MAX_UDPSIZE, and DNSSEC is assumed to be not
  144. /// supported.
  145. /// These parameters can be altered via setter methods of this class.
  146. /// Note, however, that the version number cannot be changed once
  147. /// constructed.
  148. ///
  149. /// The version number parameter can be omitted, in which case the highest
  150. /// supported version in this implementation will be assumed.
  151. /// When specified, if it is larger than the highest supported version,
  152. /// an exception of class \c isc::InvalidParameter will be thrown.
  153. ///
  154. /// This constructor throws no other exception.
  155. ///
  156. /// \param version The version number of the EDNS to be constructed.
  157. explicit EDNS(const uint8_t version = SUPPORTED_VERSION);
  158. /// \brief Constructor from resource record (RR) parameters.
  159. ///
  160. /// This constructor is intended to be used to construct an EDNS object
  161. /// from an OPT RR contained in an incoming DNS message.
  162. ///
  163. /// Unlike many other constructors for this purpose, this constructor
  164. /// does not take the bare wire-format %data in the form of an
  165. /// \c InputBuffer object. This is because parsing incoming EDNS is
  166. /// highly context dependent and it's not feasible to handle it in a
  167. /// completely polymorphic way. For example, a DNS message parser would
  168. /// have to check an OPT RR appears at most once in the message, and if
  169. /// it appears it should be in the additional section. So, the parser
  170. /// needs to have an explicit check to see if an RR is of type OPT, and
  171. /// then (if other conditions are met) construct a corresponding \c EDNS
  172. /// object. At that point the parser would have already converted the
  173. /// wire %data into corresponding objects of \c Name, \c RRClass,
  174. /// \c RRType, etc, and it makes more sense to pass them directly to the
  175. /// constructor.
  176. ///
  177. /// In practice, top level applications rarely need to use this
  178. /// constructor directly. It should normally suffice to have a higher
  179. /// level class such as \c Message do that job.
  180. ///
  181. /// This constructor checks the passed parameters to see if they are
  182. /// valid in terms of the EDNS protocol specification.
  183. /// \c name must be the root name ("."); otherwise, an exception of
  184. /// class \c DNSMessageFORMERR will be thrown.
  185. /// \c rrtype must specify the OPT RR type; otherwise, an exception of
  186. /// class \c isc::InvalidParameter will be thrown.
  187. /// The ENDS version number is extracted from \c rrttl. If it is larger
  188. /// than the higher supported version, an exception of class
  189. /// \c DNSMessageBADVERS will be thrown. Note that this is different from
  190. /// the case of the same error in the other constructor.
  191. /// This is intentional, so that the application can transparently convert
  192. /// the exception to a response RCODE according to the protocol
  193. /// specification.
  194. ///
  195. /// This initial implementation does not support EDNS options at all,
  196. /// and \c rdata is simply ignored. Future versions will support
  197. /// options, and may throw exceptions while validating the given parameter.
  198. ///
  199. /// \b Note: since no other type than OPT for \c rrtype is allowed, this
  200. /// parameter could actually have been omitted. But it is intentionally
  201. /// included as a parameter so that invalid usage of the construction
  202. /// can be detected. As noted above the caller should normally have
  203. /// the corresponding \c RRType object at the time of call to this
  204. /// constructor, so the overhead of having the additional parameter
  205. /// should be marginal.
  206. ///
  207. /// \param name The owner name of the OPT RR. This must be the root name.
  208. /// \param rrclass The RR class of the OPT RR.
  209. /// \param rrtype This must specify the OPT RR type.
  210. /// \param ttl The TTL of the OPT RR.
  211. /// \param rdata The RDATA of the OPT RR.
  212. EDNS(const Name& name, const RRClass& rrclass, const RRType& rrtype,
  213. const RRTTL& ttl, const rdata::Rdata& rdata);
  214. //@}
  215. ///
  216. /// \name Getter and Setter Methods
  217. ///
  218. //@{
  219. /// \brief Returns the version of EDNS.
  220. ///
  221. /// This method never throws an exception.
  222. uint8_t getVersion() const { return (version_); }
  223. /// \brief Returns the maximum payload size of UDP messages for the sender
  224. /// of the message containing this \c EDNS.
  225. ///
  226. /// This method never throws an exception.
  227. uint16_t getUDPSize() const { return (udp_size_); }
  228. /// \brief Specify the maximum payload size of UDP messages that use
  229. /// this EDNS.
  230. ///
  231. /// Unless explicitly specified, \c DEFAULT_MAX_UDPSIZE will be assumed
  232. /// for the maximum payload size, regardless of whether EDNS OPT RR is
  233. /// included or not. This means if an application wants to send a message
  234. /// with an EDNS OPT RR for specifying a larger UDP size, it must
  235. /// explicitly specify the value using this method.
  236. ///
  237. /// This method never throws an exception.
  238. ///
  239. /// \param udp_size The maximum payload size of UDP messages for the sender
  240. /// of the message containing this \c EDNS.
  241. void setUDPSize(const uint16_t udp_size) { udp_size_ = udp_size; }
  242. /// \brief Returns whether the message sender is DNSSEC aware.
  243. ///
  244. /// This method never throws an exception.
  245. ///
  246. /// \return true if DNSSEC is supported; otherwise false.
  247. bool getDNSSECAwareness() const { return (dnssec_aware_); }
  248. /// \brief Specifies whether the sender of the message containing this
  249. /// \c EDNS is DNSSEC aware.
  250. ///
  251. /// If the parameter is true, a subsequent call to \c toWire() will
  252. /// set the DNSSEC DO bit on for the corresponding OPT RR.
  253. ///
  254. /// This method never throws an exception.
  255. ///
  256. /// \param is_aware \c true if DNSSEC is supported; \c false otherwise.
  257. void setDNSSECAwareness(const bool is_aware) { dnssec_aware_ = is_aware; }
  258. //@}
  259. ///
  260. /// \name Converter Methods
  261. ///
  262. //@{
  263. /// \brief Render the \c EDNS in the wire format.
  264. ///
  265. /// This method renders the \c EDNS object as a form of DNS OPT RR
  266. /// via \c renderer, which encapsulates output buffer and other rendering
  267. /// contexts.
  268. /// Since the \c EDNS object does not maintain the extended RCODE
  269. /// information, a separate parameter \c extended_rcode must be passed to
  270. /// this method.
  271. ///
  272. /// If by adding the OPT RR the message size would exceed the limit
  273. /// maintained in \c renderer, this method skips rendering the RR
  274. /// and returns 0; otherwise it returns 1, which is the number of RR
  275. /// rendered.
  276. ///
  277. /// In the current implementation the return value is either 0 or 1, but
  278. /// the return type is <code>unsigned int</code> to be consistent with
  279. /// \c RRset::toWire(). In any case the caller shouldn't assume these are
  280. /// only possible return values from this method.
  281. ///
  282. /// This method is mostly exception free, but it requires memory
  283. /// allocation and if it fails a corresponding standard exception will be
  284. /// thrown.
  285. ///
  286. /// In practice, top level applications rarely need to use this
  287. /// method directly. It should normally suffice to have a higher
  288. /// level class such as \c Message do that job.
  289. ///
  290. /// <b>Note to developer:</b> the current implementation constructs an
  291. /// \c RRset object for the OPT RR and calls its \c toWire() method,
  292. /// which is inefficient. In future, we may want to optimize this method
  293. /// by caching the rendered image and having the application reuse the
  294. /// same \c EDNS object when possible.
  295. ///
  296. /// \param renderer DNS message rendering context that encapsulates the
  297. /// output buffer and name compression information.
  298. /// \param extended_rcode Upper 8 bits of extended RCODE to be rendered as
  299. /// part of the EDNS OPT RR.
  300. /// \return 1 if the OPT RR fits in the message size limit; otherwise 0.
  301. unsigned int toWire(MessageRenderer& renderer,
  302. const uint8_t extended_rcode) const;
  303. /// \brief Render the \c EDNS in the wire format.
  304. ///
  305. /// This method is same as \c toWire(MessageRenderer&,uint8_t)const
  306. /// except it renders the OPT RR in an \c OutputBuffer and therefore
  307. /// does not care about message size limit.
  308. /// As a consequence it always returns 1.
  309. unsigned int toWire(isc::util::io::OutputBuffer& buffer,
  310. const uint8_t extended_rcode) const;
  311. /// \brief Convert the EDNS to a string.
  312. ///
  313. /// The format of the resulting string is as follows:
  314. /// \code ; EDNS: version: <version>, flags: <edns flags>; udp: <udp size>
  315. /// \endcode
  316. /// where
  317. /// - \em version is the EDNS version number (integer).
  318. /// - <em>edns flags</em> is a sequence of EDNS flag bits. The only
  319. /// possible flag is the "DNSSEC OK", which is represented as "do".
  320. /// - <em>udp size</em> is sender's UDP payload size in bytes.
  321. ///
  322. /// The string will be terminated with a trailing newline character.
  323. ///
  324. /// When EDNS options are supported the output of this method will be
  325. /// extended.
  326. ///
  327. /// This method is mostly exception free, but it may require memory
  328. /// allocation and if it fails a corresponding standard exception will be
  329. /// thrown.
  330. ///
  331. /// \return A string representation of \c EDNS. See above for the format.
  332. std::string toText() const;
  333. //@}
  334. // TBD: This method is currently not implemented. We'll eventually need
  335. // something like this.
  336. //void addOption();
  337. private:
  338. /// Helper method to define unified implementation for the public versions
  339. /// of toWire().
  340. template <typename Output>
  341. int toWire(Output& output, const uint8_t extended_rcode) const;
  342. public:
  343. /// \brief The highest EDNS version this implementation supports.
  344. static const uint8_t SUPPORTED_VERSION = 0;
  345. private:
  346. // We may eventually want to migrate to pimpl, especially when we support
  347. // EDNS options. In this initial implementation, we keep it simple.
  348. const uint8_t version_;
  349. uint16_t udp_size_;
  350. bool dnssec_aware_;
  351. };
  352. /// \brief Create a new \c EDNS object from a set of RR parameters, also
  353. /// providing the extended RCODE value.
  354. ///
  355. /// This function is similar to the EDNS class constructor
  356. /// \c EDNS::EDNS(const Name&, const RRClass&, const RRType&, const RRTTL&, const rdata::Rdata&)
  357. /// but is different in that
  358. /// - It dynamically creates a new object
  359. /// - It returns (via a reference argument) the topmost 8 bits of the extended
  360. /// RCODE encoded in the \c ttl.
  361. ///
  362. /// On success, \c extended_rcode will be updated with the 8-bit part of
  363. /// the extended RCODE encoded in the TTL of the OPT RR.
  364. ///
  365. /// The intended usage of this function is to parse an OPT RR of an incoming
  366. /// DNS message, while updating the RCODE of the message.
  367. /// One common usage patter is as follows:
  368. ///
  369. /// \code Message msg;
  370. /// ...
  371. /// uint8_t extended_rcode;
  372. /// ConstEDNSPtr edns = ConstEDNSPtr(createEDNSFromRR(..., extended_rcode));
  373. /// rcode = Rcode(msg.getRcode().getCode(), extended_rcode);
  374. /// \endcode
  375. /// (although, like the \c EDNS constructor, normal applications wouldn't have
  376. /// to use this function directly).
  377. ///
  378. /// This function provides the strong exception guarantee: Unless an
  379. /// exception is thrown \c extended_code won't be modified.
  380. ///
  381. /// This function validates the given parameters and throws exceptions on
  382. /// failure in the same way as the \c EDNS class constructor.
  383. /// In addition, if memory allocation for the new object fails it throws the
  384. /// corresponding standard exception.
  385. ///
  386. /// Note that this function returns a bare pointer to the newly allocated
  387. /// object, not a shared pointer object enclosing the pointer.
  388. /// The caller is responsible for deleting the object after the use of it
  389. /// (typically, the caller would immediately encapsulate the returned pointer
  390. /// in a shared pointer object, \c EDNSPtr or \c ConstEDNSPtr).
  391. /// It returns a bare pointer so that it can be used where the use of a shared
  392. /// pointer is impossible or not desirable.
  393. ///
  394. /// Note to developers: there is no strong technical reason why this function
  395. /// cannot be a constructor of the \c EDNS class or even integrated into the
  396. /// constructor. But we decided to make it a separate free function so that
  397. /// constructors will be free from side effects (which is in itself a matter
  398. /// of preference).
  399. ///
  400. /// \param name The owner name of the OPT RR. This must be the root name.
  401. /// \param rrclass The RR class of the OPT RR.
  402. /// \param rrtype This must specify the OPT RR type.
  403. /// \param ttl The TTL of the OPT RR.
  404. /// \param rdata The RDATA of the OPT RR.
  405. /// \param extended_rcode A placeholder to store the topmost 8 bits of the
  406. /// extended Rcode.
  407. /// \return A pointer to the created \c EDNS object.
  408. EDNS* createEDNSFromRR(const Name& name, const RRClass& rrclass,
  409. const RRType& rrtype, const RRTTL& ttl,
  410. const rdata::Rdata& rdata, uint8_t& extended_rcode);
  411. /// \brief Insert the \c EDNS as a string into stream.
  412. ///
  413. /// This method convert \c edns into a string and inserts it into the
  414. /// output stream \c os.
  415. ///
  416. /// \param os A \c std::ostream object on which the insertion operation is
  417. /// performed.
  418. /// \param edns A reference to an \c EDNS object output by the operation.
  419. /// \return A reference to the same \c std::ostream object referenced by
  420. /// parameter \c os after the insertion operation.
  421. std::ostream& operator<<(std::ostream& os, const EDNS& edns);
  422. }
  423. }
  424. #endif // __EDNS_H
  425. // Local Variables:
  426. // mode: c++
  427. // End: