| Kea 3.0.2-git

isc::dns::EDNS Class Reference

The `EDNS` class represents the EDNS OPT RR defined in RFC2671. More...

`#include <edns.h>`

## Public Member Functions
Constructors and Destructor
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.
| EDNS (const uint8_t version=SUPPORTED_VERSION)
| Constructor with the EDNS version.
| EDNS (const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, const rdata::Rdata &rdata)
| Constructor from resource record (RR) parameters.
Getter and Setter Methods
uint8_t | getVersion () const
| Returns the version of EDNS.
uint16_t | getUDPSize () const
| Returns the maximum payload size of UDP messages for the sender of the message containing this `EDNS`.
void | setUDPSize (const uint16_t udp_size)
| Specify the maximum payload size of UDP messages that use this EDNS.
bool | getDNSSECAwareness () const
| Returns whether the message sender is DNSSEC aware.
void | setDNSSECAwareness (const bool is_aware)
| Specifies whether the sender of the message containing this `EDNS` is DNSSEC aware.

## Converter Methods
static const uint8_t | SUPPORTED_VERSION = 0
| The highest EDNS version this implementation supports.
uint32_t | toWire (AbstractMessageRenderer &renderer, const uint8_t extended_rcode) const
| Render the `EDNS` in the wire format.
uint32_t | toWire (isc::util::OutputBuffer &buffer, const uint8_t extended_rcode) const
| Render the `EDNS` in the wire format.
std::string | toText () const
| Convert the EDNS to a string.

## Detailed Description

The `EDNS` class represents the EDNS OPT RR defined in RFC2671.

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 `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 `Message` class).

When converting wire-format OPT RR into an `EDNS` object, it normalizes the information, i.e., unknown flags will be ignored on construction.

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.

Notes to developers

The rest of the description is for developers who need to or want to understand the design of this API.

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 `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:

message->setUDPSize(4096);

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:

message->setUDPSize(512);

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:

edns->setUDPSize(4096);

while we can explicitly specify whether to include an OPT RR by setting (or not setting) an `EDNS` object in a message:

message->setEDNS(edns); // unless we do this OPT RR is skipped

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 `EDNS` class. But it would not be desirable to maintain the extended RCODEs completely in the `Message` class, either, because we wanted to hide the mapping between EDNS semantics and its wire format representation within the `EDNS` class; if we moved the responsibility about RCODEs to the `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.

Definition at line 121 of file edns.h.

## Constructor & Destructor Documentation

## ◆ EDNS() [1/2]

isc::dns::EDNS::EDNS | ( | const uint8_t | version = SUPPORTED_VERSION | ) |
| explicit

Constructor with the EDNS version.

An application would use this constructor to specify EDNS parameters and/or options for outgoing DNS messages.

All other parameters than the version number will be initialized to reasonable defaults. Specifically, the UDP payload size is set to `Message::DEFAULT_MAX_UDPSIZE`, and DNSSEC is assumed to be not supported. These parameters can be altered via setter methods of this class. Note, however, that the version number cannot be changed once constructed.

The version number parameter can be omitted, in which case the highest supported version in this implementation will be assumed. When specified, if it is larger than the highest supported version, an exception of class `isc::InvalidParameter` will be thrown.

This constructor throws no other exception.

Parameters

  version | The version number of the EDNS to be constructed.

Definition at line 52 of file edns.cc.

References isc_throw, SUPPORTED_VERSION, and version().

Here is the call graph for this function:

## ◆ EDNS() [2/2]

isc::dns::EDNS::EDNS | ( | const Name & | name,
|  | const RRClass & | rrclass,
|  | const RRType & | rrtype,
|  | const RRTTL & | ttl,
|  | const rdata::Rdata & | rdata )

Constructor from resource record (RR) parameters.

This constructor is intended to be used to construct an EDNS object from an OPT RR contained in an incoming DNS message.

Unlike many other constructors for this purpose, this constructor does not take the bare wire-format data in the form of an `InputBuffer` object. This is because parsing incoming EDNS is highly context dependent and it's not feasible to handle it in a completely polymorphic way. For example, a DNS message parser would have to check an OPT RR appears at most once in the message, and if it appears it should be in the additional section. So, the parser needs to have an explicit check to see if an RR is of type OPT, and then (if other conditions are met) construct a corresponding `EDNS` object. At that point the parser would have already converted the wire data into corresponding objects of `Name`, `RRClass`, `RRType`, etc, and it makes more sense to pass them directly to the constructor.

In practice, top level applications rarely need to use this constructor directly. It should normally suffice to have a higher level class such as `Message` do that job.

This constructor checks the passed parameters to see if they are valid in terms of the EDNS protocol specification. `name` must be the root name ("."); otherwise, an exception of class `DNSMessageFORMERR` will be thrown. `rrtype` must specify the OPT RR type; otherwise, an exception of class `isc::InvalidParameter` will be thrown. The ENDS version number is extracted from `rrttl`. If it is larger than the higher supported version, an exception of class `DNSMessageBADVERS` will be thrown. Note that this is different from the case of the same error in the other constructor. This is intentional, so that the application can transparently convert the exception to a response RCODE according to the protocol specification.

This initial implementation does not support EDNS options at all, and `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 `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 the corresponding `RRType` object at the time of call to this constructor, so the overhead of having the additional parameter should be marginal.

Parameters

  name | The owner name of the OPT RR. This must be the root name.
  rrclass | The RR class of the OPT RR.
  rrtype | This must specify the OPT RR type.
  ttl | The TTL of the OPT RR.
  rdata | The RDATA of the OPT RR.

Definition at line 63 of file edns.cc.

References isc::dns::RRClass::getCode(), isc::dns::RRTTL::getValue(), isc_throw, isc::dns::RRType::OPT(), isc::dns::Name::ROOT_NAME(), and SUPPORTED_VERSION.

Here is the call graph for this function:

## Member Function Documentation

## ◆ getDNSSECAwareness()

bool isc::dns::EDNS::getDNSSECAwareness | ( |  | ) | const
| inline

Returns whether the message sender is DNSSEC aware.

This method never throws an exception.

Returns
  true if DNSSEC is supported; otherwise false.

Definition at line 251 of file edns.h.

Referenced by toText().

## ◆ getUDPSize()

uint16_t isc::dns::EDNS::getUDPSize | ( |  | ) | const
| inline

Returns the maximum payload size of UDP messages for the sender of the message containing this `EDNS`.

This method never throws an exception.

Definition at line 229 of file edns.h.

Referenced by toText().

## ◆ getVersion()

uint8_t isc::dns::EDNS::getVersion | ( |  | ) | const
| inline

Returns the version of EDNS.

This method never throws an exception.

Definition at line 223 of file edns.h.

Referenced by toText().

## ◆ setDNSSECAwareness()

void isc::dns::EDNS::setDNSSECAwareness | ( | const bool | is_aware | ) |
| inline

Specifies whether the sender of the message containing this `EDNS` is DNSSEC aware.

If the parameter is true, a subsequent call to `toWire()` will set the DNSSEC DO bit on for the corresponding OPT RR.

This method never throws an exception.

Parameters

  is_aware | `true` if DNSSEC is supported; `false` otherwise.

Definition at line 262 of file edns.h.

## ◆ setUDPSize()

void isc::dns::EDNS::setUDPSize | ( | const uint16_t | udp_size | ) |
| inline

Specify the maximum payload size of UDP messages that use this EDNS.

Unless explicitly specified, `DEFAULT_MAX_UDPSIZE` will be assumed 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.

Parameters

  udp_size | The maximum payload size of UDP messages for the sender of the message containing this `EDNS`.

Definition at line 244 of file edns.h.

## ◆ toText()

string isc::dns::EDNS::toText | ( |  | ) | const

Convert the EDNS to a string.

The format of the resulting string is as follows:

; EDNS: version: <version>, flags: <edns flags>; udp: <udp size>
isc::dns::EDNS::EDNS
EDNS(const uint8_t version=SUPPORTED_VERSION)
Constructor with the EDNS version.
Definition edns.cc:52
version
int version()
returns Kea hooks version.
Definition d2/gss_tsig/version.cc:13

where

- version is the EDNS version number (integer).
- edns flags is a sequence of EDNS flag bits. The only possible flag is the "DNSSEC OK", which is represented as "do".
- udp size 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.

Returns
  A string representation of `EDNS`. See above for the format.

Definition at line 87 of file edns.cc.

References getDNSSECAwareness(), getUDPSize(), and getVersion().

Referenced by isc::dns::operator<<().

Here is the call graph for this function:

## ◆ toWire() [1/2]

uint32_t isc::dns::EDNS::toWire | ( | AbstractMessageRenderer & | renderer,
|  | const uint8_t | extended_rcode ) const

Render the `EDNS` in the wire format.

This method renders the `EDNS` object as a form of DNS OPT RR via `renderer`, which encapsulates output buffer and other rendering contexts. Since the `EDNS` object does not maintain the extended RCODE information, a separate parameter `extended_rcode` must be passed to this method.

If by adding the OPT RR the message size would exceed the limit maintained in `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 `unsigned int` to be consistent with `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 `Message` do that job.

Note to developer: the current implementation constructs an `RRset` object for the OPT RR and calls its `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 `EDNS` object when possible.

Parameters

  renderer | DNS message rendering context that encapsulates the output buffer and name compression information.
  extended_rcode | Upper 8 bits of extended RCODE to be rendered as part of the EDNS OPT RR.

Returns
  1 if the OPT RR fits in the message size limit; otherwise 0.

Definition at line 128 of file edns.cc.

References isc::dns::AbstractMessageRenderer::getLength(), and isc::dns::AbstractMessageRenderer::getLengthLimit().

Here is the call graph for this function:

## ◆ toWire() [2/2]

uint32_t isc::dns::EDNS::toWire | ( | isc::util::OutputBuffer & | buffer,
|  | const uint8_t | extended_rcode ) const

Render the `EDNS` in the wire format.

This method is same as `toWire(MessageRenderer&,uint8_t)const` except it renders the OPT RR in an `OutputBuffer` and therefore does not care about message size limit. As a consequence it always returns 1.

Definition at line 142 of file edns.cc.

## Member Data Documentation

## ◆ SUPPORTED_VERSION

const uint8_t isc::dns::EDNS::SUPPORTED_VERSION = 0
| static

The highest EDNS version this implementation supports.

Definition at line 349 of file edns.h.

Referenced by EDNS(), and EDNS().

The documentation for this class was generated from the following files:

- edns.h
- edns.cc