Coverage Report

Created: 2025-12-31 07:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}