Kea  1.9.9-git
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 
24 using namespace std;
25 using namespace isc::dns;
26 using namespace isc::util;
27 using namespace isc::dns::rdata;
28 
29 namespace isc {
30 namespace dns {
31 void
32 AbstractRRset::addRdata(const Rdata& rdata) {
33  addRdata(createRdata(getType(), getClass(), rdata));
34 }
35 
36 string
37 AbstractRRset::toText() const {
38  string s;
39  RdataIteratorPtr it = getRdataIterator();
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 
69 namespace { // unnamed namespace
70 
71 // FIXME: This method's code should somehow be unified with
72 // BasicRRsetImpl::toWire() below to avoid duplication.
73 template <typename T>
74 inline unsigned int
75 rrsetToWire(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 
128 unsigned int
129 AbstractRRset::toWire(OutputBuffer& buffer) const {
130  return (rrsetToWire<OutputBuffer>(*this, buffer, 0));
131 }
132 
133 unsigned int
134 AbstractRRset::toWire(AbstractMessageRenderer& renderer) const {
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 
143 bool
144 AbstractRRset::isSameKind(const AbstractRRset& other) const {
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 
153 ostream&
154 operator<<(ostream& os, const AbstractRRset& rrset) {
155  os << rrset.toText();
156  return (os);
157 }
158 
162 public:
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.
181 unsigned int
182 BasicRRsetImpl::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 
231 BasicRRset::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 
237 BasicRRset::~BasicRRset() {
238  delete impl_;
239 }
240 
241 void
242 BasicRRset::addRdata(ConstRdataPtr rdata) {
243  impl_->rdatalist_.push_back(rdata);
244 }
245 
246 void
247 BasicRRset::addRdata(const Rdata& rdata) {
248  AbstractRRset::addRdata(rdata);
249 }
250 
251 void
252 BasicRRset::addRdata(const std::string& rdata_str) {
253  addRdata(createRdata(getType(), getClass(), rdata_str));
254 }
255 
256 unsigned int
257 BasicRRset::getRdataCount() const {
258  return (impl_->rdatalist_.size());
259 }
260 
261 const Name&
262 BasicRRset::getName() const {
263  return (impl_->name_);
264 }
265 
266 const RRClass&
267 BasicRRset::getClass() const {
268  return (impl_->rrclass_);
269 }
270 
271 const RRType&
272 BasicRRset::getType() const {
273  return (impl_->rrtype_);
274 }
275 
276 const RRTTL&
277 BasicRRset::getTTL() const {
278  return (impl_->ttl_);
279 }
280 
281 void
282 BasicRRset::setTTL(const RRTTL& ttl) {
283  impl_->ttl_ = ttl;
284 }
285 
286 string
287 BasicRRset::toText() const {
288  return (AbstractRRset::toText());
289 }
290 
291 uint16_t
292 BasicRRset::getLength() const {
293  uint16_t length = 0;
294  RdataIteratorPtr it = getRdataIterator();
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 
335 unsigned int
336 BasicRRset::toWire(OutputBuffer& buffer) const {
337  return (AbstractRRset::toWire(buffer));
338 }
339 
340 unsigned int
341 BasicRRset::toWire(AbstractMessageRenderer& renderer) const {
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 
350 RRset::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 
359 unsigned int
361  if (rrsig_) {
362  return (rrsig_->getRdataCount());
363  } else {
364  return (0);
365  }
366 }
367 
368 uint16_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 
383 unsigned int
384 RRset::toWire(OutputBuffer& buffer) const {
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 
397 unsigned 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 
415 namespace {
416 
417 class BasicRdataIterator : public RdataIterator {
418 public:
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 
450 private:
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 Name class encapsulates DNS names.
Definition: name.h:223
The BasicRRset class is a concrete derived class of AbstractRRset that defines a straightforward RRse...
Definition: rrset.h:629
const RRClass & rrclass_
Definition: dns/message.cc:695
virtual const Name & getName() const =0
Returns the owner name of the RRset.
The RdataIterator class is an abstract base class that provides an interface for accessing RDATA obje...
Definition: rrset.h:558
This encapsulates the actual implementation of the BasicRRset class.
Definition: rrset.cc:161
void skip(size_t len)
Insert a specified length of gap at the end of the buffer.
virtual uint16_t getLength() const
Get the wire format length of the BasicRRset.
Definition: rrset.cc:292
vector< ConstRdataPtr > rdatalist_
Definition: rrset.cc:176
boost::shared_ptr< const Rdata > ConstRdataPtr
Definition: rdata.h:72
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 ...
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
Definition: rdata.h:123
virtual RdataIteratorPtr getRdataIterator() const
Return an iterator to go through all RDATA stored in the BasicRRset.
Definition: rrset.cc:461
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
STL namespace.
virtual const RRClass & getClass() const =0
Returns the RR Class of the RRset.
virtual unsigned int getRRsigDataCount() const
Returns the number of RRSIG records associated with the RRset.
Definition: rrset.cc:360
void trim(size_t len)
Trim the specified length of data from the end of the internal buffer.
const RRType & rrtype_
Definition: dns/message.cc:694
void toWire(AbstractMessageRenderer &renderer) const
Render the RRTTL in the wire format.
Definition: rrttl.cc:204
virtual unsigned int getRdataCount() const
Returns the number of Rdata objects contained in the RRset.
Definition: rrset.cc:257
The RRClass class encapsulates DNS resource record classes.
Definition: rrclass.h:98
void writeUint16(uint16_t data)
Write an unsigned 16-bit integer in host byte order into the internal buffer in network byte order...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: edns.h:19
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
virtual std::string toText() const =0
Convert the RRset to a string.
Definition: rrset.cc:37
virtual void setTruncated()=0
Mark the renderer to indicate truncation has occurred while rendering.
virtual unsigned int toWire(AbstractMessageRenderer &renderer) const
Render the RRset in the wire format with name compression and truncation handling.
Definition: rrset.cc:398
void toWire(AbstractMessageRenderer &renderer) const
Render the RRType in the wire format.
Definition: rrtype.cc:55
The RRTTL class encapsulates TTLs used in DNS resource records.
Definition: rrttl.h:55
virtual RdataIteratorPtr getRdataIterator() const =0
Return an iterator to go through all RDATA stored in the RRset.
void toWire(AbstractMessageRenderer &renderer) const
Render the RRClass in the wire format.
Definition: rrclass.cc:54
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
A standard DNS module exception that is thrown if an RRset object does not contain any RDATA where re...
Definition: rrset.h:31
virtual const RRTTL & getTTL() const =0
Returns the TTL of the RRset.
Defines the logger used by the top-level component of kea-dhcp-ddns.
The AbstractRRset class is an abstract base class that models a DNS RRset.
Definition: rrset.h:154
virtual unsigned int toWire(AbstractMessageRenderer &renderer) const
Render the RRset in the wire format with name compression and truncation handling.
Definition: rrset.cc:341
std::vector< rdata::ConstRdataPtr >::const_iterator it_
Iterator used to retrieve data.
Definition: rrset.cc:455
const std::vector< rdata::ConstRdataPtr > * datavector_
Vector containing data.
Definition: rrset.cc:452
const Name & name_
Definition: dns/message.cc:693
ostream & operator<<(ostream &os, const AbstractRRset &rrset)
Insert the RRset as a string into stream.
Definition: rrset.cc:154
The RRType class encapsulates DNS resource record types.
Definition: rrtype.h:106
size_t getLength() const
Return the length of data written in the internal buffer.
boost::shared_ptr< RdataIterator > RdataIteratorPtr
A pointer-like type point to an RdataIterator object.
Definition: rrset.h:63
virtual const RRType & getType() const =0
Returns the RR Type of the RRset.
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
Definition: rrset.h:47
BasicRRsetImpl(const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl)
Definition: rrset.cc:163
virtual size_t getLengthLimit() const =0
Return the maximum length of rendered data that can fit in the corresponding DNS message without trun...
virtual uint16_t getLength() const
Get the wire format length of the RRset.
Definition: rrset.cc:369
virtual ~RRset()
Definition: rrset.cc:357
void toWire(AbstractMessageRenderer &renderer) const
Render the Name in the wire format with compression.
Definition: name.cc:502