Coverage Report

Created: 2026-08-13 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/nsecrecords.cc
Line
Count
Source
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
#include "dnsrecords.hh"
26
27
class NSECBitmapGenerator
28
{
29
public:
30
615
  NSECBitmapGenerator(DNSPacketWriter& pw_): pw(pw_)
31
615
  {
32
615
    memset(res, 0, sizeof(res));
33
615
  }
34
35
  void set(uint16_t type)
36
993
  {
37
993
    uint16_t bit = type % 256;
38
993
    int window = static_cast<int>(type / 256);
39
40
993
    if (window != oldWindow) {
41
616
      if (oldWindow > -1) {
42
369
        res[0] = static_cast<unsigned char>(oldWindow);
43
369
        res[1] = static_cast<unsigned char>(len);
44
369
        tmp.assign(res, res+len+2);
45
369
        pw.xfrBlob(tmp);
46
369
      }
47
616
      memset(res, 0, sizeof(res));
48
616
      oldWindow = window;
49
616
    }
50
993
    res[2+bit/8] |= 1 << (7-(bit%8));
51
993
    len=1+bit/8;
52
993
  }
53
54
  void finish()
55
615
  {
56
615
    res[0] = static_cast<unsigned char>(oldWindow);
57
615
    res[1] = static_cast<unsigned char>(len);
58
615
    if (len) {
59
247
      tmp.assign(res, res+len+2);
60
247
      pw.xfrBlob(tmp);
61
247
    }
62
615
  }
63
64
private:
65
  DNSPacketWriter& pw;
66
  /* one byte for the window,
67
     one for the length,
68
     then the maximum of 32 bytes */
69
  uint8_t res[34];
70
  int oldWindow{-1};
71
  int len{0};
72
  string tmp;
73
};
74
75
void NSECBitmap::toPacket(DNSPacketWriter& pw) const
76
615
{
77
615
  NSECBitmapGenerator nbg(pw);
78
615
  if (d_bitset) {
79
0
    size_t found = 0;
80
0
    size_t l_count = d_bitset->count();
81
0
    for(size_t idx = 0; idx < nbTypes && found < l_count; ++idx){
82
0
      if (!d_bitset->test(idx)) {
83
0
        continue;
84
0
      }
85
0
      found++;
86
0
      nbg.set(idx);
87
0
    }
88
0
  }
89
615
  else {
90
993
    for (const auto& type : d_set) {
91
993
      nbg.set(type);
92
993
    }
93
615
  }
94
95
615
  nbg.finish();
96
615
}
97
98
void NSECBitmap::fromPacket(PacketReader& pr)
99
9.85k
{
100
9.85k
  string bitmap;
101
9.85k
  pr.xfrBlob(bitmap);
102
103
  // 00 06 20 00 00 00 00 03  -> NS RRSIG NSEC  ( 2, 46, 47 ) counts from left
104
9.85k
  if(bitmap.empty()) {
105
4.87k
    return;
106
4.87k
  }
107
108
4.98k
  if(bitmap.size() < 2) {
109
17
    throw MOADNSException("NSEC record with impossibly small bitmap");
110
17
  }
111
112
39.4k
  for(unsigned int n = 0; n+1 < bitmap.size();) {
113
35.8k
    uint8_t window=static_cast<uint8_t>(bitmap[n++]);
114
35.8k
    uint8_t blen=static_cast<uint8_t>(bitmap[n++]);
115
116
    // end if zero padding and ensure packet length
117
35.8k
    if (window == 0 && blen == 0) {
118
1.04k
      break;
119
1.04k
    }
120
121
34.7k
    if (blen > 32) {
122
306
      throw MOADNSException("NSEC record with invalid bitmap length");
123
306
    }
124
125
34.4k
    if (n + blen > bitmap.size()) {
126
54
      throw MOADNSException("NSEC record with bitmap length > packet length");
127
54
    }
128
129
221k
    for(unsigned int k=0; k < blen; k++) {
130
186k
      uint8_t val=bitmap[n++];
131
1.68M
      for(int bit = 0; bit < 8 ; ++bit , val>>=1) {
132
1.49M
        if(val & 1) {
133
696k
          set((7-bit) + 8*(k) + 256*window);
134
696k
        }
135
1.49M
      }
136
186k
    }
137
34.4k
  }
138
4.96k
}
139
140
string NSECBitmap::getZoneRepresentation() const
141
1.51k
{
142
1.51k
  string ret;
143
144
1.51k
  if (d_bitset) {
145
51
    size_t found = 0;
146
51
    size_t l_count = d_bitset->count();
147
1.56M
    for(size_t idx = 0; idx < nbTypes && found < l_count; ++idx) {
148
1.56M
      if (!d_bitset->test(idx)) {
149
1.55M
        continue;
150
1.55M
      }
151
12.7k
      found++;
152
153
12.7k
      ret+=" ";
154
12.7k
      ret+=DNSRecordContent::NumberToType(idx);
155
12.7k
    }
156
51
  }
157
1.46k
  else {
158
7.21k
    for(const auto& type : d_set) {
159
7.21k
      ret+=" ";
160
7.21k
      ret+=DNSRecordContent::NumberToType(type);
161
7.21k
    }
162
1.46k
  }
163
164
1.51k
  return ret;
165
1.51k
}
166
167
void NSECRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
168
4
{
169
4
  regist(1, 47, &make, &make, "NSEC");
170
4
}
171
172
std::shared_ptr<DNSRecordContent> NSECRecordContent::make(const string& content)
173
604
{
174
604
  return std::make_shared<NSECRecordContent>(content);
175
604
}
176
177
NSECRecordContent::NSECRecordContent(const string& content, const ZoneName& zone)
178
604
{
179
604
  RecordTextReader rtr(content, zone);
180
604
  rtr.xfrName(d_next);
181
182
5.08k
  while(!rtr.eof()) {
183
4.47k
    uint16_t type;
184
4.47k
    rtr.xfrType(type);
185
4.47k
    set(type);
186
4.47k
  }
187
604
}
188
189
void NSECRecordContent::toPacket(DNSPacketWriter& pw) const
190
406
{
191
406
  pw.xfrName(d_next);
192
406
  d_bitmap.toPacket(pw);
193
406
}
194
195
std::shared_ptr<NSECRecordContent::DNSRecordContent> NSECRecordContent::make(const DNSRecord & /* dr */, PacketReader& pr)
196
6.09k
{
197
6.09k
  auto ret=std::make_shared<NSECRecordContent>();
198
6.09k
  pr.xfrName(ret->d_next);
199
200
6.09k
  ret->d_bitmap.fromPacket(pr);
201
202
6.09k
  return ret;
203
6.09k
}
204
205
string NSECRecordContent::getZoneRepresentation(bool /* noDot */) const
206
1.02k
{
207
1.02k
  string ret;
208
1.02k
  RecordTextWriter rtw(ret);
209
1.02k
  rtw.xfrName(d_next);
210
211
1.02k
  return ret + d_bitmap.getZoneRepresentation();
212
1.02k
}
213
214
////// begin of NSEC3
215
216
void NSEC3RecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
217
4
{
218
4
  regist(1, 50, &make, &make, "NSEC3");
219
4
}
220
221
std::shared_ptr<DNSRecordContent> NSEC3RecordContent::make(const string& content)
222
300
{
223
300
  return std::make_shared<NSEC3RecordContent>(content);
224
300
}
225
226
NSEC3RecordContent::NSEC3RecordContent(const string& content, const ZoneName& zone)
227
300
{
228
300
  RecordTextReader rtr(content, zone);
229
300
  rtr.xfr8BitInt(d_algorithm);
230
300
  rtr.xfr8BitInt(d_flags);
231
300
  rtr.xfr16BitInt(d_iterations);
232
233
300
  rtr.xfrHexBlob(d_salt);
234
300
  rtr.xfrBase32HexBlob(d_nexthash);
235
236
822
  while(!rtr.eof()) {
237
522
    uint16_t type;
238
522
    rtr.xfrType(type);
239
522
    set(type);
240
522
  }
241
300
}
242
243
void NSEC3RecordContent::toPacket(DNSPacketWriter& pw) const
244
196
{
245
196
  pw.xfr8BitInt(d_algorithm);
246
196
  pw.xfr8BitInt(d_flags);
247
196
  pw.xfr16BitInt(d_iterations);
248
196
  pw.xfr8BitInt(d_salt.length());
249
196
  pw.xfrBlob(d_salt);
250
251
196
  pw.xfr8BitInt(d_nexthash.length());
252
196
  pw.xfrBlob(d_nexthash);
253
254
196
  d_bitmap.toPacket(pw);
255
196
}
256
257
std::shared_ptr<NSEC3RecordContent::DNSRecordContent> NSEC3RecordContent::make(const DNSRecord& /* dr */, PacketReader& pr)
258
2.21k
{
259
2.21k
  auto ret=std::make_shared<NSEC3RecordContent>();
260
2.21k
  pr.xfr8BitInt(ret->d_algorithm);
261
2.21k
  pr.xfr8BitInt(ret->d_flags);
262
2.21k
  pr.xfr16BitInt(ret->d_iterations);
263
2.21k
  uint8_t len;
264
2.21k
  pr.xfr8BitInt(len);
265
2.21k
  pr.xfrBlob(ret->d_salt, len);
266
267
2.21k
  pr.xfr8BitInt(len);
268
2.21k
  pr.xfrBlob(ret->d_nexthash, len);
269
270
2.21k
  ret->d_bitmap.fromPacket(pr);
271
2.21k
  return ret;
272
2.21k
}
273
274
string NSEC3RecordContent::getZoneRepresentation(bool /* noDot */) const
275
417
{
276
417
  string ret;
277
417
  RecordTextWriter rtw(ret);
278
417
  rtw.xfr8BitInt(d_algorithm);
279
417
  rtw.xfr8BitInt(d_flags);
280
417
  rtw.xfr16BitInt(d_iterations);
281
282
417
  rtw.xfrHexBlob(d_salt);
283
417
  rtw.xfrBase32HexBlob(d_nexthash);
284
285
417
  return ret + d_bitmap.getZoneRepresentation();
286
417
}
287
288
289
void NSEC3PARAMRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
290
4
{
291
4
  regist(1, 51, &make, &make, "NSEC3PARAM");
292
4
  regist(254, 51, &make, &make, "NSEC3PARAM");
293
4
}
294
295
std::shared_ptr<DNSRecordContent> NSEC3PARAMRecordContent::make(const string& content)
296
42
{
297
42
  return std::make_shared<NSEC3PARAMRecordContent>(content);
298
42
}
299
300
NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const ZoneName& zone)
301
42
{
302
42
  RecordTextReader rtr(content, zone);
303
42
  rtr.xfr8BitInt(d_algorithm);
304
42
  rtr.xfr8BitInt(d_flags);
305
42
  rtr.xfr16BitInt(d_iterations);
306
42
  rtr.xfrHexBlob(d_salt);
307
42
}
308
309
void NSEC3PARAMRecordContent::toPacket(DNSPacketWriter& pw) const
310
17
{
311
17
  pw.xfr8BitInt(d_algorithm);
312
17
        pw.xfr8BitInt(d_flags);
313
17
        pw.xfr16BitInt(d_iterations);
314
17
  pw.xfr8BitInt(d_salt.length());
315
  // cerr<<"salt: '"<<makeHexDump(d_salt)<<"', "<<d_salt.length()<<endl;
316
17
  pw.xfrBlob(d_salt);
317
17
}
318
319
std::shared_ptr<NSEC3PARAMRecordContent::DNSRecordContent> NSEC3PARAMRecordContent::make(const DNSRecord& /* dr */, PacketReader& pr)
320
1.01k
{
321
1.01k
  auto ret=std::make_shared<NSEC3PARAMRecordContent>();
322
1.01k
  pr.xfr8BitInt(ret->d_algorithm);
323
1.01k
        pr.xfr8BitInt(ret->d_flags);
324
1.01k
        pr.xfr16BitInt(ret->d_iterations);
325
1.01k
  uint8_t len;
326
1.01k
  pr.xfr8BitInt(len);
327
1.01k
  pr.xfrHexBlob(ret->d_salt, len);
328
1.01k
  return ret;
329
1.01k
}
330
331
string NSEC3PARAMRecordContent::getZoneRepresentation(bool /* noDot */) const
332
61
{
333
61
  string ret;
334
61
  RecordTextWriter rtw(ret);
335
61
  rtw.xfr8BitInt(d_algorithm);
336
61
        rtw.xfr8BitInt(d_flags);
337
61
        rtw.xfr16BitInt(d_iterations);
338
61
  rtw.xfrHexBlob(d_salt);
339
61
  return ret;
340
61
}
341
342
////// end of NSEC3
343
344
////// begin of CSYNC
345
346
void CSYNCRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
347
4
{
348
4
  regist(1, 62, &make, &make, "CSYNC");
349
4
}
350
351
std::shared_ptr<DNSRecordContent> CSYNCRecordContent::make(const string& content)
352
64
{
353
64
  return std::make_shared<CSYNCRecordContent>(content);
354
64
}
355
356
CSYNCRecordContent::CSYNCRecordContent(const string& content, const ZoneName& zone)
357
64
{
358
64
  RecordTextReader rtr(content, zone);
359
64
  rtr.xfr32BitInt(d_serial);
360
64
  rtr.xfr16BitInt(d_flags);
361
362
511
  while(!rtr.eof()) {
363
447
    uint16_t type;
364
447
    rtr.xfrType(type);
365
447
    set(type);
366
447
  }
367
64
}
368
369
void CSYNCRecordContent::toPacket(DNSPacketWriter& pw) const
370
31
{
371
31
  pw.xfr32BitInt(d_serial);
372
31
  pw.xfr16BitInt(d_flags);
373
374
31
  d_bitmap.toPacket(pw);
375
31
}
376
377
std::shared_ptr<CSYNCRecordContent::DNSRecordContent> CSYNCRecordContent::make(const DNSRecord& /* dr */, PacketReader& pr)
378
2.16k
{
379
2.16k
  auto ret=std::make_shared<CSYNCRecordContent>();
380
2.16k
  pr.xfr32BitInt(ret->d_serial);
381
2.16k
  pr.xfr16BitInt(ret->d_flags);
382
383
2.16k
  ret->d_bitmap.fromPacket(pr);
384
2.16k
  return ret;
385
2.16k
}
386
387
string CSYNCRecordContent::getZoneRepresentation(bool /* noDot */) const
388
81
{
389
81
  string ret;
390
81
  RecordTextWriter rtw(ret);
391
81
  rtw.xfr32BitInt(d_serial);
392
81
  rtw.xfr16BitInt(d_flags);
393
394
81
  return ret + d_bitmap.getZoneRepresentation();
395
81
}
396
397
////// end of CSYNC