|
@@ -42,31 +42,90 @@ typedef boost::shared_ptr<EDNS> EDNSPtr;
|
|
|
/// \brief A pointer-like type pointing to an immutable \c EDNS object.
|
|
|
typedef boost::shared_ptr<const EDNS> ConstEDNSPtr;
|
|
|
|
|
|
-/// Document why this is separated from \c Message.
|
|
|
+/// The \c EDNS class represents the %EDNS OPT RR defined in RFC2671.
|
|
|
///
|
|
|
-/// Stores normalized information: unknown flags will be ignored on
|
|
|
-/// construction.
|
|
|
+/// This class encapsulates various optional features of %EDNS such as
|
|
|
+/// the UDP payload size or the DNSSEC DO bit, and provides interfaces
|
|
|
+/// to manage these features. It is also responsible for conversion
|
|
|
+/// to and from wire-format OPT RR.
|
|
|
+/// One important exception is about the extended RCODE:
|
|
|
+/// The \c EDNS class is only responsible for extracting the 8-bit part
|
|
|
+/// of the 12-bit extended RCODE from the OPT RR's TTL field of an
|
|
|
+/// incoming message, and for setting the 8-bit part into the OPT RR TTL
|
|
|
+/// of an outgoing message. It's not supposed to know how to construct the
|
|
|
+/// complete RCODE, much less maintain the RCODE in it.
|
|
|
+/// It is the caller's responsibility (typically the \c Message class).
|
|
|
///
|
|
|
-/// Decision: separate the knowledge about the relationship with rcode and
|
|
|
-/// the wire format. EDNS is only responsible for the 8-bit part of the
|
|
|
-/// 12-bit extended RCODE.
|
|
|
+/// When converting wire-format OPT RR into an \c EDNS object, it normalizes
|
|
|
+/// the information, i.e., unknown flags will be ignored on construction.
|
|
|
///
|
|
|
-/// note: extended Rcode is handled in the Message class. We may want to
|
|
|
-/// generalize this by passing the whole Message and letting the \c EDNS
|
|
|
-/// object modify or refer to it based on the EDNS protocol. But it would
|
|
|
-/// couple the \c Message and \c EDNS more tightly. Right now, the decision
|
|
|
-/// is to consider \c Rcode is a special case; if a future version of the EDNS
|
|
|
-/// protocol introduces further relationship between the message and the EDNS,
|
|
|
-/// we might reconsider the interface, probably with higher abstraction.
|
|
|
+/// This class is also supposed to support %EDNS options such as NSID,
|
|
|
+/// but the initial implementation does not include it. This is a near term
|
|
|
+/// TODO item.
|
|
|
///
|
|
|
-/// MEMO: performance consideration: toWire() can be optimized by caching
|
|
|
-/// the rendered image and reuse EDNS
|
|
|
+/// <b>Notes to developers</b>
|
|
|
///
|
|
|
-/// This version of this class is copyable, but we may want to change it
|
|
|
-/// once we support EDNS options.
|
|
|
-/// (Note to ourselves: the python binding assumes this class is copyable).
|
|
|
+/// The rest of the description is for developers who need to or want to
|
|
|
+/// understand the design of this API.
|
|
|
///
|
|
|
-/// TBD: how to manage options is an open issue.
|
|
|
+/// Representing %EDNS is tricky. An OPT RR is no different from other RRs
|
|
|
+/// in terms of the wire format syntax, and in that sense we could use the
|
|
|
+/// generic \c RRset class to represent an OPT RR (BIND 9 adopts this
|
|
|
+/// approach). But the resulting interface would be inconvenient for
|
|
|
+/// developers. For example, the developer would need to know that the
|
|
|
+/// UDP size is encoded in the RR Class field. It's better to provide
|
|
|
+/// a more abstract interface along with the special semantics of OPT RR.
|
|
|
+///
|
|
|
+/// Another approach would be to realize each optional feature of EDNS
|
|
|
+/// as an attribute of the DNS message.
|
|
|
+/// NLnet Labs' ldns takes this approach.
|
|
|
+/// This way an operation for specifying the UDP size would be written
|
|
|
+/// like this:
|
|
|
+/// \code message->setUDPSize(4096); \endcode
|
|
|
+/// which should be more intuitive.
|
|
|
+/// A drawback of this approach is that OPT RR is itself optional and the
|
|
|
+/// separate parameters may not necessarily indicate whether to include an
|
|
|
+/// OPT RR per se.
|
|
|
+/// For example, consider what should be done with this code:
|
|
|
+/// \code message->setUDPSize(512); \endcode
|
|
|
+/// Since the payload size of 512 is the default, it may mean the OPT RR
|
|
|
+/// should be skipped. But it might also mean the caller intentionally
|
|
|
+/// (for some reason) wants to insert an OPT RR specifying the default UDP
|
|
|
+/// size explicitly.
|
|
|
+///
|
|
|
+/// So, we use a separate class that encapsulates the EDNS semantics and
|
|
|
+/// knows the mapping between the semantics and the wire format representation.
|
|
|
+/// This way the interface can be semantics-based and is intuitive:
|
|
|
+/// \code edns->setUDPSize(4096); \endcode
|
|
|
+/// while we can explicitly specify whether to include an OPT RR by setting
|
|
|
+/// (or not setting) an \c EDNS object in a message:
|
|
|
+/// \code message->setEDNS(edns); // unless we do this OPT RR is skipped
|
|
|
+/// \endcode
|
|
|
+///
|
|
|
+/// There is still a non trivial point: How to manage extended RCODEs.
|
|
|
+/// An OPT RR encodes the upper 8 bits of extended 12-bit RCODE.
|
|
|
+/// In general, it would be better to provide a unified interface to get
|
|
|
+/// access to RCODEs whether or not they are traditional 4 bit codes or
|
|
|
+/// extended ones that have non 0 upper bits.
|
|
|
+/// However, since an OPT RR may not appear in a message the RCODE cannot be
|
|
|
+/// maintained in the \c EDNS class.
|
|
|
+/// But it would not be desirable to maintain the extended RCODEs completely
|
|
|
+/// in the \c Message class, either, because we wanted to hide the mapping
|
|
|
+/// between %EDNS semantics and its wire format representation within the
|
|
|
+/// \c EDNS class; if we moved the responsibility about RCODEs to the
|
|
|
+/// \c Message class, it would have to parse and render the upper 8 bits of
|
|
|
+/// the RCODEs, dealing with wire representation of OPT RR.
|
|
|
+/// This is suboptimal in the sense of encapsulation.
|
|
|
+///
|
|
|
+/// As a compromise, our decision is to separate the knowledge about the
|
|
|
+/// relationship with RCODE from the knowledge about the wire format as
|
|
|
+/// noted in the beginning of this description.
|
|
|
+///
|
|
|
+/// This decoupling is based on the observation that the extended RCODE
|
|
|
+/// is a very special case where %EDNS only has partial information.
|
|
|
+/// If a future version of the %EDNS protocol introduces further relationship
|
|
|
+/// between the message and the %EDNS, we might reconsider the interface,
|
|
|
+/// probably with higher abstraction.
|
|
|
class EDNS {
|
|
|
public:
|
|
|
///
|
|
@@ -75,6 +134,11 @@ public:
|
|
|
/// We use the default copy constructor, default copy assignment operator,
|
|
|
/// and default destructors intentionally.
|
|
|
///
|
|
|
+ /// Note about copyability: This version of this class is copyable,
|
|
|
+ /// but we may want to change it once we support EDNS options, when
|
|
|
+ /// we want to revise this class using the pimpl idiom.
|
|
|
+ /// But we should be careful about that: the python binding currently
|
|
|
+ /// assumes this class is copyable.
|
|
|
//@{
|
|
|
/// Constructor with the EDNS version.
|
|
|
/// An application would use this constructor to specify EDNS parameters
|
|
@@ -82,7 +146,7 @@ public:
|
|
|
///
|
|
|
/// All other parameters than the version number will be initialized to
|
|
|
/// reasonable defaults.
|
|
|
- /// Specifically, the UDP buffer size is set to
|
|
|
+ /// Specifically, the UDP payload size is set to
|
|
|
/// \c Message::DEFAULT_MAX_UDPSIZE, and DNSSEC is assumed to be not
|
|
|
/// supported.
|
|
|
/// These parameters can be altered via setter methods of this class.
|
|
@@ -136,11 +200,11 @@ public:
|
|
|
/// the exception to a response RCODE according to the protocol
|
|
|
/// specification.
|
|
|
///
|
|
|
- /// In this initial implementation does not support EDNS options at all,
|
|
|
+ /// This initial implementation does not support EDNS options at all,
|
|
|
/// and \c rdata is simply ignored. Future versions will support
|
|
|
/// options, and may throw exceptions while validating the given parameter.
|
|
|
///
|
|
|
- /// Note: since no other type than OPT for \c rrtype is allowed, this
|
|
|
+ /// \b Note: since no other type than OPT for \c rrtype is allowed, this
|
|
|
/// parameter could actually have been omitted. But it is intentionally
|
|
|
/// included as a parameter so that invalid usage of the construction
|
|
|
/// can be detected. As noted above the caller should normally have
|
|
@@ -162,47 +226,125 @@ public:
|
|
|
///
|
|
|
//@{
|
|
|
/// \brief Returns the version of EDNS.
|
|
|
+ ///
|
|
|
+ /// This method never throws an exception.
|
|
|
uint8_t getVersion() const { return (version_); }
|
|
|
|
|
|
- /// \brief Return the maximum buffer size of UDP messages for the sender
|
|
|
- /// of the message.
|
|
|
+ /// \brief Returns the maximum payload size of UDP messages for the sender
|
|
|
+ /// of the message containing this \c EDNS.
|
|
|
+ ///
|
|
|
+ /// This method never throws an exception.
|
|
|
uint16_t getUDPSize() const { return (udp_size_); }
|
|
|
|
|
|
- /// \brief Specify the maximum buffer size of UDP messages that use
|
|
|
+ /// \brief Specify the maximum payload size of UDP messages that use
|
|
|
/// this EDNS.
|
|
|
///
|
|
|
/// Unless explicitly specified, \c DEFAULT_MAX_UDPSIZE will be assumed
|
|
|
- /// for the maximum buffer size, regardless of whether EDNS OPT RR is
|
|
|
+ /// for the maximum payload size, regardless of whether EDNS OPT RR is
|
|
|
/// included or not. This means if an application wants to send a message
|
|
|
/// with an EDNS OPT RR for specifying a larger UDP size, it must
|
|
|
/// explicitly specify the value using this method.
|
|
|
+ ///
|
|
|
+ /// This method never throws an exception.
|
|
|
+ ///
|
|
|
+ /// \param udp_size The maximum payload size of UDP messages for the sender
|
|
|
+ /// of the message containing this \c EDNS.
|
|
|
void setUDPSize(const uint16_t udp_size) { udp_size_ = udp_size; }
|
|
|
|
|
|
- /// \brief Return whether the message sender indicates DNSSEC is supported.
|
|
|
+ /// \brief Returns whether the message sender is DNSSEC aware.
|
|
|
///
|
|
|
- /// \return true if the
|
|
|
- bool isDNSSECSupported() const { return (dnssec_ok_); }
|
|
|
+ /// This method never throws an exception.
|
|
|
+ ///
|
|
|
+ /// \return true if DNSSEC is supported; otherwise false.
|
|
|
+ bool getDNSSECAwareness() const { return (dnssec_aware_); }
|
|
|
|
|
|
- /// \brief Specify whether DNSSEC is supported in the message.
|
|
|
- void setDNSSECSupported(const bool on) { dnssec_ok_ = on; }
|
|
|
+ /// \brief Specifies whether the sender of the message containing this
|
|
|
+ /// \c EDNS is DNSSEC aware.
|
|
|
+ ///
|
|
|
+ /// If the parameter is true, a subsequent call to \c toWire() will
|
|
|
+ /// set the DNSSEC DO bit on for the corresponding OPT RR.
|
|
|
+ ///
|
|
|
+ /// This method never throws an exception.
|
|
|
+ ///
|
|
|
+ /// \param is_aware \c true if DNSSEC is supported; \c false otherwise.
|
|
|
+ void setDNSSECAwareness(const bool is_aware) { dnssec_aware_ = is_aware; }
|
|
|
//@}
|
|
|
|
|
|
///
|
|
|
/// \name Converter Methods
|
|
|
///
|
|
|
//@{
|
|
|
- /// \brief
|
|
|
+ /// \brief Render the \c EDNS in the wire format.
|
|
|
+ ///
|
|
|
+ /// This method renders the \c EDNS object as a form of DNS OPT RR
|
|
|
+ /// via \c renderer, which encapsulates output buffer and other rendering
|
|
|
+ /// contexts.
|
|
|
+ /// Since the \c EDNS object does not maintain the extended RCODE
|
|
|
+ /// information, a separate parameter \c extended_rcode must be passed to
|
|
|
+ /// this method.
|
|
|
+ ///
|
|
|
+ /// If by adding the OPT RR the message size would exceed the limit
|
|
|
+ /// maintained in \c renderer, this method skips rendering the RR
|
|
|
+ /// and returns 0; otherwise it returns 1, which is the number of RR
|
|
|
+ /// rendered.
|
|
|
///
|
|
|
/// In the current implementation the return value is either 0 or 1, but
|
|
|
/// the return type is <code>unsigned int</code> to be consistent with
|
|
|
- /// RRset::toWire(). In any case the caller shouldn't assume these are
|
|
|
+ /// \c RRset::toWire(). In any case the caller shouldn't assume these are
|
|
|
/// only possible return values from this method.
|
|
|
+ ///
|
|
|
+ /// This method is mostly exception free, but it requires memory
|
|
|
+ /// allocation and if it fails a corresponding standard exception will be
|
|
|
+ /// thrown.
|
|
|
+ ///
|
|
|
+ /// In practice, top level applications rarely need to use this
|
|
|
+ /// method directly. It should normally suffice to have a higher
|
|
|
+ /// level class such as \c Message do that job.
|
|
|
+ ///
|
|
|
+ /// <b>Note to developer:</b> the current implementation constructs an
|
|
|
+ /// \c RRset object for the OPT RR and calls its \c toWire() method,
|
|
|
+ /// which is inefficient. In future, we may want to optimize this method
|
|
|
+ /// by caching the rendered image and having the application reuse the
|
|
|
+ /// same \c EDNS object when possible.
|
|
|
+ ///
|
|
|
+ /// \param renderer DNS message rendering context that encapsulates the
|
|
|
+ /// output buffer and name compression information.
|
|
|
+ /// \param extended_rcode Upper 8 bits of extended RCODE to be rendered as
|
|
|
+ /// part of the EDNS OPT RR.
|
|
|
+ /// \return 1 if the OPT RR fits in the message size limit; otherwise 0.
|
|
|
unsigned int toWire(MessageRenderer& renderer,
|
|
|
const uint8_t extended_rcode) const;
|
|
|
+
|
|
|
+ /// \brief Render the \c EDNS in the wire format.
|
|
|
+ ///
|
|
|
+ /// This method is same as \c toWire(MessageRenderer&,uint8_t)const
|
|
|
+ /// except it renders the OPT RR in an \c OutputBuffer and therefore
|
|
|
+ /// does not care about message size limit.
|
|
|
+ /// As a consequence it always returns 1.
|
|
|
unsigned int toWire(OutputBuffer& buffer,
|
|
|
const uint8_t extended_rcode) const;
|
|
|
|
|
|
/// \brief Convert the EDNS to a string.
|
|
|
+ ///
|
|
|
+ /// The format of the resulting string is as follows:
|
|
|
+ /// \code ; EDNS: version: <version>, flags: <edns flags>; udp: <udp size>
|
|
|
+ /// \endcode
|
|
|
+ /// where
|
|
|
+ /// - \em version is the EDNS version number (integer).
|
|
|
+ /// - <em>edns flags</em> is a sequence of EDNS flag bits. The only
|
|
|
+ /// possible flag is the "DNSSEC OK", which is represented as "do".
|
|
|
+ /// - <em>udp size</em> is sender's UDP payload size in bytes.
|
|
|
+ ///
|
|
|
+ /// The string will be terminated with a trailing newline character.
|
|
|
+ ///
|
|
|
+ /// When EDNS options are supported the output of this method will be
|
|
|
+ /// extended.
|
|
|
+ ///
|
|
|
+ /// This method is mostly exception free, but it may require memory
|
|
|
+ /// allocation and if it fails a corresponding standard exception will be
|
|
|
+ /// thrown.
|
|
|
+ ///
|
|
|
+ /// \return A string representation of \c EDNS. See above for the format.
|
|
|
std::string toText() const;
|
|
|
//@}
|
|
|
|
|
@@ -220,10 +362,11 @@ public:
|
|
|
/// \brief The highest EDNS version this implementation supports.
|
|
|
static const uint8_t SUPPORTED_VERSION = 0;
|
|
|
private:
|
|
|
- // We may want to use pimpl, especially when we support EDNS options.
|
|
|
+ // We may eventually want to migrate to pimpl, especially when we support
|
|
|
+ // EDNS options. In this initial implementation, we keep it simple.
|
|
|
const uint8_t version_;
|
|
|
uint16_t udp_size_;
|
|
|
- bool dnssec_ok_;
|
|
|
+ bool dnssec_aware_;
|
|
|
};
|
|
|
|
|
|
/// \brief Create a new \c EDNS object from a set of RR parameters, also
|
|
@@ -286,7 +429,16 @@ EDNS* createEDNSFromRR(const Name& name, const RRClass& rrclass,
|
|
|
const RRType& rrtype, const RRTTL& ttl,
|
|
|
const rdata::Rdata& rdata, uint8_t& extended_rcode);
|
|
|
|
|
|
-/// \brief
|
|
|
+/// \brief Insert the \c EDNS as a string into stream.
|
|
|
+///
|
|
|
+/// This method convert \c edns into a string and inserts it into the
|
|
|
+/// output stream \c os.
|
|
|
+///
|
|
|
+/// \param os A \c std::ostream object on which the insertion operation is
|
|
|
+/// performed.
|
|
|
+/// \param edns A reference to an \c EDNS object output by the operation.
|
|
|
+/// \return A reference to the same \c std::ostream object referenced by
|
|
|
+/// parameter \c os after the insertion operation.
|
|
|
std::ostream& operator<<(std::ostream& os, const EDNS& edns);
|
|
|
}
|
|
|
}
|