Kea 2.5.8
isc::dns::TSIGRecord Class Reference

TSIG resource record. More...

#include <tsigrecord.h>

Public Member Functions

Constructors

We use the default copy constructor, default copy assignment operator, (and default destructor) intentionally.

 TSIGRecord (const Name &key_name, const rdata::any::TSIG &tsig_rdata)
 Constructor from TSIG key name and RDATA.
 
 TSIGRecord (const Name &name, const RRClass &rrclass, const RRTTL &ttl, const rdata::Rdata &rdata, size_t length)
 Constructor from resource record (RR) parameters.
 
const NamegetName () const
 Return the owner name of the TSIG RR, which is the TSIG key name.
 
const rdata::any::TSIGgetRdata () const
 Return the RDATA of the TSIG RR.
 

Protocol constants and defaults

static const uint32_t TSIG_TTL = 0
 The TTL value to be used in TSIG RRs.
 
size_t getLength () const
 Return the length of the TSIG record.
 
uint32_t toWire (AbstractMessageRenderer &renderer) const
 Render the TSIG RR in the wire format.
 
uint32_t toWire (isc::util::OutputBuffer &buffer) const
 Render the TSIG RR in the wire format.
 
std::string toText () const
 Convert the TSIG record to a string.
 
static const RRClassgetClass ()
 Return the RR class of TSIG.
 
static const RRTTLgetTTL ()
 Return the TTL value of TSIG.
 

Detailed Description

TSIG resource record.

A TSIGRecord class object represents a TSIG resource record and is responsible for conversion to and from wire format TSIG record based on the protocol specification (RFC2845). This class is provided so that other classes and applications can handle TSIG without knowing protocol details of TSIG, such as that it uses a fixed constant of TTL.

Todo:
So the plan is to eventually provide the "from wire" constructor. It's not yet provided in the current phase of development.
Note
This class could be a derived class of AbstractRRset. That way it would be able to be used in a polymorphic way; for example, an application can construct a TSIG RR by itself and insert it to a Message object as a generic RRset. On the other hand, it would mean this class would have to implement an RdataIterator (even though it can be done via straightforward forwarding) while the iterator is mostly redundant since there should be one and only one RDATA for a valid TSIG RR. Likewise, some methods such as setTTL() method wouldn't be well defined due to such special rules for TSIG as using a fixed TTL. Overall, TSIG is a very special RR type that simply uses the compatible resource record format, and it will be unlikely that a user wants to handle it through a generic interface in a polymorphic way. We therefore chose to define it as a separate class. This is also similar to why EDNS is a separate class.

Definition at line 51 of file tsigrecord.h.

Constructor & Destructor Documentation

◆ TSIGRecord() [1/2]

isc::dns::TSIGRecord::TSIGRecord ( const Name key_name,
const rdata::any::TSIG tsig_rdata 
)

Constructor from TSIG key name and RDATA.

Exceptions
std::bad_allocResource allocation for copying the name or RDATA fails

Definition at line 40 of file tsigrecord.cc.

◆ TSIGRecord() [2/2]

isc::dns::TSIGRecord::TSIGRecord ( const Name name,
const RRClass rrclass,
const RRTTL ttl,
const rdata::Rdata rdata,
size_t  length 
)

Constructor from resource record (RR) parameters.

This constructor is intended to be used in the context of parsing an incoming DNS message that contains a TSIG. The parser would first extract the owner name, RR type (which is TSIG) class, TTL and the TSIG RDATA from the message. This constructor is expected to be given these RR parameters (except the RR type, because it must be TSIG).

According to RFC2845, a TSIG RR uses fixed RR class (ANY) and TTL (0). If the RR class or TTL is different from the expected one, this implementation considers it an invalid record and throws an exception of class DNSMessageFORMERR.

Note
This behavior is not specified in the protocol specification, but this implementation rejects unexpected values for the following reasons (but in any case, this won't matter much in practice as RFC2848 clearly states these fields always have the fixed values and any sane implementation of TSIG signer will follow that): According to the RFC editor (in a private communication), the intended use of the TSIG TTL field is to signal protocol extensions (currently no such extension is defined), so this field may actually be validly non 0 in future. However, until the implementation supports that extension it may not always be able to handle the extended TSIG as intended; the extension may even affect digest computation. There's a related issue on this point. Different implementations interpret the RFC in different ways on the received TTL when digesting the message: BIND 9 uses the received value (even if it's not 0) as part of the TSIG variables; NLnet Labs' LDNS and NSD always use a fixed constant of 0 regardless of the received TTL value. This means if and when an extension with non 0 TTL is introduced there will be interoperability problems in the form of verification failure. By explicitly rejecting it (and subsequently returning a response with a format error) we can indicate the source of the problem more clearly than a "bad signature" TSIG error, which can happen for various reasons. On the other hand, rejecting unexpected RR classes is mostly for consistency; the RFC lists these two fields in the same way, so it makes more sense to handle them equally. (BIND 9 rejects unexpected RR classes for TSIG, but that is part of general check on RR classes on received RRs; it generally requests all classes are the same, and if the protocol specifies the use of a particular class for a particular type of RR, it requests that class be used).

Likewise, if rdata is not of type any::TSIG, an exception of class DNSMessageFORMERR will be thrown. When the caller is a DNS message parser and builds rdata from incoming wire format data as described above, this case happens when the RR class is different from ANY (in the implementation, the type check takes place before the explicit check against the RR class explained in the previous paragraph).

The length parameter is intended to be the length of the TSIG RR (from the beginning of the owner name to the end of the RDATA) when the caller is a DNS message parser. Note that it is the actual length for the RR in the format; if the owner name or the algorithm name (in the RDATA) is compressed (although the latter should not be compressed according to RFC3597), the length must be the size of the compressed data. The length is recorded inside the class and will be returned via subsequent calls to getLength(). It's intended to be used in the context TSIG verification; in the verify process the MAC computation must be performed for the original data without TSIG, so, to avoid parsing the entire data in the verify process again, it's necessary to record information that can identify the length to be digested for the MAC. This parameter serves for that purpose.

Note
Since the constructor doesn't take the wire format data per se, it doesn't (and cannot) check the validity of length, and simply accepts any given value. It even accepts obviously invalid values such as 0. It's caller's responsibility to provide a valid value of length, and, the verifier's responsibility to use the length safely.

DISCUSSION: this design is fragile in that it introduces a tight coupling between message parsing and TSIG verification via the TSIGRecord class. In terms of responsibility decoupling, the ideal way to have TSIGRecord remember the entire wire data along with the length of the TSIG. Then in the TSIG verification we could refer to the necessary potion of data solely from a TSIGRecord object. However, this approach would require expensive heavy copy of the original data or introduce another kind of coupling between the data holder and this class (if the original data is freed while a TSIGRecord object referencing the data still exists, the result will be catastrophic). As a "best current compromise", we use the current design. We may reconsider it if it turns out to cause a big problem or we come up with a better idea.

Exceptions
DNSMessageFORMERRGiven RR parameters are invalid for TSIG.
std::bad_allocInternal resource allocation fails.
Parameters
nameThe owner name of the TSIG RR
rrclassThe RR class of the RR. Must be RRClass::ANY() (see above)
ttlThe TTL of the RR. Must be 0 (see above)
rdataThe RDATA of the RR. Must be of type any::TSIG.
lengthThe size of the RR (see above)

Definition at line 66 of file tsigrecord.cc.

References getClass(), isc_throw, and TSIG_TTL.

+ Here is the call graph for this function:

Member Function Documentation

◆ getClass()

const RRClass & isc::dns::TSIGRecord::getClass ( )
static

Return the RR class of TSIG.

TSIG always uses the ANY RR class. This static method returns it, when, though unlikely, an application wants to know which class TSIG is supposed to use.

Exceptions
None

Definition at line 79 of file tsigrecord.cc.

References isc::dns::RRClass::ANY().

Referenced by TSIGRecord(), isc::dns::TSIGContext::sign(), toText(), and isc::dns::TSIGContext::verify().

+ Here is the call graph for this function:

◆ getLength()

size_t isc::dns::TSIGRecord::getLength ( ) const
inline

Return the length of the TSIG record.

When constructed from the key name and RDATA, it is the length of the record when it is rendered by the toWire() method.

Note
When constructed "from wire", that will mean the length of the wire format data for the TSIG RR. The length will be necessary to verify the message once parse is completed.
Exceptions
None

Definition at line 211 of file tsigrecord.h.

Referenced by isc::dns::TSIGContext::verify().

◆ getName()

const Name & isc::dns::TSIGRecord::getName ( ) const
inline

Return the owner name of the TSIG RR, which is the TSIG key name.

Exceptions
None

Definition at line 168 of file tsigrecord.h.

Referenced by isc::dns::TSIGContext::verify().

◆ getRdata()

const rdata::any::TSIG & isc::dns::TSIGRecord::getRdata ( ) const
inline

Return the RDATA of the TSIG RR.

Exceptions
None

Definition at line 175 of file tsigrecord.h.

Referenced by isc::dns::TSIGContext::verify().

◆ getTTL()

const RRTTL & isc::dns::TSIGRecord::getTTL ( )
static

Return the TTL value of TSIG.

TSIG always uses 0 TTL. This static method returns it, when, though unlikely, an application wants to know the TTL TSIG is supposed to use.

Exceptions
None

Definition at line 84 of file tsigrecord.cc.

References TSIG_TTL.

◆ toText()

std::string isc::dns::TSIGRecord::toText ( ) const

Convert the TSIG record to a string.

The output format is the same as the result of toText() for other normal types of RRsets (with always using the same RR class and TTL). It also ends with a newline.

Exceptions
std::bad_allocInternal resource allocation fails (this should be rare).
Returns
A string representation of TSIG record

Definition at line 129 of file tsigrecord.cc.

References getClass(), isc::dns::rdata::any::TSIG::toText(), toText(), isc::dns::Name::toText(), isc::dns::RRType::TSIG(), and TSIG_TTL.

Referenced by isc::dns::operator<<(), and toText().

+ Here is the call graph for this function:

◆ toWire() [1/2]

uint32_t isc::dns::TSIGRecord::toWire ( AbstractMessageRenderer renderer) const

Render the TSIG RR in the wire format.

This method renders the TSIG record as a form of a DNS TSIG RR via renderer, which encapsulates output buffer and other rendering contexts.

Normally this version of toWire() method tries to compress the owner name of the RR whenever possible, but this method intentionally skips owner name compression. This is due to a report that some Windows clients refuse a TSIG if its owner name is compressed (See http://marc.info/?l=bind-workers&m=126637138430819&w=2). Reportedly this seemed to be specific to GSS-TSIG, but this implementation skip compression regardless of the algorithm.

If by adding the TSIG RR the message size would exceed the limit maintained in renderer, this method skips rendering the RR and returns 0 and mark renderer as "truncated" (so that a subsequent call to isTruncated() on renderer will result in true); otherwise it returns 1, which is the number of RR rendered.

Note
If the caller follows the specification of adding TSIG as described in RFC2845, this should not happen; the caller is generally expected to leave a sufficient room in the message for the TSIG. But this method checks the unexpected case nevertheless.
Exceptions
std::bad_allocInternal resource allocation fails (this should be rare).
Parameters
rendererDNS message rendering context that encapsulates the output buffer and name compression information.
Returns
1 if the TSIG RR fits in the message size limit; otherwise 0.

Definition at line 108 of file tsigrecord.cc.

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

+ Here is the call graph for this function:

◆ toWire() [2/2]

uint32_t isc::dns::TSIGRecord::toWire ( isc::util::OutputBuffer buffer) const

Render the TSIG RR in the wire format.

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

Definition at line 122 of file tsigrecord.cc.

References isc::dns::Name::toWire().

+ Here is the call graph for this function:

Member Data Documentation

◆ TSIG_TTL

const uint32_t isc::dns::TSIGRecord::TSIG_TTL = 0
static

The TTL value to be used in TSIG RRs.

Definition at line 270 of file tsigrecord.h.

Referenced by TSIGRecord(), getTTL(), isc::dns::TSIGContext::sign(), toText(), and isc::dns::TSIGContext::verify().


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