/src/kea/src/lib/dns/rrset.cc
Line | Count | Source |
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 | | |
9 | | #include <exceptions/isc_assert.h> |
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 | | |
23 | | using namespace isc::dns; |
24 | | using namespace isc::util; |
25 | | using namespace isc::dns::rdata; |
26 | | |
27 | | using namespace std; |
28 | | |
29 | | namespace isc { |
30 | | namespace dns { |
31 | | void |
32 | 0 | AbstractRRset::addRdata(const Rdata& rdata) { |
33 | 0 | addRdata(createRdata(getType(), getClass(), rdata)); |
34 | 0 | } |
35 | | |
36 | | string |
37 | 42 | AbstractRRset::toText() const { |
38 | 42 | string s; |
39 | 42 | RdataIteratorPtr it = getRdataIterator(); |
40 | | |
41 | | // In the case of an empty rrset, just print name, ttl, class, and |
42 | | // type |
43 | 42 | if (it->isLast()) { |
44 | | // But only for class ANY or NONE |
45 | 30 | if (getClass() != RRClass::ANY() && |
46 | 30 | getClass() != RRClass::NONE()) { |
47 | 30 | isc_throw(EmptyRRset, "toText() is attempted for an empty RRset"); |
48 | 30 | } |
49 | | |
50 | 0 | s += getName().toText() + " " + getTTL().toText() + " " + |
51 | 0 | getClass().toText() + " " + getType().toText() + "\n"; |
52 | 0 | return (s); |
53 | 30 | } |
54 | | |
55 | 12 | do { |
56 | 12 | s += getName().toText() + " " + getTTL().toText() + " " + |
57 | 12 | getClass().toText() + " " + getType().toText() + " " + |
58 | 12 | it->getCurrent().toText() + "\n"; |
59 | 12 | it->next(); |
60 | 12 | } while (!it->isLast()); |
61 | | |
62 | 12 | if (getRRsig()) { |
63 | 0 | s += getRRsig()->toText(); |
64 | 0 | } |
65 | | |
66 | 12 | return (s); |
67 | 42 | } |
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 uint32_t |
75 | 12 | rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) { |
76 | 12 | uint32_t n = 0; |
77 | 12 | RdataIteratorPtr it = rrset.getRdataIterator(); |
78 | | |
79 | 12 | if (it->isLast()) { |
80 | | // empty rrsets are only allowed for classes ANY and NONE |
81 | 0 | if (rrset.getClass() != RRClass::ANY() && |
82 | 0 | rrset.getClass() != RRClass::NONE()) { |
83 | 0 | isc_throw(EmptyRRset, "toWire() is attempted for an empty RRset"); |
84 | 0 | } |
85 | | |
86 | | // For an empty RRset, write the name, type, class and TTL once, |
87 | | // followed by empty rdata. |
88 | 0 | rrset.getName().toWire(output); |
89 | 0 | rrset.getType().toWire(output); |
90 | 0 | rrset.getClass().toWire(output); |
91 | 0 | rrset.getTTL().toWire(output); |
92 | 0 | output.writeUint16(0); |
93 | | // Still counts as 1 'rr'; it does show up in the message |
94 | 0 | return (1); |
95 | 0 | } |
96 | | |
97 | | // sort the set of Rdata based on rrset-order and sortlist, and possible |
98 | | // other options. Details to be considered. |
99 | 12 | do { |
100 | 12 | const size_t pos0 = output.getLength(); |
101 | 12 | isc_throw_assert(pos0 < 65536); |
102 | | |
103 | 12 | rrset.getName().toWire(output); |
104 | 12 | rrset.getType().toWire(output); |
105 | 12 | rrset.getClass().toWire(output); |
106 | 12 | rrset.getTTL().toWire(output); |
107 | | |
108 | 12 | const size_t pos = output.getLength(); |
109 | 12 | output.skip(sizeof(uint16_t)); // leave the space for RDLENGTH |
110 | 12 | it->getCurrent().toWire(output); |
111 | 12 | output.writeUint16At(output.getLength() - pos - sizeof(uint16_t), pos); |
112 | | |
113 | 12 | if (limit > 0 && output.getLength() > limit) { |
114 | | // truncation is needed |
115 | 0 | output.trim(output.getLength() - pos0); |
116 | 0 | return (n); |
117 | 0 | } |
118 | | |
119 | 12 | it->next(); |
120 | 12 | ++n; |
121 | 12 | } while (!it->isLast()); |
122 | | |
123 | 12 | return (n); |
124 | 12 | } rrset.cc:unsigned int isc::dns::(anonymous namespace)::rrsetToWire<isc::util::OutputBuffer>(isc::dns::AbstractRRset const&, isc::util::OutputBuffer&, unsigned long) Line | Count | Source | 75 | 12 | rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) { | 76 | 12 | uint32_t n = 0; | 77 | 12 | RdataIteratorPtr it = rrset.getRdataIterator(); | 78 | | | 79 | 12 | if (it->isLast()) { | 80 | | // empty rrsets are only allowed for classes ANY and NONE | 81 | 0 | if (rrset.getClass() != RRClass::ANY() && | 82 | 0 | rrset.getClass() != RRClass::NONE()) { | 83 | 0 | isc_throw(EmptyRRset, "toWire() is attempted for an empty RRset"); | 84 | 0 | } | 85 | | | 86 | | // For an empty RRset, write the name, type, class and TTL once, | 87 | | // followed by empty rdata. | 88 | 0 | rrset.getName().toWire(output); | 89 | 0 | rrset.getType().toWire(output); | 90 | 0 | rrset.getClass().toWire(output); | 91 | 0 | rrset.getTTL().toWire(output); | 92 | 0 | output.writeUint16(0); | 93 | | // Still counts as 1 'rr'; it does show up in the message | 94 | 0 | return (1); | 95 | 0 | } | 96 | | | 97 | | // sort the set of Rdata based on rrset-order and sortlist, and possible | 98 | | // other options. Details to be considered. | 99 | 12 | do { | 100 | 12 | const size_t pos0 = output.getLength(); | 101 | 12 | isc_throw_assert(pos0 < 65536); | 102 | | | 103 | 12 | rrset.getName().toWire(output); | 104 | 12 | rrset.getType().toWire(output); | 105 | 12 | rrset.getClass().toWire(output); | 106 | 12 | rrset.getTTL().toWire(output); | 107 | | | 108 | 12 | const size_t pos = output.getLength(); | 109 | 12 | output.skip(sizeof(uint16_t)); // leave the space for RDLENGTH | 110 | 12 | it->getCurrent().toWire(output); | 111 | 12 | output.writeUint16At(output.getLength() - pos - sizeof(uint16_t), pos); | 112 | | | 113 | 12 | if (limit > 0 && output.getLength() > limit) { | 114 | | // truncation is needed | 115 | 0 | output.trim(output.getLength() - pos0); | 116 | 0 | return (n); | 117 | 0 | } | 118 | | | 119 | 12 | it->next(); | 120 | 12 | ++n; | 121 | 12 | } while (!it->isLast()); | 122 | | | 123 | 12 | return (n); | 124 | 12 | } |
Unexecuted instantiation: rrset.cc:unsigned int isc::dns::(anonymous namespace)::rrsetToWire<isc::dns::AbstractMessageRenderer>(isc::dns::AbstractRRset const&, isc::dns::AbstractMessageRenderer&, unsigned long) |
125 | | |
126 | | } // end of unnamed namespace |
127 | | |
128 | | uint32_t |
129 | 12 | AbstractRRset::toWire(OutputBuffer& buffer) const { |
130 | 12 | return (rrsetToWire<OutputBuffer>(*this, buffer, 0)); |
131 | 12 | } |
132 | | |
133 | | uint32_t |
134 | 0 | AbstractRRset::toWire(AbstractMessageRenderer& renderer) const { |
135 | 0 | const uint32_t rrs_written = rrsetToWire<AbstractMessageRenderer>( |
136 | 0 | *this, renderer, renderer.getLengthLimit()); |
137 | 0 | if (getRdataCount() > rrs_written) { |
138 | 0 | renderer.setTruncated(); |
139 | 0 | } |
140 | 0 | return (rrs_written); |
141 | 0 | } |
142 | | |
143 | | bool |
144 | 0 | 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 | 0 | return (getType() == other.getType() && |
149 | 0 | getName() == other.getName() && |
150 | 0 | getClass() == other.getClass()); |
151 | 0 | } |
152 | | |
153 | | ostream& |
154 | 0 | operator<<(ostream& os, const AbstractRRset& rrset) { |
155 | 0 | os << rrset.toText(); |
156 | 0 | return (os); |
157 | 0 | } |
158 | | |
159 | | /// \brief This encapsulates the actual implementation of the \c BasicRRset |
160 | | /// class. It's hidden from applications. |
161 | | class BasicRRsetImpl { |
162 | | public: |
163 | | BasicRRsetImpl(const Name& name, const RRClass& rrclass, |
164 | | const RRType& rrtype, const RRTTL& ttl) : |
165 | 12.1k | name_(name), rrclass_(rrclass), rrtype_(rrtype), ttl_(ttl) {} |
166 | | |
167 | | uint32_t toWire(AbstractMessageRenderer& renderer, size_t limit) const; |
168 | | |
169 | | Name name_; |
170 | | RRClass rrclass_; |
171 | | RRType rrtype_; |
172 | | RRTTL ttl_; |
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 | | uint32_t |
182 | 0 | BasicRRsetImpl::toWire(AbstractMessageRenderer& renderer, size_t limit) const { |
183 | 0 | if (rdatalist_.empty()) { |
184 | | // empty rrsets are only allowed for classes ANY and NONE |
185 | 0 | if (rrclass_ != RRClass::ANY() && |
186 | 0 | rrclass_ != RRClass::NONE()) { |
187 | 0 | isc_throw(EmptyRRset, "toWire() is attempted for an empty RRset"); |
188 | 0 | } |
189 | | |
190 | | // For an empty RRset, write the name, type, class and TTL once, |
191 | | // followed by empty rdata. |
192 | 0 | name_.toWire(renderer); |
193 | 0 | rrtype_.toWire(renderer); |
194 | 0 | rrclass_.toWire(renderer); |
195 | 0 | ttl_.toWire(renderer); |
196 | 0 | renderer.writeUint16(0); |
197 | | // Still counts as 1 'rr'; it does show up in the message |
198 | 0 | return (1); |
199 | 0 | } |
200 | | |
201 | 0 | 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 | 0 | for (auto const& rdata : rdatalist_) { |
206 | 0 | const size_t pos0 = renderer.getLength(); |
207 | 0 | isc_throw_assert(pos0 < 65536); |
208 | |
|
209 | 0 | name_.toWire(renderer); |
210 | 0 | rrtype_.toWire(renderer); |
211 | 0 | rrclass_.toWire(renderer); |
212 | 0 | ttl_.toWire(renderer); |
213 | |
|
214 | 0 | const size_t pos = renderer.getLength(); |
215 | 0 | renderer.skip(sizeof(uint16_t)); // leave the space for RDLENGTH |
216 | 0 | rdata->toWire(renderer); |
217 | 0 | renderer.writeUint16At(renderer.getLength() - pos - sizeof(uint16_t), |
218 | 0 | pos); |
219 | |
|
220 | 0 | if (limit > 0 && renderer.getLength() > limit) { |
221 | | // truncation is needed |
222 | 0 | renderer.trim(renderer.getLength() - pos0); |
223 | 0 | return (n); |
224 | 0 | } |
225 | 0 | ++n; |
226 | 0 | } |
227 | | |
228 | 0 | return (n); |
229 | 0 | } |
230 | | |
231 | | BasicRRset::BasicRRset(const Name& name, const RRClass& rrclass, |
232 | 12.1k | const RRType& rrtype, const RRTTL& ttl) { |
233 | 12.1k | impl_.reset(new BasicRRsetImpl(name, rrclass, rrtype, ttl)); |
234 | 12.1k | } |
235 | | |
236 | 12.1k | BasicRRset::~BasicRRset() { |
237 | 12.1k | } |
238 | | |
239 | | void |
240 | 40.2k | BasicRRset::addRdata(ConstRdataPtr rdata) { |
241 | 40.2k | impl_->rdatalist_.push_back(rdata); |
242 | 40.2k | } |
243 | | |
244 | | void |
245 | 0 | BasicRRset::addRdata(const Rdata& rdata) { |
246 | 0 | AbstractRRset::addRdata(rdata); |
247 | 0 | } |
248 | | |
249 | | void |
250 | 0 | BasicRRset::addRdata(const std::string& rdata_str) { |
251 | 0 | addRdata(createRdata(getType(), getClass(), rdata_str)); |
252 | 0 | } |
253 | | |
254 | | uint32_t |
255 | 24 | BasicRRset::getRdataCount() const { |
256 | 24 | return (impl_->rdatalist_.size()); |
257 | 24 | } |
258 | | |
259 | | const Name& |
260 | 50.1k | BasicRRset::getName() const { |
261 | 50.1k | return (impl_->name_); |
262 | 50.1k | } |
263 | | |
264 | | const RRClass& |
265 | 133k | BasicRRset::getClass() const { |
266 | 133k | return (impl_->rrclass_); |
267 | 133k | } |
268 | | |
269 | | const RRType& |
270 | 372k | BasicRRset::getType() const { |
271 | 372k | return (impl_->rrtype_); |
272 | 372k | } |
273 | | |
274 | | const RRTTL& |
275 | 30.3k | BasicRRset::getTTL() const { |
276 | 30.3k | return (impl_->ttl_); |
277 | 30.3k | } |
278 | | |
279 | | void |
280 | 30.3k | BasicRRset::setTTL(const RRTTL& ttl) { |
281 | 30.3k | impl_->ttl_ = ttl; |
282 | 30.3k | } |
283 | | |
284 | | string |
285 | 42 | BasicRRset::toText() const { |
286 | 42 | return (AbstractRRset::toText()); |
287 | 42 | } |
288 | | |
289 | | uint16_t |
290 | 0 | BasicRRset::getLength() const { |
291 | 0 | uint16_t length = 0; |
292 | 0 | RdataIteratorPtr it = getRdataIterator(); |
293 | |
|
294 | 0 | if (it->isLast()) { |
295 | | // empty rrsets are only allowed for classes ANY and NONE |
296 | 0 | if (getClass() != RRClass::ANY() && |
297 | 0 | getClass() != RRClass::NONE()) { |
298 | 0 | isc_throw(EmptyRRset, "getLength() is attempted for an empty RRset"); |
299 | 0 | } |
300 | | |
301 | | // For an empty RRset, write the name, type, class and TTL once, |
302 | | // followed by empty rdata. |
303 | 0 | length += getName().getLength(); |
304 | 0 | length += 2; // TYPE field |
305 | 0 | length += 2; // CLASS field |
306 | 0 | length += 4; // TTL field |
307 | 0 | length += 2; // RDLENGTH field (=0 in wire format) |
308 | |
|
309 | 0 | return (length); |
310 | 0 | } |
311 | | |
312 | 0 | do { |
313 | | // This is a size_t as some of the following additions may |
314 | | // overflow due to a programming mistake somewhere. |
315 | 0 | size_t rrlen = 0; |
316 | |
|
317 | 0 | rrlen += getName().getLength(); |
318 | 0 | rrlen += 2; // TYPE field |
319 | 0 | rrlen += 2; // CLASS field |
320 | 0 | rrlen += 4; // TTL field |
321 | 0 | rrlen += 2; // RDLENGTH field |
322 | 0 | rrlen += it->getCurrent().getLength(); |
323 | |
|
324 | 0 | isc_throw_assert(length + rrlen < 65536); |
325 | 0 | length += rrlen; |
326 | |
|
327 | 0 | it->next(); |
328 | 0 | } while (!it->isLast()); |
329 | | |
330 | 0 | return (length); |
331 | 0 | } |
332 | | |
333 | | uint32_t |
334 | 12 | BasicRRset::toWire(OutputBuffer& buffer) const { |
335 | 12 | return (AbstractRRset::toWire(buffer)); |
336 | 12 | } |
337 | | |
338 | | uint32_t |
339 | 0 | BasicRRset::toWire(AbstractMessageRenderer& renderer) const { |
340 | 0 | const uint32_t rrs_written = impl_->toWire(renderer, |
341 | 0 | renderer.getLengthLimit()); |
342 | 0 | if (impl_->rdatalist_.size() > rrs_written) { |
343 | 0 | renderer.setTruncated(); |
344 | 0 | } |
345 | 0 | return (rrs_written); |
346 | 0 | } |
347 | | |
348 | | RRset::RRset(const Name& name, const RRClass& rrclass, |
349 | | const RRType& rrtype, const RRTTL& ttl) : |
350 | 12.1k | BasicRRset(name, rrclass, rrtype, ttl) { |
351 | 12.1k | } |
352 | | |
353 | 12.1k | RRset::~RRset() { |
354 | 12.1k | } |
355 | | |
356 | | uint32_t |
357 | 0 | RRset::getRRsigDataCount() const { |
358 | 0 | if (rrsig_) { |
359 | 0 | return (rrsig_->getRdataCount()); |
360 | 0 | } else { |
361 | 0 | return (0); |
362 | 0 | } |
363 | 0 | } |
364 | | |
365 | | uint16_t |
366 | 0 | RRset::getLength() const { |
367 | 0 | uint16_t length = BasicRRset::getLength(); |
368 | |
|
369 | 0 | if (rrsig_) { |
370 | 0 | 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 | 0 | isc_throw_assert(length + rrsigs_length < 65536); |
374 | 0 | length += rrsigs_length; |
375 | 0 | } |
376 | | |
377 | 0 | return (length); |
378 | 0 | } |
379 | | |
380 | | uint32_t |
381 | 12 | RRset::toWire(OutputBuffer& buffer) const { |
382 | 12 | uint32_t rrs_written = BasicRRset::toWire(buffer); |
383 | 12 | if (getRdataCount() > rrs_written) { |
384 | 0 | return (rrs_written); |
385 | 0 | } |
386 | | |
387 | 12 | if (rrsig_) { |
388 | 0 | rrs_written += rrsig_->toWire(buffer); |
389 | 0 | } |
390 | | |
391 | 12 | return (rrs_written); |
392 | 12 | } |
393 | | |
394 | | uint32_t |
395 | 0 | RRset::toWire(AbstractMessageRenderer& renderer) const { |
396 | 0 | uint32_t rrs_written = BasicRRset::toWire(renderer); |
397 | 0 | if (getRdataCount() > rrs_written) { |
398 | 0 | return (rrs_written); |
399 | 0 | } |
400 | | |
401 | 0 | if (rrsig_) { |
402 | 0 | rrs_written += rrsig_->toWire(renderer); |
403 | |
|
404 | 0 | if (getRdataCount() + getRRsigDataCount() > rrs_written) { |
405 | 0 | renderer.setTruncated(); |
406 | 0 | } |
407 | 0 | } |
408 | |
|
409 | 0 | return (rrs_written); |
410 | 0 | } |
411 | | |
412 | | namespace { |
413 | | |
414 | | class BasicRdataIterator : public RdataIterator { |
415 | | public: |
416 | | /// @brief Constructor. |
417 | | BasicRdataIterator(const std::vector<rdata::ConstRdataPtr>& datavector) : |
418 | 54 | datavector_(&datavector), it_(datavector_->begin()) { |
419 | 54 | } |
420 | | |
421 | | /// @brief Destructor. |
422 | 54 | ~BasicRdataIterator() { |
423 | 54 | } |
424 | | |
425 | | /// @brief Set iterator at first position. |
426 | 0 | virtual void first() { |
427 | 0 | it_ = datavector_->begin(); |
428 | 0 | } |
429 | | |
430 | | /// @brief Advance iterator. |
431 | 24 | virtual void next() { |
432 | 24 | ++it_; |
433 | 24 | } |
434 | | |
435 | | /// @brief Get value at current iterator position. |
436 | | /// |
437 | | /// @return The value at current iterator position. |
438 | 24 | virtual const rdata::Rdata& getCurrent() const { |
439 | 24 | return (**it_); |
440 | 24 | } |
441 | | |
442 | | /// @brief Check if iterator has reached the end. |
443 | | /// |
444 | | /// @return true if iterator has reached the end, false otherwise. |
445 | 78 | virtual bool isLast() const { |
446 | 78 | return (it_ == datavector_->end()); |
447 | 78 | } |
448 | | |
449 | | private: |
450 | | /// @brief Vector containing data. |
451 | | const std::vector<rdata::ConstRdataPtr>* datavector_; |
452 | | |
453 | | /// @brief Iterator used to retrieve data. |
454 | | std::vector<rdata::ConstRdataPtr>::const_iterator it_; |
455 | | }; |
456 | | |
457 | | } |
458 | | |
459 | | RdataIteratorPtr |
460 | 54 | BasicRRset::getRdataIterator() const { |
461 | 54 | return (RdataIteratorPtr(new BasicRdataIterator(impl_->rdatalist_))); |
462 | 54 | } |
463 | | |
464 | | } |
465 | | } |