Coverage Report

Created: 2025-12-31 06:16

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
0
  NSECBitmapGenerator(DNSPacketWriter& pw_): pw(pw_)
31
0
  {
32
0
    memset(res, 0, sizeof(res));
33
0
  }
34
35
  void set(uint16_t type)
36
0
  {
37
0
    uint16_t bit = type % 256;
38
0
    int window = static_cast<int>(type / 256);
39
40
0
    if (window != oldWindow) {
41
0
      if (oldWindow > -1) {
42
0
        res[0] = static_cast<unsigned char>(oldWindow);
43
0
        res[1] = static_cast<unsigned char>(len);
44
0
        tmp.assign(res, res+len+2);
45
0
        pw.xfrBlob(tmp);
46
0
      }
47
0
      memset(res, 0, sizeof(res));
48
0
      oldWindow = window;
49
0
    }
50
0
    res[2+bit/8] |= 1 << (7-(bit%8));
51
0
    len=1+bit/8;
52
0
  }
53
54
  void finish()
55
0
  {
56
0
    res[0] = static_cast<unsigned char>(oldWindow);
57
0
    res[1] = static_cast<unsigned char>(len);
58
0
    if (len) {
59
0
      tmp.assign(res, res+len+2);
60
0
      pw.xfrBlob(tmp);
61
0
    }
62
0
  }
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
0
{
77
0
  NSECBitmapGenerator nbg(pw);
78
0
  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
0
  else {
90
0
    for (const auto& type : d_set) {
91
0
      nbg.set(type);
92
0
    }
93
0
  }
94
95
0
  nbg.finish();
96
0
}
97
98
void NSECBitmap::fromPacket(PacketReader& pr)
99
6.83k
{
100
6.83k
  string bitmap;
101
6.83k
  pr.xfrBlob(bitmap);
102
103
  // 00 06 20 00 00 00 00 03  -> NS RRSIG NSEC  ( 2, 46, 47 ) counts from left
104
6.83k
  if(bitmap.empty()) {
105
3.86k
    return;
106
3.86k
  }
107
108
2.97k
  if(bitmap.size() < 2) {
109
6
    throw MOADNSException("NSEC record with impossibly small bitmap");
110
6
  }
111
112
10.0k
  for(unsigned int n = 0; n+1 < bitmap.size();) {
113
7.45k
    uint8_t window=static_cast<uint8_t>(bitmap[n++]);
114
7.45k
    uint8_t blen=static_cast<uint8_t>(bitmap[n++]);
115
116
    // end if zero padding and ensure packet length
117
7.45k
    if (window == 0 && blen == 0) {
118
332
      break;
119
332
    }
120
121
7.12k
    if (blen > 32) {
122
54
      throw MOADNSException("NSEC record with invalid bitmap length");
123
54
    }
124
125
7.06k
    if (n + blen > bitmap.size()) {
126
21
      throw MOADNSException("NSEC record with bitmap length > packet length");
127
21
    }
128
129
85.8k
    for(unsigned int k=0; k < blen; k++) {
130
78.7k
      uint8_t val=bitmap[n++];
131
709k
      for(int bit = 0; bit < 8 ; ++bit , val>>=1) {
132
630k
        if(val & 1) {
133
456k
          set((7-bit) + 8*(k) + 256*window);
134
456k
        }
135
630k
      }
136
78.7k
    }
137
7.04k
  }
138
2.97k
}
139
140
string NSECBitmap::getZoneRepresentation() const
141
0
{
142
0
  string ret;
143
144
0
  if (d_bitset) {
145
0
    size_t found = 0;
146
0
    size_t l_count = d_bitset->count();
147
0
    for(size_t idx = 0; idx < nbTypes && found < l_count; ++idx) {
148
0
      if (!d_bitset->test(idx)) {
149
0
        continue;
150
0
      }
151
0
      found++;
152
153
0
      ret+=" ";
154
0
      ret+=DNSRecordContent::NumberToType(idx);
155
0
    }
156
0
  }
157
0
  else {
158
0
    for(const auto& type : d_set) {
159
0
      ret+=" ";
160
0
      ret+=DNSRecordContent::NumberToType(type);
161
0
    }
162
0
  }
163
164
0
  return ret;
165
0
}
166
167
void NSECRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
168
2
{
169
2
  regist(1, 47, &make, &make, "NSEC");
170
2
}
171
172
std::shared_ptr<DNSRecordContent> NSECRecordContent::make(const string& content)
173
0
{
174
0
  return std::make_shared<NSECRecordContent>(content);
175
0
}
176
177
NSECRecordContent::NSECRecordContent(const string& content, const ZoneName& zone)
178
0
{
179
0
  RecordTextReader rtr(content, zone);
180
0
  rtr.xfrName(d_next);
181
182
0
  while(!rtr.eof()) {
183
0
    uint16_t type;
184
0
    rtr.xfrType(type);
185
0
    set(type);
186
0
  }
187
0
}
188
189
void NSECRecordContent::toPacket(DNSPacketWriter& pw) const
190
0
{
191
0
  pw.xfrName(d_next);
192
0
  d_bitmap.toPacket(pw);
193
0
}
194
195
std::shared_ptr<NSECRecordContent::DNSRecordContent> NSECRecordContent::make(const DNSRecord & /* dr */, PacketReader& pr)
196
3.77k
{
197
3.77k
  auto ret=std::make_shared<NSECRecordContent>();
198
3.77k
  pr.xfrName(ret->d_next);
199
200
3.77k
  ret->d_bitmap.fromPacket(pr);
201
202
3.77k
  return ret;
203
3.77k
}
204
205
string NSECRecordContent::getZoneRepresentation(bool /* noDot */) const
206
0
{
207
0
  string ret;
208
0
  RecordTextWriter rtw(ret);
209
0
  rtw.xfrName(d_next);
210
211
0
  return ret + d_bitmap.getZoneRepresentation();
212
0
}
213
214
////// begin of NSEC3
215
216
void NSEC3RecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
217
2
{
218
2
  regist(1, 50, &make, &make, "NSEC3");
219
2
}
220
221
std::shared_ptr<DNSRecordContent> NSEC3RecordContent::make(const string& content)
222
0
{
223
0
  return std::make_shared<NSEC3RecordContent>(content);
224
0
}
225
226
NSEC3RecordContent::NSEC3RecordContent(const string& content, const ZoneName& zone)
227
0
{
228
0
  RecordTextReader rtr(content, zone);
229
0
  rtr.xfr8BitInt(d_algorithm);
230
0
  rtr.xfr8BitInt(d_flags);
231
0
  rtr.xfr16BitInt(d_iterations);
232
233
0
  rtr.xfrHexBlob(d_salt);
234
0
  rtr.xfrBase32HexBlob(d_nexthash);
235
236
0
  while(!rtr.eof()) {
237
0
    uint16_t type;
238
0
    rtr.xfrType(type);
239
0
    set(type);
240
0
  }
241
0
}
242
243
void NSEC3RecordContent::toPacket(DNSPacketWriter& pw) const
244
0
{
245
0
  pw.xfr8BitInt(d_algorithm);
246
0
  pw.xfr8BitInt(d_flags);
247
0
  pw.xfr16BitInt(d_iterations);
248
0
  pw.xfr8BitInt(d_salt.length());
249
0
  pw.xfrBlob(d_salt);
250
251
0
  pw.xfr8BitInt(d_nexthash.length());
252
0
  pw.xfrBlob(d_nexthash);
253
254
0
  d_bitmap.toPacket(pw);
255
0
}
256
257
std::shared_ptr<NSEC3RecordContent::DNSRecordContent> NSEC3RecordContent::make(const DNSRecord& /* dr */, PacketReader& pr)
258
2.29k
{
259
2.29k
  auto ret=std::make_shared<NSEC3RecordContent>();
260
2.29k
  pr.xfr8BitInt(ret->d_algorithm);
261
2.29k
  pr.xfr8BitInt(ret->d_flags);
262
2.29k
  pr.xfr16BitInt(ret->d_iterations);
263
2.29k
  uint8_t len;
264
2.29k
  pr.xfr8BitInt(len);
265
2.29k
  pr.xfrBlob(ret->d_salt, len);
266
267
2.29k
  pr.xfr8BitInt(len);
268
2.29k
  pr.xfrBlob(ret->d_nexthash, len);
269
270
2.29k
  ret->d_bitmap.fromPacket(pr);
271
2.29k
  return ret;
272
2.29k
}
273
274
string NSEC3RecordContent::getZoneRepresentation(bool /* noDot */) const
275
0
{
276
0
  string ret;
277
0
  RecordTextWriter rtw(ret);
278
0
  rtw.xfr8BitInt(d_algorithm);
279
0
  rtw.xfr8BitInt(d_flags);
280
0
  rtw.xfr16BitInt(d_iterations);
281
282
0
  rtw.xfrHexBlob(d_salt);
283
0
  rtw.xfrBase32HexBlob(d_nexthash);
284
285
0
  return ret + d_bitmap.getZoneRepresentation();
286
0
}
287
288
289
void NSEC3PARAMRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
290
2
{
291
2
  regist(1, 51, &make, &make, "NSEC3PARAM");
292
2
  regist(254, 51, &make, &make, "NSEC3PARAM");
293
2
}
294
295
std::shared_ptr<DNSRecordContent> NSEC3PARAMRecordContent::make(const string& content)
296
0
{
297
0
  return std::make_shared<NSEC3PARAMRecordContent>(content);
298
0
}
299
300
NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const ZoneName& zone)
301
0
{
302
0
  RecordTextReader rtr(content, zone);
303
0
  rtr.xfr8BitInt(d_algorithm);
304
0
  rtr.xfr8BitInt(d_flags);
305
0
  rtr.xfr16BitInt(d_iterations);
306
0
  rtr.xfrHexBlob(d_salt);
307
0
}
308
309
void NSEC3PARAMRecordContent::toPacket(DNSPacketWriter& pw) const
310
0
{
311
0
  pw.xfr8BitInt(d_algorithm);
312
0
        pw.xfr8BitInt(d_flags);
313
0
        pw.xfr16BitInt(d_iterations);
314
0
  pw.xfr8BitInt(d_salt.length());
315
  // cerr<<"salt: '"<<makeHexDump(d_salt)<<"', "<<d_salt.length()<<endl;
316
0
  pw.xfrBlob(d_salt);
317
0
}
318
319
std::shared_ptr<NSEC3PARAMRecordContent::DNSRecordContent> NSEC3PARAMRecordContent::make(const DNSRecord& /* dr */, PacketReader& pr)
320
1.03k
{
321
1.03k
  auto ret=std::make_shared<NSEC3PARAMRecordContent>();
322
1.03k
  pr.xfr8BitInt(ret->d_algorithm);
323
1.03k
        pr.xfr8BitInt(ret->d_flags);
324
1.03k
        pr.xfr16BitInt(ret->d_iterations);
325
1.03k
  uint8_t len;
326
1.03k
  pr.xfr8BitInt(len);
327
1.03k
  pr.xfrHexBlob(ret->d_salt, len);
328
1.03k
  return ret;
329
1.03k
}
330
331
string NSEC3PARAMRecordContent::getZoneRepresentation(bool /* noDot */) const
332
0
{
333
0
  string ret;
334
0
  RecordTextWriter rtw(ret);
335
0
  rtw.xfr8BitInt(d_algorithm);
336
0
        rtw.xfr8BitInt(d_flags);
337
0
        rtw.xfr16BitInt(d_iterations);
338
0
  rtw.xfrHexBlob(d_salt);
339
0
  return ret;
340
0
}
341
342
////// end of NSEC3
343
344
////// begin of CSYNC
345
346
void CSYNCRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
347
2
{
348
2
  regist(1, 62, &make, &make, "CSYNC");
349
2
}
350
351
std::shared_ptr<DNSRecordContent> CSYNCRecordContent::make(const string& content)
352
0
{
353
0
  return std::make_shared<CSYNCRecordContent>(content);
354
0
}
355
356
CSYNCRecordContent::CSYNCRecordContent(const string& content, const ZoneName& zone)
357
0
{
358
0
  RecordTextReader rtr(content, zone);
359
0
  rtr.xfr32BitInt(d_serial);
360
0
  rtr.xfr16BitInt(d_flags);
361
362
0
  while(!rtr.eof()) {
363
0
    uint16_t type;
364
0
    rtr.xfrType(type);
365
0
    set(type);
366
0
  }
367
0
}
368
369
void CSYNCRecordContent::toPacket(DNSPacketWriter& pw) const
370
0
{
371
0
  pw.xfr32BitInt(d_serial);
372
0
  pw.xfr16BitInt(d_flags);
373
374
0
  d_bitmap.toPacket(pw);
375
0
}
376
377
std::shared_ptr<CSYNCRecordContent::DNSRecordContent> CSYNCRecordContent::make(const DNSRecord& /* dr */, PacketReader& pr)
378
869
{
379
869
  auto ret=std::make_shared<CSYNCRecordContent>();
380
869
  pr.xfr32BitInt(ret->d_serial);
381
869
  pr.xfr16BitInt(ret->d_flags);
382
383
869
  ret->d_bitmap.fromPacket(pr);
384
869
  return ret;
385
869
}
386
387
string CSYNCRecordContent::getZoneRepresentation(bool /* noDot */) const
388
0
{
389
0
  string ret;
390
0
  RecordTextWriter rtw(ret);
391
0
  rtw.xfr32BitInt(d_serial);
392
0
  rtw.xfr16BitInt(d_flags);
393
394
0
  return ret + d_bitmap.getZoneRepresentation();
395
0
}
396
397
////// end of CSYNC