Kea 2.5.5
rrset.cc
Go to the documentation of this file.
1// Copyright (C) 2010-2021 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
9#include <algorithm>
10#include <string>
11#include <vector>
12
13#include <boost/shared_ptr.hpp>
14#include <boost/foreach.hpp>
15
16#include <util/buffer.h>
17#include <dns/messagerenderer.h>
18#include <dns/name.h>
19#include <dns/rrclass.h>
20#include <dns/rrtype.h>
21#include <dns/rrttl.h>
22#include <dns/rrset.h>
23
24using namespace std;
25using namespace isc::dns;
26using namespace isc::util;
27using namespace isc::dns::rdata;
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 unsigned int
75rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) {
76 unsigned int 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 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
128unsigned int
130 return (rrsetToWire<OutputBuffer>(*this, buffer, 0));
131}
132
133unsigned int
135 const unsigned int 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 unsigned int 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.
181unsigned int
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 unsigned int 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 BOOST_FOREACH(const ConstRdataPtr& rdata, rdatalist_) {
206 const size_t pos0 = renderer.getLength();
207 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{
234 impl_ = new BasicRRsetImpl(name, rrclass, rrtype, ttl);
235}
236
238 delete impl_;
239}
240
241void
243 impl_->rdatalist_.push_back(rdata);
244}
245
246void
249}
250
251void
252BasicRRset::addRdata(const std::string& rdata_str) {
253 addRdata(createRdata(getType(), getClass(), rdata_str));
254}
255
256unsigned int
258 return (impl_->rdatalist_.size());
259}
260
261const Name&
263 return (impl_->name_);
264}
265
266const RRClass&
268 return (impl_->rrclass_);
269}
270
271const RRType&
273 return (impl_->rrtype_);
274}
275
276const RRTTL&
278 return (impl_->ttl_);
279}
280
281void
283 impl_->ttl_ = ttl;
284}
285
286string
288 return (AbstractRRset::toText());
289}
290
291uint16_t
293 uint16_t length = 0;
295
296 if (it->isLast()) {
297 // empty rrsets are only allowed for classes ANY and NONE
298 if (getClass() != RRClass::ANY() &&
299 getClass() != RRClass::NONE()) {
300 isc_throw(EmptyRRset, "getLength() is attempted for an empty RRset");
301 }
302
303 // For an empty RRset, write the name, type, class and TTL once,
304 // followed by empty rdata.
305 length += getName().getLength();
306 length += 2; // TYPE field
307 length += 2; // CLASS field
308 length += 4; // TTL field
309 length += 2; // RDLENGTH field (=0 in wire format)
310
311 return (length);
312 }
313
314 do {
315 // This is a size_t as some of the following additions may
316 // overflow due to a programming mistake somewhere.
317 size_t rrlen = 0;
318
319 rrlen += getName().getLength();
320 rrlen += 2; // TYPE field
321 rrlen += 2; // CLASS field
322 rrlen += 4; // TTL field
323 rrlen += 2; // RDLENGTH field
324 rrlen += it->getCurrent().getLength();
325
326 assert(length + rrlen < 65536);
327 length += rrlen;
328
329 it->next();
330 } while (!it->isLast());
331
332 return (length);
333}
334
335unsigned int
337 return (AbstractRRset::toWire(buffer));
338}
339
340unsigned int
342 const unsigned int rrs_written = impl_->toWire(renderer,
343 renderer.getLengthLimit());
344 if (impl_->rdatalist_.size() > rrs_written) {
345 renderer.setTruncated();
346 }
347 return (rrs_written);
348}
349
350RRset::RRset(const Name& name, const RRClass& rrclass,
351 const RRType& rrtype, const RRTTL& ttl) :
352 BasicRRset(name, rrclass, rrtype, ttl)
353{
354 rrsig_ = RRsetPtr();
355}
356
358
359unsigned int
361 if (rrsig_) {
362 return (rrsig_->getRdataCount());
363 } else {
364 return (0);
365 }
366}
367
368uint16_t
370 uint16_t length = BasicRRset::getLength();
371
372 if (rrsig_) {
373 const uint16_t rrsigs_length = rrsig_->getLength();
374 // the uint16_ts are promoted to ints during addition below, so
375 // it won't overflow a 16-bit register.
376 assert(length + rrsigs_length < 65536);
377 length += rrsigs_length;
378 }
379
380 return (length);
381}
382
383unsigned int
385 unsigned int rrs_written = BasicRRset::toWire(buffer);
386 if (getRdataCount() > rrs_written) {
387 return (rrs_written);
388 }
389
390 if (rrsig_) {
391 rrs_written += rrsig_->toWire(buffer);
392 }
393
394 return (rrs_written);
395}
396
397unsigned int
399 unsigned int rrs_written = BasicRRset::toWire(renderer);
400 if (getRdataCount() > rrs_written) {
401 return (rrs_written);
402 }
403
404 if (rrsig_) {
405 rrs_written += rrsig_->toWire(renderer);
406
407 if (getRdataCount() + getRRsigDataCount() > rrs_written) {
408 renderer.setTruncated();
409 }
410 }
411
412 return (rrs_written);
413}
414
415namespace {
416
417class BasicRdataIterator : public RdataIterator {
418public:
420 BasicRdataIterator(const std::vector<rdata::ConstRdataPtr>& datavector) :
421 datavector_(&datavector), it_(datavector_->begin()) {}
422
424 ~BasicRdataIterator() {}
425
427 virtual void first() {
428 it_ = datavector_->begin();
429 }
430
432 virtual void next() {
433 ++it_;
434 }
435
439 virtual const rdata::Rdata& getCurrent() const {
440 return (**it_);
441 }
442
446 virtual bool isLast() const {
447 return (it_ == datavector_->end());
448 }
449
450private:
452 const std::vector<rdata::ConstRdataPtr>* datavector_;
453
455 std::vector<rdata::ConstRdataPtr>::const_iterator it_;
456};
457
458}
459
462 return (RdataIteratorPtr(new BasicRdataIterator(impl_->rdatalist_)));
463}
464
465}
466}
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:154
virtual unsigned int 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 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 unsigned int getRdataCount() const =0
Returns the number of Rdata objects contained in the RRset.
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
unsigned int toWire(AbstractMessageRenderer &renderer, size_t limit) const
Definition: rrset.cc:182
BasicRRsetImpl(const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl)
Definition: rrset.cc:163
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:629
virtual RdataIteratorPtr getRdataIterator() const
Return an iterator to go through all RDATA stored in the BasicRRset.
Definition: rrset.cc:461
virtual const RRTTL & getTTL() const
Returns the TTL of the RRset.
Definition: rrset.cc:277
virtual unsigned int getRdataCount() const
Returns the number of Rdata objects contained in the RRset.
Definition: rrset.cc:257
virtual void addRdata(rdata::ConstRdataPtr rdata)
Add an RDATA to the RRset (pointer version).
Definition: rrset.cc:242
virtual unsigned int toWire(AbstractMessageRenderer &renderer) const
Render the RRset in the wire format with name compression and truncation handling.
Definition: rrset.cc:341
virtual ~BasicRRset()
The destructor.
Definition: rrset.cc:237
virtual void setTTL(const RRTTL &ttl)
Updates the TTL of the RRset.
Definition: rrset.cc:282
virtual const RRType & getType() const
Returns the RR Type of the RRset.
Definition: rrset.cc:272
virtual uint16_t getLength() const
Get the wire format length of the BasicRRset.
Definition: rrset.cc:292
virtual const RRClass & getClass() const
Returns the RR Class of the RRset.
Definition: rrset.cc:267
virtual const Name & getName() const
Returns the owner name of the RRset.
Definition: rrset.cc:262
virtual std::string toText() const
Convert the RRset to a string.
Definition: rrset.cc:287
A standard DNS module exception that is thrown if an RRset object does not contain any RDATA where re...
Definition: rrset.h:31
The Name class encapsulates DNS names.
Definition: name.h:223
std::string toText(bool omit_final_dot=false) const
Convert the Name to a string.
Definition: name.cc:507
void toWire(AbstractMessageRenderer &renderer) const
Render the Name in the wire format with compression.
Definition: name.cc:502
size_t getLength() const
Gets the length of the Name in its wire format.
Definition: name.h:360
The RRClass class encapsulates DNS resource record classes.
Definition: rrclass.h:98
static const RRClass & ANY()
Definition: rrclass.h:301
static const RRClass & NONE()
Definition: rrclass.h:325
void toWire(AbstractMessageRenderer &renderer) const
Render the RRClass in the wire format.
Definition: rrclass.cc:54
const std::string toText() const
Convert the RRClass to a string.
Definition: rrclass.cc:44
The RRTTL class encapsulates TTLs used in DNS resource records.
Definition: rrttl.h:55
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:106
void toWire(AbstractMessageRenderer &renderer) const
Render the RRType in the wire format.
Definition: rrtype.cc:55
const std::string toText() const
Convert the RRType to a string.
Definition: rrtype.cc:45
virtual ~RRset()
Definition: rrset.cc:357
virtual uint16_t getLength() const
Get the wire format length of the RRset.
Definition: rrset.cc:369
virtual unsigned int toWire(AbstractMessageRenderer &renderer) const
Render the RRset in the wire format with name compression and truncation handling.
Definition: rrset.cc:398
RRset(const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl)
Definition: rrset.cc:350
virtual unsigned int getRRsigDataCount() const
Returns the number of RRSIG records associated with the RRset.
Definition: rrset.cc:360
The RdataIterator class is an abstract base class that provides an interface for accessing RDATA obje...
Definition: rrset.h:558
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
Definition: rdata.h:123
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Rdata > ConstRdataPtr
Definition: rdata.h:72
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:56
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
Definition: rrset.h:53
ostream & operator<<(std::ostream &os, const EDNS &edns)
Insert the EDNS as a string into stream.
Definition: edns.cc:172
boost::shared_ptr< RdataIterator > RdataIteratorPtr
A pointer-like type point to an RdataIterator object.
Definition: rrset.h:63
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.