Kea 2.5.8
rrset.cc
Go to the documentation of this file.
1// Copyright (C) 2010-2024 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#include <config.h>
8
10#include <dns/messagerenderer.h>
11#include <dns/name.h>
12#include <dns/rrclass.h>
13#include <dns/rrtype.h>
14#include <dns/rrttl.h>
15#include <dns/rrset.h>
16#include <util/buffer.h>
17
18#include <algorithm>
19#include <string>
20#include <vector>
21#include <boost/shared_ptr.hpp>
22
23using namespace isc::dns;
24using namespace isc::util;
25using namespace isc::dns::rdata;
26
27using namespace std;
28
29namespace isc {
30namespace dns {
31void
34}
35
36string
38 string s;
40
41 // In the case of an empty rrset, just print name, ttl, class, and
42 // type
43 if (it->isLast()) {
44 // But only for class ANY or NONE
45 if (getClass() != RRClass::ANY() &&
46 getClass() != RRClass::NONE()) {
47 isc_throw(EmptyRRset, "toText() is attempted for an empty RRset");
48 }
49
50 s += getName().toText() + " " + getTTL().toText() + " " +
51 getClass().toText() + " " + getType().toText() + "\n";
52 return (s);
53 }
54
55 do {
56 s += getName().toText() + " " + getTTL().toText() + " " +
57 getClass().toText() + " " + getType().toText() + " " +
58 it->getCurrent().toText() + "\n";
59 it->next();
60 } while (!it->isLast());
61
62 if (getRRsig()) {
63 s += getRRsig()->toText();
64 }
65
66 return (s);
67}
68
69namespace { // unnamed namespace
70
71// FIXME: This method's code should somehow be unified with
72// BasicRRsetImpl::toWire() below to avoid duplication.
73template <typename T>
74inline uint32_t
75rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) {
76 uint32_t n = 0;
78
79 if (it->isLast()) {
80 // empty rrsets are only allowed for classes ANY and NONE
81 if (rrset.getClass() != RRClass::ANY() &&
82 rrset.getClass() != RRClass::NONE()) {
83 isc_throw(EmptyRRset, "toWire() is attempted for an empty RRset");
84 }
85
86 // For an empty RRset, write the name, type, class and TTL once,
87 // followed by empty rdata.
88 rrset.getName().toWire(output);
89 rrset.getType().toWire(output);
90 rrset.getClass().toWire(output);
91 rrset.getTTL().toWire(output);
92 output.writeUint16(0);
93 // Still counts as 1 'rr'; it does show up in the message
94 return (1);
95 }
96
97 // sort the set of Rdata based on rrset-order and sortlist, and possible
98 // other options. Details to be considered.
99 do {
100 const size_t pos0 = output.getLength();
101 isc_throw_assert(pos0 < 65536);
102
103 rrset.getName().toWire(output);
104 rrset.getType().toWire(output);
105 rrset.getClass().toWire(output);
106 rrset.getTTL().toWire(output);
107
108 const size_t pos = output.getLength();
109 output.skip(sizeof(uint16_t)); // leave the space for RDLENGTH
110 it->getCurrent().toWire(output);
111 output.writeUint16At(output.getLength() - pos - sizeof(uint16_t), pos);
112
113 if (limit > 0 && output.getLength() > limit) {
114 // truncation is needed
115 output.trim(output.getLength() - pos0);
116 return (n);
117 }
118
119 it->next();
120 ++n;
121 } while (!it->isLast());
122
123 return (n);
124}
125
126} // end of unnamed namespace
127
128uint32_t
130 return (rrsetToWire<OutputBuffer>(*this, buffer, 0));
131}
132
133uint32_t
135 const uint32_t rrs_written = rrsetToWire<AbstractMessageRenderer>(
136 *this, renderer, renderer.getLengthLimit());
137 if (getRdataCount() > rrs_written) {
138 renderer.setTruncated();
139 }
140 return (rrs_written);
141}
142
143bool
145 // Compare classes last as they're likely to be identical. Compare
146 // names late in the list too, as these are expensive. So we compare
147 // types first, names second and classes last.
148 return (getType() == other.getType() &&
149 getName() == other.getName() &&
150 getClass() == other.getClass());
151}
152
153ostream&
154operator<<(ostream& os, const AbstractRRset& rrset) {
155 os << rrset.toText();
156 return (os);
157}
158
162public:
163 BasicRRsetImpl(const Name& name, const RRClass& rrclass,
164 const RRType& rrtype, const RRTTL& ttl) :
165 name_(name), rrclass_(rrclass), rrtype_(rrtype), ttl_(ttl) {}
166
167 uint32_t toWire(AbstractMessageRenderer& renderer, size_t limit) const;
168
173 // XXX: "list" is not a good name: It in fact isn't a list; more conceptual
174 // name than a data structure name is generally better. But since this
175 // is only used in the internal implementation we'll live with it.
176 vector<ConstRdataPtr> rdatalist_;
177};
178
179// FIXME: This method's code should somehow be unified with
180// rrsetToWire() above to avoid duplication.
181uint32_t
182BasicRRsetImpl::toWire(AbstractMessageRenderer& renderer, size_t limit) const {
183 if (rdatalist_.empty()) {
184 // empty rrsets are only allowed for classes ANY and NONE
185 if (rrclass_ != RRClass::ANY() &&
186 rrclass_ != RRClass::NONE()) {
187 isc_throw(EmptyRRset, "toWire() is attempted for an empty RRset");
188 }
189
190 // For an empty RRset, write the name, type, class and TTL once,
191 // followed by empty rdata.
192 name_.toWire(renderer);
193 rrtype_.toWire(renderer);
194 rrclass_.toWire(renderer);
195 ttl_.toWire(renderer);
196 renderer.writeUint16(0);
197 // Still counts as 1 'rr'; it does show up in the message
198 return (1);
199 }
200
201 uint32_t n = 0;
202
203 // sort the set of Rdata based on rrset-order and sortlist, and possible
204 // other options. Details to be considered.
205 for (auto const& rdata : rdatalist_) {
206 const size_t pos0 = renderer.getLength();
207 isc_throw_assert(pos0 < 65536);
208
209 name_.toWire(renderer);
210 rrtype_.toWire(renderer);
211 rrclass_.toWire(renderer);
212 ttl_.toWire(renderer);
213
214 const size_t pos = renderer.getLength();
215 renderer.skip(sizeof(uint16_t)); // leave the space for RDLENGTH
216 rdata->toWire(renderer);
217 renderer.writeUint16At(renderer.getLength() - pos - sizeof(uint16_t),
218 pos);
219
220 if (limit > 0 && renderer.getLength() > limit) {
221 // truncation is needed
222 renderer.trim(renderer.getLength() - pos0);
223 return (n);
224 }
225 ++n;
226 }
227
228 return (n);
229}
230
231BasicRRset::BasicRRset(const Name& name, const RRClass& rrclass,
232 const RRType& rrtype, const RRTTL& ttl) {
233 impl_.reset(new BasicRRsetImpl(name, rrclass, rrtype, ttl));
234}
235
237}
238
239void
241 impl_->rdatalist_.push_back(rdata);
242}
243
244void
247}
248
249void
250BasicRRset::addRdata(const std::string& rdata_str) {
251 addRdata(createRdata(getType(), getClass(), rdata_str));
252}
253
254uint32_t
256 return (impl_->rdatalist_.size());
257}
258
259const Name&
261 return (impl_->name_);
262}
263
264const RRClass&
266 return (impl_->rrclass_);
267}
268
269const RRType&
271 return (impl_->rrtype_);
272}
273
274const RRTTL&
276 return (impl_->ttl_);
277}
278
279void
281 impl_->ttl_ = ttl;
282}
283
284string
286 return (AbstractRRset::toText());
287}
288
289uint16_t
291 uint16_t length = 0;
293
294 if (it->isLast()) {
295 // empty rrsets are only allowed for classes ANY and NONE
296 if (getClass() != RRClass::ANY() &&
297 getClass() != RRClass::NONE()) {
298 isc_throw(EmptyRRset, "getLength() is attempted for an empty RRset");
299 }
300
301 // For an empty RRset, write the name, type, class and TTL once,
302 // followed by empty rdata.
303 length += getName().getLength();
304 length += 2; // TYPE field
305 length += 2; // CLASS field
306 length += 4; // TTL field
307 length += 2; // RDLENGTH field (=0 in wire format)
308
309 return (length);
310 }
311
312 do {
313 // This is a size_t as some of the following additions may
314 // overflow due to a programming mistake somewhere.
315 size_t rrlen = 0;
316
317 rrlen += getName().getLength();
318 rrlen += 2; // TYPE field
319 rrlen += 2; // CLASS field
320 rrlen += 4; // TTL field
321 rrlen += 2; // RDLENGTH field
322 rrlen += it->getCurrent().getLength();
323
324 isc_throw_assert(length + rrlen < 65536);
325 length += rrlen;
326
327 it->next();
328 } while (!it->isLast());
329
330 return (length);
331}
332
333uint32_t
335 return (AbstractRRset::toWire(buffer));
336}
337
338uint32_t
340 const uint32_t rrs_written = impl_->toWire(renderer,
341 renderer.getLengthLimit());
342 if (impl_->rdatalist_.size() > rrs_written) {
343 renderer.setTruncated();
344 }
345 return (rrs_written);
346}
347
348RRset::RRset(const Name& name, const RRClass& rrclass,
349 const RRType& rrtype, const RRTTL& ttl) :
350 BasicRRset(name, rrclass, rrtype, ttl) {
351}
352
354}
355
356uint32_t
358 if (rrsig_) {
359 return (rrsig_->getRdataCount());
360 } else {
361 return (0);
362 }
363}
364
365uint16_t
367 uint16_t length = BasicRRset::getLength();
368
369 if (rrsig_) {
370 const uint16_t rrsigs_length = rrsig_->getLength();
371 // the uint16_ts are promoted to ints during addition below, so
372 // it won't overflow a 16-bit register.
373 isc_throw_assert(length + rrsigs_length < 65536);
374 length += rrsigs_length;
375 }
376
377 return (length);
378}
379
380uint32_t
382 uint32_t rrs_written = BasicRRset::toWire(buffer);
383 if (getRdataCount() > rrs_written) {
384 return (rrs_written);
385 }
386
387 if (rrsig_) {
388 rrs_written += rrsig_->toWire(buffer);
389 }
390
391 return (rrs_written);
392}
393
394uint32_t
396 uint32_t rrs_written = BasicRRset::toWire(renderer);
397 if (getRdataCount() > rrs_written) {
398 return (rrs_written);
399 }
400
401 if (rrsig_) {
402 rrs_written += rrsig_->toWire(renderer);
403
404 if (getRdataCount() + getRRsigDataCount() > rrs_written) {
405 renderer.setTruncated();
406 }
407 }
408
409 return (rrs_written);
410}
411
412namespace {
413
414class BasicRdataIterator : public RdataIterator {
415public:
417 BasicRdataIterator(const std::vector<rdata::ConstRdataPtr>& datavector) :
418 datavector_(&datavector), it_(datavector_->begin()) {
419 }
420
422 ~BasicRdataIterator() {
423 }
424
426 virtual void first() {
427 it_ = datavector_->begin();
428 }
429
431 virtual void next() {
432 ++it_;
433 }
434
438 virtual const rdata::Rdata& getCurrent() const {
439 return (**it_);
440 }
441
445 virtual bool isLast() const {
446 return (it_ == datavector_->end());
447 }
448
449private:
451 const std::vector<rdata::ConstRdataPtr>* datavector_;
452
454 std::vector<rdata::ConstRdataPtr>::const_iterator it_;
455};
456
457}
458
461 return (RdataIteratorPtr(new BasicRdataIterator(impl_->rdatalist_)));
462}
463
464}
465}
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
virtual void setTruncated()=0
Mark the renderer to indicate truncation has occurred while rendering.
void trim(size_t len)
Trim the specified length of data from the end of the internal buffer.
size_t getLength() const
Return the length of data written in the internal buffer.
virtual size_t getLengthLimit() const =0
Return the maximum length of rendered data that can fit in the corresponding DNS message without trun...
void skip(size_t len)
Insert a specified length of gap at the end of the buffer.
void writeUint16At(uint16_t data, size_t pos)
Write an unsigned 16-bit integer in host byte order at the specified position of the internal buffer ...
void writeUint16(uint16_t data)
Write an unsigned 16-bit integer in host byte order into the internal buffer in network byte order.
The AbstractRRset class is an abstract base class that models a DNS RRset.
Definition: rrset.h:151
virtual uint32_t toWire(AbstractMessageRenderer &renderer) const =0
Render the RRset in the wire format with name compression and truncation handling.
Definition: rrset.cc:134
virtual const RRType & getType() const =0
Returns the RR Type of the RRset.
virtual uint32_t getRdataCount() const =0
Returns the number of Rdata objects contained in the RRset.
virtual std::string toText() const =0
Convert the RRset to a string.
Definition: rrset.cc:37
virtual bool isSameKind(const AbstractRRset &other) const
Check whether two RRsets are of the same kind.
Definition: rrset.cc:144
virtual RRsetPtr getRRsig() const =0
Return pointer to this RRset's RRSIG RRset.
virtual const Name & getName() const =0
Returns the owner name of the RRset.
virtual const RRTTL & getTTL() const =0
Returns the TTL of the RRset.
virtual RdataIteratorPtr getRdataIterator() const =0
Return an iterator to go through all RDATA stored in the RRset.
virtual void addRdata(rdata::ConstRdataPtr rdata)=0
Add an RDATA to the RRset (pointer version).
virtual const RRClass & getClass() const =0
Returns the RR Class of the RRset.
This encapsulates the actual implementation of the BasicRRset class.
Definition: rrset.cc:161
BasicRRsetImpl(const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl)
Definition: rrset.cc:163
uint32_t toWire(AbstractMessageRenderer &renderer, size_t limit) const
Definition: rrset.cc:182
vector< ConstRdataPtr > rdatalist_
Definition: rrset.cc:176
The BasicRRset class is a concrete derived class of AbstractRRset that defines a straightforward RRse...
Definition: rrset.h:626
virtual RdataIteratorPtr getRdataIterator() const
Return an iterator to go through all RDATA stored in the BasicRRset.
Definition: rrset.cc:460
virtual const RRTTL & getTTL() const
Returns the TTL of the RRset.
Definition: rrset.cc:275
virtual void addRdata(rdata::ConstRdataPtr rdata)
Add an RDATA to the RRset (pointer version).
Definition: rrset.cc:240
virtual uint32_t getRdataCount() const
Returns the number of Rdata objects contained in the RRset.
Definition: rrset.cc:255
virtual ~BasicRRset()
The destructor.
Definition: rrset.cc:236
virtual void setTTL(const RRTTL &ttl)
Updates the TTL of the RRset.
Definition: rrset.cc:280
virtual const RRType & getType() const
Returns the RR Type of the RRset.
Definition: rrset.cc:270
virtual uint16_t getLength() const
Get the wire format length of the BasicRRset.
Definition: rrset.cc:290
virtual const RRClass & getClass() const
Returns the RR Class of the RRset.
Definition: rrset.cc:265
virtual const Name & getName() const
Returns the owner name of the RRset.
Definition: rrset.cc:260
virtual uint32_t toWire(AbstractMessageRenderer &renderer) const
Render the RRset in the wire format with name compression and truncation handling.
Definition: rrset.cc:339
virtual std::string toText() const
Convert the RRset to a string.
Definition: rrset.cc:285
A standard DNS module exception that is thrown if an RRset object does not contain any RDATA where re...
Definition: rrset.h:28
The Name class encapsulates DNS names.
Definition: name.h:219
std::string toText(bool omit_final_dot=false) const
Convert the Name to a string.
Definition: name.cc:503
void toWire(AbstractMessageRenderer &renderer) const
Render the Name in the wire format with compression.
Definition: name.cc:498
size_t getLength() const
Gets the length of the Name in its wire format.
Definition: name.h:356
The RRClass class encapsulates DNS resource record classes.
Definition: rrclass.h:89
static const RRClass & ANY()
Definition: rrclass.h:298
static const RRClass & NONE()
Definition: rrclass.h:316
void toWire(AbstractMessageRenderer &renderer) const
Render the RRClass in the wire format.
Definition: rrclass.cc:53
const std::string toText() const
Convert the RRClass to a string.
Definition: rrclass.cc:43
The RRTTL class encapsulates TTLs used in DNS resource records.
Definition: rrttl.h:51
void toWire(AbstractMessageRenderer &renderer) const
Render the RRTTL in the wire format.
Definition: rrttl.cc:204
const std::string toText() const
Convert the RRTTL to a string.
Definition: rrttl.cc:192
The RRType class encapsulates DNS resource record types.
Definition: rrtype.h:96
void toWire(AbstractMessageRenderer &renderer) const
Render the RRType in the wire format.
Definition: rrtype.cc:54
const std::string toText() const
Convert the RRType to a string.
Definition: rrtype.cc:44
virtual ~RRset()
Definition: rrset.cc:353
virtual uint16_t getLength() const
Get the wire format length of the RRset.
Definition: rrset.cc:366
RRset(const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl)
Definition: rrset.cc:348
virtual uint32_t toWire(AbstractMessageRenderer &renderer) const
Render the RRset in the wire format with name compression and truncation handling.
Definition: rrset.cc:395
virtual uint32_t getRRsigDataCount() const
Returns the number of RRSIG records associated with the RRset.
Definition: rrset.cc:357
The RdataIterator class is an abstract base class that provides an interface for accessing RDATA obje...
Definition: rrset.h:555
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
Definition: rdata.h:120
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:347
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition: isc_assert.h:18
boost::shared_ptr< const Rdata > ConstRdataPtr
Definition: rdata.h:69
RdataPtr createRdata(const RRType &rrtype, const RRClass &rrclass, const std::string &rdata_string)
Create RDATA of a given pair of RR type and class from a string.
Definition: rdata.cc:54
ostream & operator<<(std::ostream &os, const EDNS &edns)
Insert the EDNS as a string into stream.
Definition: edns.cc:163
boost::shared_ptr< RdataIterator > RdataIteratorPtr
A pointer-like type point to an RdataIterator object.
Definition: rrset.h:60
Defines the logger used by the top-level component of kea-lfc.