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