Coverage Report

Created: 2026-06-07 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/dnsrecords.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
26
#include <boost/format.hpp>
27
28
#include "utility.hh"
29
#include "dnsrecords.hh"
30
#include "iputils.hh"
31
32
0
void DNSResourceRecord::setContent(const string &cont) {
33
0
  content = cont;
34
0
  switch(qtype.getCode()) {
35
0
    case QType::SRV:
36
0
    case QType::MX:
37
0
      if (content.size() >= 2 && *(content.rbegin()+1) == ' ')
38
0
        return;
39
0
      [[fallthrough]];
40
0
#if !defined(RECURSOR)
41
0
    case QType::ALIAS:
42
0
#endif
43
0
    case QType::CNAME:
44
0
    case QType::DNAME:
45
0
    case QType::NS:
46
0
    case QType::PTR:
47
0
      if (content.size() >= 2 && *(content.rbegin()) == '.')
48
0
        boost::erase_tail(content, 1);
49
0
  }
50
0
}
51
52
0
string DNSResourceRecord::getZoneRepresentation(bool noDot) const {
53
0
  ostringstream ret;
54
0
  vector<string> parts;
55
0
  string last;
56
57
0
  switch(qtype.getCode()) {
58
0
    case QType::SRV:
59
0
    case QType::MX:
60
0
      stringtok(parts, content);
61
0
      if (parts.empty())
62
0
        return "";
63
0
      last = *parts.rbegin();
64
0
      ret << content;
65
0
      if (last == ".")
66
0
        break;
67
0
      if (*(last.rbegin()) != '.' && !noDot)
68
0
        ret << ".";
69
0
      break;
70
0
#if !defined(RECURSOR)
71
0
    case QType::ALIAS:
72
0
#endif
73
0
    case QType::CNAME:
74
0
    case QType::DNAME:
75
0
    case QType::NS:
76
0
    case QType::PTR:
77
0
      ret<<content;
78
0
      if (*(content.rbegin()) != '.' && !noDot)
79
0
        ret<<".";
80
0
      break;
81
0
    default:
82
0
      ret<<content;
83
0
    break;
84
0
  }
85
0
  return ret.str();
86
0
}
87
88
bool DNSResourceRecord::operator==(const DNSResourceRecord& rhs) const
89
0
{
90
0
  string lcontent=toLower(content);
91
0
  string rcontent=toLower(rhs.content);
92
93
0
  return
94
0
    std::tie(qname, qtype, lcontent, ttl) ==
95
0
    std::tie(rhs.qname, rhs.qtype, rcontent, rhs.ttl);
96
0
}
97
98
//NOLINTBEGIN
99
boilerplate_conv(A, conv.xfrIP(d_ip));
100
//NOLINTEND
101
102
ARecordContent::ARecordContent(uint32_t ip)
103
0
{
104
0
  d_ip = ip;
105
0
}
106
107
ARecordContent::ARecordContent(const ComboAddress& ca)
108
0
{
109
0
  d_ip = ca.sin4.sin_addr.s_addr;
110
0
}
111
112
AAAARecordContent::AAAARecordContent(const ComboAddress& ca)
113
0
{
114
0
  d_ip6.assign((const char*)ca.sin6.sin6_addr.s6_addr, 16);
115
0
}
116
117
118
119
ComboAddress ARecordContent::getCA(int port) const
120
0
{
121
0
  ComboAddress ret;
122
0
  ret.sin4.sin_family=AF_INET;
123
0
  ret.sin4.sin_port=htons(port);
124
0
  memcpy(&ret.sin4.sin_addr.s_addr, &d_ip, sizeof(ret.sin4.sin_addr.s_addr));
125
0
  return ret;
126
0
}
127
128
ComboAddress AAAARecordContent::getCA(int port) const
129
0
{
130
0
  ComboAddress ret;
131
0
  ret.reset();
132
133
0
  ret.sin4.sin_family=AF_INET6;
134
0
  ret.sin6.sin6_port = htons(port);
135
0
  memcpy(&ret.sin6.sin6_addr.s6_addr, d_ip6.c_str(), sizeof(ret.sin6.sin6_addr.s6_addr));
136
0
  return ret;
137
0
}
138
139
140
void ARecordContent::doRecordCheck(const DNSRecord& dr)
141
1.32k
{
142
1.32k
  if(dr.d_clen!=4)
143
22
    throw MOADNSException("Wrong size for A record ("+std::to_string(dr.d_clen)+")");
144
1.32k
}
145
146
//NOLINTBEGIN
147
boilerplate_conv(AAAA, conv.xfrIP6(d_ip6); );
148
149
boilerplate_conv(NS, conv.xfrName(d_content, true));
150
boilerplate_conv(PTR, conv.xfrName(d_content, true));
151
boilerplate_conv(CNAME, conv.xfrName(d_content, true));
152
#if !defined(RECURSOR)
153
boilerplate_conv(ALIAS, conv.xfrName(d_content, false));
154
#endif
155
boilerplate_conv(DNAME, conv.xfrName(d_content));
156
boilerplate_conv(MB, conv.xfrName(d_madname, true));
157
boilerplate_conv(MG, conv.xfrName(d_mgmname, true));
158
boilerplate_conv(MR, conv.xfrName(d_alias, true));
159
boilerplate_conv(MINFO, conv.xfrName(d_rmailbx, true); conv.xfrName(d_emailbx, true));
160
boilerplate_conv(TXT, conv.xfrText(d_text, true));
161
#ifdef HAVE_LUA_RECORDS
162
boilerplate_conv(LUA, conv.xfrType(d_type); conv.xfrText(d_code, true));
163
#endif
164
#if defined(PDNS_AUTH) // [
165
/* Move the position to the end of the current DNS record,
166
   because of a bug in the authoritative server used to insert
167
   non-empty content for some ENT records (see https://github.com/PowerDNS/pdns/pull/17000)
168
*/
169
boilerplate_conv(ENT, conv.consumeRemaining());
170
#else
171
boilerplate_conv(ENT, );
172
#endif // ]
173
boilerplate_conv(SPF, conv.xfrText(d_text, true));
174
boilerplate_conv(HINFO, conv.xfrText(d_cpu);   conv.xfrText(d_host));
175
176
boilerplate_conv(RP,
177
                 conv.xfrName(d_mbox);
178
                 conv.xfrName(d_info)
179
                 );
180
181
182
boilerplate_conv(OPT,
183
                   conv.xfrBlob(d_data)
184
                 );
185
//NOLINTEND
186
187
// NOLINTBEGIN
188
boilerplate_conv(WALLET, conv.xfrText(d_text, true));
189
// NOLINTEND
190
191
#ifdef HAVE_LUA_RECORDS
192
193
bool g_luaRecordInsertWhitespace;
194
195
string LUARecordContent::getCode() const
196
{
197
  // in d_code, series of "part1" "part2"
198
  vector<string> parts;
199
  stringtok(parts, d_code, "\"");
200
  string ret;
201
  if (g_luaRecordInsertWhitespace) { // default before 5.0
202
    for(const auto& part : parts) {
203
      ret += part;
204
      ret.append(1, ' ');
205
    }
206
  }
207
  else { // default since 5.0
208
    for(const auto& part : parts) {
209
      if (part != " ") {
210
        ret += part;
211
      }
212
    }
213
  }
214
  return ret;
215
}
216
#endif
217
218
void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options) const
219
0
{
220
0
  string::size_type pos=0;
221
0
  uint16_t code, len;
222
0
  while(d_data.size() >= 4 + pos) {
223
0
    code = 256 * (unsigned char)d_data.at(pos) + (unsigned char)d_data.at(pos+1);
224
0
    len = 256 * (unsigned char)d_data.at(pos+2) + (unsigned char)d_data.at(pos+3);
225
0
    pos+=4;
226
227
0
    if(pos + len > d_data.size())
228
0
      break;
229
230
0
    string field(d_data.c_str() + pos, len);
231
0
    pos+=len;
232
0
    options.emplace_back(code, std::move(field));
233
0
  }
234
0
}
235
236
//NOLINTBEGIN
237
boilerplate_conv(TSIG,
238
                 conv.xfrName(d_algoName);
239
                 conv.xfr48BitInt(d_time);
240
                 conv.xfr16BitInt(d_fudge);
241
                 uint16_t size=d_mac.size();
242
                 conv.xfr16BitInt(size);
243
                 if (size>0) conv.xfrBlobNoSpaces(d_mac, size);
244
                 conv.xfr16BitInt(d_origID);
245
                 conv.xfr16BitInt(d_eRcode);
246
                 size=d_otherData.size();
247
                 conv.xfr16BitInt(size);
248
                 if (size>0) conv.xfrBlobNoSpaces(d_otherData, size);
249
                 );
250
//NOLINTEND
251
252
0
MXRecordContent::MXRecordContent(uint16_t preference, DNSName  mxname):  d_preference(preference), d_mxname(std::move(mxname))
253
0
{
254
0
}
255
256
//NOLINTBEGIN
257
boilerplate_conv(MX,
258
                 conv.xfr16BitInt(d_preference);
259
                 conv.xfrName(d_mxname, true);
260
                 )
261
262
boilerplate_conv(KX,
263
                 conv.xfr16BitInt(d_preference);
264
                 conv.xfrName(d_exchanger, false);
265
                 )
266
267
boilerplate_conv(IPSECKEY,
268
   conv.xfr8BitInt(d_preference);
269
   conv.xfr8BitInt(d_gatewaytype);
270
   conv.xfr8BitInt(d_algorithm);
271
272
   // now we need to determine values
273
   switch(d_gatewaytype) {
274
   case 0: // NO KEY
275
     break;
276
   case 1: // IPv4 GW
277
     conv.xfrIP(d_ip4);
278
     break;
279
   case 2: // IPv6 GW
280
     conv.xfrIP6(d_ip6);
281
     break;
282
   case 3: // DNS label
283
     conv.xfrName(d_gateway, false);
284
     break;
285
   default:
286
     throw MOADNSException("Parsing record content: invalid gateway type");
287
   };
288
289
   switch(d_algorithm) {
290
   case 0:
291
     break;
292
   case 1:
293
   case 2:
294
     conv.xfrBlob(d_publickey);
295
     break;
296
   default:
297
     throw MOADNSException("Parsing record content: invalid algorithm type");
298
   }
299
)
300
301
boilerplate_conv(DHCID,
302
                 conv.xfrBlob(d_content);
303
                 )
304
305
306
boilerplate_conv(AFSDB,
307
                 conv.xfr16BitInt(d_subtype);
308
                 conv.xfrName(d_hostname);
309
                 )
310
311
312
boilerplate_conv(NAPTR,
313
                 conv.xfr16BitInt(d_order);    conv.xfr16BitInt(d_preference);
314
                 conv.xfrText(d_flags);        conv.xfrText(d_services);         conv.xfrText(d_regexp);
315
                 conv.xfrName(d_replacement);
316
                 )
317
//NOLINTEND
318
319
320
SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, DNSName  target)
321
0
: d_weight(weight), d_port(port), d_target(std::move(target)), d_preference(preference)
322
0
{}
323
324
//NOLINTBEGIN
325
boilerplate_conv(SRV,
326
                 conv.xfr16BitInt(d_preference);   conv.xfr16BitInt(d_weight);   conv.xfr16BitInt(d_port);
327
                 conv.xfrName(d_target);
328
                 )
329
//NOLINTEND
330
331
SOARecordContent::SOARecordContent(DNSName  mname, DNSName  rname, const struct soatimes& st)
332
0
: d_mname(std::move(mname)), d_rname(std::move(rname)), d_st(st)
333
0
{
334
0
}
335
336
//NOLINTBEGIN
337
boilerplate_conv(SOA,
338
                 conv.xfrName(d_mname, true);
339
                 conv.xfrName(d_rname, true);
340
                 conv.xfr32BitInt(d_st.serial);
341
                 conv.xfr32BitInt(d_st.refresh);
342
                 conv.xfr32BitInt(d_st.retry);
343
                 conv.xfr32BitInt(d_st.expire);
344
                 conv.xfr32BitInt(d_st.minimum);
345
                 );
346
#undef KEY
347
boilerplate_conv(KEY,
348
                 conv.xfr16BitInt(d_flags);
349
                 conv.xfr8BitInt(d_protocol);
350
                 conv.xfr8BitInt(d_algorithm);
351
                 conv.xfrBlob(d_certificate);
352
                 );
353
354
boilerplate_conv(ZONEMD,
355
                 conv.xfr32BitInt(d_serial);
356
                 conv.xfr8BitInt(d_scheme);
357
                 conv.xfr8BitInt(d_hashalgo);
358
                 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
359
                 );
360
361
boilerplate_conv(CERT,
362
                 conv.xfr16BitInt(d_type);
363
                 if (d_type == 0) throw MOADNSException("CERT type 0 is reserved");
364
365
                 conv.xfr16BitInt(d_tag);
366
                 conv.xfr8BitInt(d_algorithm);
367
                 conv.xfrBlob(d_certificate);
368
                 )
369
370
boilerplate_conv(TLSA,
371
                 conv.xfr8BitInt(d_certusage);
372
                 conv.xfr8BitInt(d_selector);
373
                 conv.xfr8BitInt(d_matchtype);
374
                 conv.xfrHexBlob(d_cert, true);
375
                 )
376
377
boilerplate_conv(OPENPGPKEY,
378
                 conv.xfrBlob(d_keyring);
379
                 )
380
381
boilerplate_conv(SVCB,
382
                 conv.xfr16BitInt(d_priority);
383
                 conv.xfrName(d_target, false);
384
                 if (d_priority != 0) {
385
                   conv.xfrSvcParamKeyVals(d_params);
386
                 }
387
                 )
388
389
boilerplate_conv(HTTPS,
390
                 conv.xfr16BitInt(d_priority);
391
                 conv.xfrName(d_target, false);
392
                 if (d_priority != 0) {
393
                   conv.xfrSvcParamKeyVals(d_params);
394
                 }
395
                 )
396
397
boilerplate_conv(HHIT,
398
                 conv.xfrBlob(d_data);
399
                 )
400
401
boilerplate_conv(BRID,
402
                 conv.xfrBlob(d_data);
403
                 )
404
405
boilerplate_conv(SMIMEA,
406
                 conv.xfr8BitInt(d_certusage);
407
                 conv.xfr8BitInt(d_selector);
408
                 conv.xfr8BitInt(d_matchtype);
409
                 conv.xfrHexBlob(d_cert, true);
410
                 )
411
412
0
DSRecordContent::DSRecordContent() = default;
413
boilerplate_conv(DS,
414
                 conv.xfr16BitInt(d_tag);
415
                 conv.xfr8BitInt(d_algorithm);
416
                 conv.xfr8BitInt(d_digesttype);
417
                 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
418
                 )
419
420
0
CDSRecordContent::CDSRecordContent() = default;
421
boilerplate_conv(CDS,
422
                 conv.xfr16BitInt(d_tag);
423
                 conv.xfr8BitInt(d_algorithm);
424
                 conv.xfr8BitInt(d_digesttype);
425
                 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
426
                 )
427
428
0
DLVRecordContent::DLVRecordContent() = default;
429
boilerplate_conv(DLV,
430
                 conv.xfr16BitInt(d_tag);
431
                 conv.xfr8BitInt(d_algorithm);
432
                 conv.xfr8BitInt(d_digesttype);
433
                 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
434
                 )
435
436
437
boilerplate_conv(SSHFP,
438
                 conv.xfr8BitInt(d_algorithm);
439
                 conv.xfr8BitInt(d_fptype);
440
                 conv.xfrHexBlob(d_fingerprint, true);
441
                 )
442
443
boilerplate_conv(RRSIG,
444
                 conv.xfrType(d_type);
445
                   conv.xfr8BitInt(d_algorithm);
446
                   conv.xfr8BitInt(d_labels);
447
                   conv.xfr32BitInt(d_originalttl);
448
                   conv.xfrTime(d_sigexpire);
449
                   conv.xfrTime(d_siginception);
450
                 conv.xfr16BitInt(d_tag);
451
                 conv.xfrName(d_signer);
452
                 conv.xfrBlob(d_signature);
453
                 )
454
455
0
RRSIGRecordContent::RRSIGRecordContent() = default;
456
457
boilerplate_conv(DNSKEY,
458
                 conv.xfr16BitInt(d_flags);
459
                 conv.xfr8BitInt(d_protocol);
460
                 conv.xfr8BitInt(d_algorithm);
461
                 conv.xfrBlob(d_key);
462
                 )
463
2.34k
DNSKEYRecordContent::DNSKEYRecordContent() = default;
464
465
boilerplate_conv(CDNSKEY,
466
                 conv.xfr16BitInt(d_flags);
467
                 conv.xfr8BitInt(d_protocol);
468
                 conv.xfr8BitInt(d_algorithm);
469
                 conv.xfrBlob(d_key);
470
                 )
471
0
CDNSKEYRecordContent::CDNSKEYRecordContent() = default;
472
473
boilerplate_conv(RKEY,
474
                 conv.xfr16BitInt(d_flags);
475
                 conv.xfr8BitInt(d_protocol);
476
                 conv.xfr8BitInt(d_algorithm);
477
                 conv.xfrBlob(d_key);
478
                 )
479
0
RKEYRecordContent::RKEYRecordContent() = default;
480
481
boilerplate_conv(NID,
482
                 conv.xfr16BitInt(d_preference);
483
                 conv.xfrNodeOrLocatorID(d_node_id);)
484
485
boilerplate_conv(L32,
486
                 conv.xfr16BitInt(d_preference);
487
                 conv.xfrIP(d_locator);)
488
489
boilerplate_conv(L64,
490
                 conv.xfr16BitInt(d_preference);
491
                 conv.xfrNodeOrLocatorID(d_locator);)
492
493
boilerplate_conv(LP,
494
                 conv.xfr16BitInt(d_preference);
495
                 conv.xfrName(d_fqdn, false);)
496
//NOLINTEND
497
498
/* EUI48 start */
499
void EUI48RecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
500
2
{
501
2
  regist(1, QType::EUI48, &make, &make, "EUI48");
502
2
}
503
std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr)
504
792
{
505
792
    if(dr.d_clen!=6)
506
13
      throw MOADNSException("Wrong size for EUI48 record");
507
508
779
    auto ret=std::make_shared<EUI48RecordContent>();
509
779
    pr.copyRecord((uint8_t*) &ret->d_eui48, 6);
510
779
    return ret;
511
792
}
512
std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const string& zone)
513
0
{
514
    // try to parse
515
0
    auto ret=std::make_shared<EUI48RecordContent>();
516
    // format is 6 hex bytes and dashes
517
0
    if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
518
0
           ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2,
519
0
           ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) {
520
0
       throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse");
521
0
    }
522
0
    return ret;
523
0
}
524
void EUI48RecordContent::toPacket(DNSPacketWriter& pw) const
525
0
{
526
0
    string blob(d_eui48, d_eui48+6);
527
0
    pw.xfrBlob(blob);
528
0
}
529
530
string EUI48RecordContent::getZoneRepresentation(bool /* noDot */) const
531
0
{
532
0
    char tmp[18];
533
0
    snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x",
534
0
           d_eui48[0], d_eui48[1], d_eui48[2],
535
0
           d_eui48[3], d_eui48[4], d_eui48[5]);
536
0
    return tmp;
537
0
}
538
539
/* EUI48 end */
540
541
/* EUI64 start */
542
543
void EUI64RecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
544
2
{
545
2
  regist(1, QType::EUI64, &make, &make, "EUI64");
546
2
}
547
std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr)
548
814
{
549
814
    if(dr.d_clen!=8)
550
18
      throw MOADNSException("Wrong size for EUI64 record");
551
552
796
    auto ret=std::make_shared<EUI64RecordContent>();
553
796
    pr.copyRecord((uint8_t*) &ret->d_eui64, 8);
554
796
    return ret;
555
814
}
556
std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const string& zone)
557
0
{
558
    // try to parse
559
0
    auto ret=std::make_shared<EUI64RecordContent>();
560
    // format is 8 hex bytes and dashes
561
0
    if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
562
0
           ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2,
563
0
           ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5,
564
0
           ret->d_eui64+6, ret->d_eui64+7) != 8) {
565
0
       throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse");
566
0
    }
567
0
    return ret;
568
0
}
569
void EUI64RecordContent::toPacket(DNSPacketWriter& pw) const
570
0
{
571
0
    string blob(d_eui64, d_eui64+8);
572
0
    pw.xfrBlob(blob);
573
0
}
574
575
string EUI64RecordContent::getZoneRepresentation(bool /* noDot */) const
576
0
{
577
0
    char tmp[24];
578
0
    snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
579
0
           d_eui64[0], d_eui64[1], d_eui64[2],
580
0
           d_eui64[3], d_eui64[4], d_eui64[5],
581
0
           d_eui64[6], d_eui64[7]);
582
0
    return tmp;
583
0
}
584
585
/* EUI64 end */
586
587
/* APL start */
588
/* https://tools.ietf.org/html/rfc3123 */
589
void APLRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
590
2
{
591
2
  regist(1, QType::APL, &make, &make, "APL");
592
2
}
593
594
// Parse incoming packets (e.g. nsupdate)
595
3.50k
std::shared_ptr<DNSRecordContent> APLRecordContent::make(const DNSRecord &dr, PacketReader& pr) {
596
3.50k
  uint8_t temp;
597
3.50k
  APLRDataElement ard;
598
3.50k
  size_t processed = 0;
599
600
3.50k
  auto ret=std::make_shared<APLRecordContent>();
601
602
7.07k
  while (processed<dr.d_clen) {
603
3.65k
    pr.xfr16BitInt(ard.d_family);
604
3.65k
    pr.xfr8BitInt(ard.d_prefix);
605
3.65k
    pr.xfr8BitInt(temp);
606
3.65k
    ard.d_n = (temp & 128) >> 7;
607
3.65k
    ard.d_afdlength = temp & 127;
608
609
3.65k
    if (ard.d_family == APL_FAMILY_IPV4) {
610
2.04k
      if (ard.d_afdlength > 4) {
611
2
        throw MOADNSException("Invalid IP length for IPv4 APL");
612
2
      }
613
2.04k
      memset(ard.d_ip.d_ip4, 0, sizeof(ard.d_ip.d_ip4));
614
3.01k
      for (u_int i=0; i < ard.d_afdlength; i++)
615
968
        pr.xfr8BitInt(ard.d_ip.d_ip4[i]);
616
2.04k
    } else if (ard.d_family == APL_FAMILY_IPV6) {
617
1.53k
      if (ard.d_afdlength > 16) {
618
5
        throw MOADNSException("Invalid IP length for IPv6 APL");
619
5
      }
620
1.52k
      memset(ard.d_ip.d_ip6, 0, sizeof(ard.d_ip.d_ip6));
621
4.24k
      for (u_int i=0; i < ard.d_afdlength; i++)
622
2.71k
        pr.xfr8BitInt(ard.d_ip.d_ip6[i]);
623
1.52k
    } else
624
71
    throw MOADNSException("Unknown family for APL record");
625
626
3.57k
    processed += 4 + ard.d_afdlength;
627
628
3.57k
    ret->aplrdata.push_back(ard);
629
3.57k
  }
630
631
3.42k
  return ret;
632
3.50k
}
633
634
// Parse a single APL <apitem>
635
0
APLRDataElement APLRecordContent::parseAPLElement(const string& element) {
636
0
  string record;
637
0
  Netmask nm;
638
0
  unsigned int bytes;
639
0
  bool done_trimming;
640
0
  APLRDataElement ard;
641
642
  // Parse the optional leading ! (negate)
643
0
  if (element.at(0) == '!') {
644
0
    ard.d_n = true;
645
0
    record = element.substr(1, element.length()-1);
646
0
  } else {
647
0
    ard.d_n = false;
648
0
    record = element;
649
0
  }
650
651
0
  if (record.find('/') == string::npos) { // Required by RFC section 5
652
0
    throw MOADNSException("Asked to decode '"+element+"' as an APL record, but missing subnet mask");
653
0
  }
654
655
656
0
  if (record.find("1:", 0) == 0) { // IPv4
657
0
    uint32_t v4ip;
658
659
0
    ard.d_family = APL_FAMILY_IPV4;
660
661
    // Ensure that a mask is provided
662
663
    // Read IPv4 string into a Netmask object
664
0
    nm = Netmask(record.substr(2, record.length() - 2));
665
0
    ard.d_prefix = nm.getBits();
666
667
0
    if (nm.getNetwork().isIPv4() == 0)
668
0
      throw MOADNSException("Asked to decode '"+element+"' as an APL v4 record");
669
670
    // Section 4.1 of RFC 3123 (don't send trailing "0" bytes)
671
    // Copy data; using array of bytes since we might end up truncating them in the packet
672
0
    v4ip = ntohl(nm.getNetwork().sin4.sin_addr.s_addr);
673
0
    memset(ard.d_ip.d_ip4, 0, sizeof(ard.d_ip.d_ip4));
674
0
    bytes  = 4; // Start by assuming we'll send 4 bytes
675
0
    done_trimming = false;
676
0
    for (int i=0; i<4; i++) {
677
0
      ard.d_ip.d_ip4[3-i] = (v4ip & 255);
678
      // Remove trailing "0" bytes from packet and update length
679
0
      if ((v4ip & 255) == 0 and !done_trimming) {
680
0
        bytes--;
681
0
      } else {
682
0
        done_trimming = true;
683
0
      }
684
0
      v4ip = v4ip >> 8;
685
0
    }
686
0
    ard.d_afdlength = bytes;
687
688
0
  } else if (record.find("2:", 0) == 0) { // IPv6
689
0
    ard.d_family = APL_FAMILY_IPV6;
690
691
    // Parse IPv6 string into a Netmask object
692
0
    nm = Netmask(record.substr(2, record.length() - 2));
693
0
    ard.d_prefix = nm.getBits();
694
695
0
    if (nm.getNetwork().isIPv6() == 0)
696
0
      throw MOADNSException("Asked to decode '"+element+"' as an APL v6 record");
697
698
    // Section 4.2 of RFC 3123 (don't send trailing "0" bytes)
699
    // Remove trailing "0" bytes from packet and reduce length
700
0
    memset(ard.d_ip.d_ip6, 0, sizeof(ard.d_ip.d_ip6));
701
0
    bytes = 16; // Start by assuming we'll send 16 bytes
702
0
    done_trimming = false;
703
0
    for (int i=0; i<16; i++) {
704
0
      ard.d_ip.d_ip6[15-i] = nm.getNetwork().sin6.sin6_addr.s6_addr[15-i];
705
0
      if (nm.getNetwork().sin6.sin6_addr.s6_addr[15-i] == 0 and !done_trimming) {
706
        // trailing 0 byte, update length
707
0
        bytes--;
708
0
      } else {
709
0
        done_trimming = true;
710
0
      }
711
0
    }
712
0
    ard.d_afdlength = bytes;
713
714
0
  } else {
715
0
      throw MOADNSException("Asked to encode '"+element+"' as an IPv6 APL record but got unknown Address Family");
716
0
  }
717
0
  return ard;
718
719
0
}
720
721
// Parse backend record (0, 1 or more <apitem>)
722
0
std::shared_ptr<DNSRecordContent> APLRecordContent::make(const string& zone) {
723
0
  APLRDataElement ard;
724
0
  vector<string> elements;
725
726
0
  auto ret=std::make_shared<APLRecordContent>();
727
728
0
  boost::split(elements, zone, boost::is_any_of(" "));
729
0
  for (auto & element : elements) {
730
0
    if (!element.empty()) {
731
0
      ard = ret->parseAPLElement(element);
732
0
      ret->aplrdata.push_back(ard);
733
0
    }
734
0
  }
735
0
  return ret;
736
0
}
737
738
739
// DNSRecord to Packet conversion
740
0
void APLRecordContent::toPacket(DNSPacketWriter& pw) const {
741
0
  for (auto & ard : aplrdata) {
742
0
    pw.xfr16BitInt(ard.d_family);
743
0
    pw.xfr8BitInt(ard.d_prefix);
744
0
    pw.xfr8BitInt((ard.d_n << 7) + ard.d_afdlength);
745
0
    if (ard.d_family == APL_FAMILY_IPV4) {
746
0
      for (int i=0; i<ard.d_afdlength; i++) {
747
0
        pw.xfr8BitInt(ard.d_ip.d_ip4[i]);
748
0
      }
749
0
    } else if (ard.d_family == APL_FAMILY_IPV6) {
750
0
      for (int i=0; i<ard.d_afdlength; i++) {
751
0
        pw.xfr8BitInt(ard.d_ip.d_ip6[i]);
752
0
      }
753
0
    }
754
0
  }
755
0
}
756
757
// Decode record into string
758
0
string APLRecordContent::getZoneRepresentation(bool /* noDot */) const {
759
0
  string s_n, s_family, output;
760
0
  ComboAddress ca;
761
0
  Netmask nm;
762
763
0
  output = "";
764
765
0
  for (std::vector<APLRDataElement>::const_iterator ard = aplrdata.begin() ; ard != aplrdata.end(); ++ard) {
766
767
    // Negation flag
768
0
    if (ard->d_n) {
769
0
      s_n = "!";
770
0
    } else {
771
0
      s_n = "";
772
0
    }
773
774
0
    if (ard->d_family == APL_FAMILY_IPV4) { // IPv4
775
0
      s_family = std::to_string(APL_FAMILY_IPV4);
776
0
      ca = ComboAddress();
777
0
      memset(&ca.sin4.sin_addr.s_addr, 0, sizeof(ca.sin4.sin_addr.s_addr));
778
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
779
0
      memcpy(&ca.sin4.sin_addr.s_addr, ard->d_ip.d_ip4, ard->d_afdlength);
780
0
    } else if (ard->d_family == APL_FAMILY_IPV6) { // IPv6
781
0
      s_family = std::to_string(APL_FAMILY_IPV6);
782
0
      ca = ComboAddress();
783
0
      ca.sin4.sin_family = AF_INET6;
784
0
      memset(&ca.sin6.sin6_addr.s6_addr, 0, sizeof(ca.sin6.sin6_addr.s6_addr));
785
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
786
0
      memcpy(&ca.sin6.sin6_addr.s6_addr, ard->d_ip.d_ip6, ard->d_afdlength);
787
0
    } else {
788
0
      throw MOADNSException("Asked to decode APL record but got unknown Address Family");
789
0
    }
790
791
0
    nm = Netmask(ca, ard->d_prefix);
792
793
0
    output += s_n + s_family + ":" + nm.toString();
794
0
    if (std::next(ard) != aplrdata.end())
795
0
      output += " ";
796
0
  }
797
0
  return output;
798
0
}
799
800
/* APL end */
801
802
/* SVCB start */
803
0
bool SVCBBaseRecordContent::autoHint(const SvcParam::SvcParamKey &key) const {
804
0
  auto p = getParamIt(key);
805
0
  if (p == d_params.end()) {
806
0
    return false;
807
0
  }
808
0
  return p->getAutoHint();
809
0
}
810
811
0
void SVCBBaseRecordContent::setHints(const SvcParam::SvcParamKey &key, const std::vector<ComboAddress> &addresses) {
812
0
  auto p = getParamIt(key);
813
0
  if (p == d_params.end()) {
814
0
    return;
815
0
  }
816
817
0
  std::vector<ComboAddress> h;
818
0
  h.reserve(h.size() + addresses.size());
819
0
  h.insert(h.end(), addresses.begin(), addresses.end());
820
821
0
  try {
822
0
    auto newParam = SvcParam(key, std::move(h));
823
0
    d_params.erase(p);
824
0
    d_params.insert(std::move(newParam));
825
0
  } catch (...) {
826
    // XXX maybe we should SERVFAIL instead?
827
0
    return;
828
0
  }
829
0
}
830
831
0
void SVCBBaseRecordContent::removeParam(const SvcParam::SvcParamKey &key) {
832
0
  auto p = getParamIt(key);
833
0
  if (p == d_params.end()) {
834
0
    return;
835
0
  }
836
0
  d_params.erase(p);
837
0
}
838
839
0
bool SVCBBaseRecordContent::hasParams() const {
840
0
  return !d_params.empty();
841
0
}
842
843
0
bool SVCBBaseRecordContent::hasParam(const SvcParam::SvcParamKey &key) const {
844
0
  return getParamIt(key) != d_params.end();
845
0
}
846
847
0
SvcParam SVCBBaseRecordContent::getParam(const SvcParam::SvcParamKey &key) const {
848
0
  auto p = getParamIt(key);
849
0
  if (p == d_params.end()) {
850
0
    throw std::out_of_range("No param with key " + SvcParam::keyToString(key));
851
0
  }
852
0
  return *p;
853
0
}
854
855
0
set<SvcParam>::const_iterator SVCBBaseRecordContent::getParamIt(const SvcParam::SvcParamKey &key) const {
856
0
  return std::find(d_params.begin(), d_params.end(), key);
857
0
}
858
859
std::shared_ptr<SVCBBaseRecordContent> SVCBRecordContent::clone() const
860
0
{
861
0
  return std::shared_ptr<SVCBBaseRecordContent>(std::make_shared<SVCBRecordContent>(*this));
862
0
}
863
864
std::shared_ptr<SVCBBaseRecordContent> HTTPSRecordContent::clone() const
865
0
{
866
0
  return std::shared_ptr<SVCBBaseRecordContent>(std::make_shared<HTTPSRecordContent>(*this));
867
0
}
868
869
/* SVCB end */
870
871
std::shared_ptr<DRIPBaseRecordContent> HHITRecordContent::clone() const
872
0
{
873
0
  return {std::make_shared<HHITRecordContent>(*this)};
874
0
}
875
876
std::shared_ptr<DRIPBaseRecordContent> BRIDRecordContent::clone() const
877
0
{
878
0
  return {std::make_shared<BRIDRecordContent>(*this)};
879
0
}
880
881
//NOLINTBEGIN
882
boilerplate_conv(TKEY,
883
                 conv.xfrName(d_algo);
884
                 conv.xfr32BitInt(d_inception);
885
                 conv.xfr32BitInt(d_expiration);
886
                 conv.xfr16BitInt(d_mode);
887
                 conv.xfr16BitInt(d_error);
888
                 conv.xfr16BitInt(d_keysize);
889
                 if (d_keysize>0) conv.xfrBlobNoSpaces(d_key, d_keysize);
890
                 conv.xfr16BitInt(d_othersize);
891
                 if (d_othersize>0) conv.xfrBlobNoSpaces(d_other, d_othersize);
892
                 )
893
894
boilerplate_conv(URI,
895
                 conv.xfr16BitInt(d_priority);
896
                 conv.xfr16BitInt(d_weight);
897
                 conv.xfrText(d_target, true, false);
898
                 )
899
900
boilerplate_conv(CAA,
901
                 conv.xfr8BitInt(d_flags);
902
                 conv.xfrUnquotedText(d_tag, true);
903
                 conv.xfrText(d_value, true, false); /* no lenField */
904
                )
905
906
boilerplate_conv(RESINFO, conv.xfrText(d_text, true));
907
//NOLINTEND
908
909
static uint16_t makeTag(const std::string& data)
910
0
{
911
0
  const unsigned char* key=(const unsigned char*)data.c_str();
912
0
  unsigned int keysize=data.length();
913
914
0
  unsigned long ac;     /* assumed to be 32 bits or larger */
915
0
  unsigned int i;                /* loop index */
916
917
0
  for ( ac = 0, i = 0; i < keysize; ++i )
918
0
    ac += (i & 1) ? key[i] : key[i] << 8;
919
0
  ac += (ac >> 16) & 0xFFFF;
920
0
  return ac & 0xFFFF;
921
0
}
922
923
uint16_t DNSKEYRecordContent::getTag() const
924
0
{
925
0
  return makeTag(this->serialize(DNSName()));
926
0
}
927
928
929
/*
930
 * Fills `eo` by parsing the EDNS(0) OPT RR (RFC 6891)
931
 */
932
bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo)
933
0
{
934
0
  eo->d_extFlags=0;
935
0
  if(mdp.d_header.arcount && !mdp.d_answers.empty()) {
936
0
    for(const MOADNSParser::answers_t::value_type& val :  mdp.d_answers) {
937
0
      if(val.d_place == DNSResourceRecord::ADDITIONAL && val.d_type == QType::OPT) {
938
0
        eo->d_packetsize=val.d_class;
939
940
0
        EDNS0Record stuff;
941
0
        uint32_t ttl=ntohl(val.d_ttl);
942
0
        static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
943
0
        memcpy(&stuff, &ttl, sizeof(stuff));
944
945
0
        eo->d_extRCode=stuff.extRCode;
946
0
        eo->d_version=stuff.version;
947
0
        eo->d_extFlags = ntohs(stuff.extFlags);
948
0
        auto orc = getRR<OPTRecordContent>(val);
949
0
        if(orc == nullptr)
950
0
          return false;
951
0
        orc->getData(eo->d_options);
952
0
        return true;
953
0
      }
954
0
    }
955
0
  }
956
0
  return false;
957
0
}
958
959
static void reportBasicTypes(const ReportIsOnlyCallableByReportAllTypes& guard)
960
2
{
961
2
  ARecordContent::report(guard);
962
2
  AAAARecordContent::report(guard);
963
2
  NSRecordContent::report(guard);
964
2
  CNAMERecordContent::report(guard);
965
2
  MXRecordContent::report(guard);
966
2
  SOARecordContent::report(guard);
967
2
  SRVRecordContent::report(guard);
968
2
  PTRRecordContent::report(guard);
969
2
  DNSRecordContent::regist(QClass::CHAOS, QType::TXT, &TXTRecordContent::make, &TXTRecordContent::make, "TXT");
970
2
  TXTRecordContent::report(guard);
971
#ifdef HAVE_LUA_RECORDS
972
  LUARecordContent::report(guard);
973
#endif
974
2
  DNSRecordContent::regist(QClass::IN, QType::ANY, nullptr, nullptr, "ANY");
975
2
  DNSRecordContent::regist(QClass::IN, QType::AXFR, nullptr, nullptr, "AXFR");
976
2
  DNSRecordContent::regist(QClass::IN, QType::IXFR, nullptr, nullptr, "IXFR");
977
2
}
978
979
static void reportOtherTypes(const ReportIsOnlyCallableByReportAllTypes& guard)
980
2
{
981
2
   MBRecordContent::report(guard);
982
2
   MGRecordContent::report(guard);
983
2
   MRRecordContent::report(guard);
984
2
   AFSDBRecordContent::report(guard);
985
2
   DNAMERecordContent::report(guard);
986
2
#if !defined(RECURSOR)
987
2
   ALIASRecordContent::report(guard);
988
2
#endif
989
2
   SPFRecordContent::report(guard);
990
2
   NAPTRRecordContent::report(guard);
991
2
   KXRecordContent::report(guard);
992
2
   LOCRecordContent::report(guard);
993
2
   ENTRecordContent::report(guard);
994
2
   HINFORecordContent::report(guard);
995
2
   RPRecordContent::report(guard);
996
2
   KEYRecordContent::report(guard);
997
2
   DNSKEYRecordContent::report(guard);
998
2
   DHCIDRecordContent::report(guard);
999
2
   CDNSKEYRecordContent::report(guard);
1000
2
   RKEYRecordContent::report(guard);
1001
2
   RRSIGRecordContent::report(guard);
1002
2
   DSRecordContent::report(guard);
1003
2
   CDSRecordContent::report(guard);
1004
2
   SSHFPRecordContent::report(guard);
1005
2
   CERTRecordContent::report(guard);
1006
2
   NSECRecordContent::report(guard);
1007
2
   NSEC3RecordContent::report(guard);
1008
2
   NSEC3PARAMRecordContent::report(guard);
1009
2
   TLSARecordContent::report(guard);
1010
2
   SMIMEARecordContent::report(guard);
1011
2
   OPENPGPKEYRecordContent::report(guard);
1012
2
   SVCBRecordContent::report(guard);
1013
2
   HTTPSRecordContent::report(guard);
1014
2
   HHITRecordContent::report(guard);
1015
2
   BRIDRecordContent::report(guard);
1016
2
   DLVRecordContent::report(guard);
1017
2
   DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG");
1018
2
   DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY");
1019
   //TSIGRecordContent::report(guard);
1020
2
   OPTRecordContent::report(guard);
1021
2
   EUI48RecordContent::report(guard);
1022
2
   EUI64RecordContent::report(guard);
1023
2
   MINFORecordContent::report(guard);
1024
2
   URIRecordContent::report(guard);
1025
2
   CAARecordContent::report(guard);
1026
2
   RESINFORecordContent::report(guard);
1027
2
   APLRecordContent::report(guard);
1028
2
   IPSECKEYRecordContent::report(guard);
1029
2
   CSYNCRecordContent::report(guard);
1030
2
   NIDRecordContent::report(guard);
1031
2
   L32RecordContent::report(guard);
1032
2
   L64RecordContent::report(guard);
1033
2
   LPRecordContent::report(guard);
1034
2
   WALLETRecordContent::report(guard);
1035
2
   ZONEMDRecordContent::report(guard);
1036
2
}
1037
1038
struct ReportIsOnlyCallableByReportAllTypes
1039
{
1040
};
1041
1042
void reportAllTypes()
1043
2
{
1044
2
  ReportIsOnlyCallableByReportAllTypes guard;
1045
2
  reportBasicTypes(guard);
1046
2
  reportOtherTypes(guard);
1047
2
  DNSRecordContent::lock();
1048
2
}
1049
1050
ComboAddress getAddr(const DNSRecord& dr, uint16_t defport)
1051
0
{
1052
0
  if (auto a = getRR<ARecordContent>(dr)) {
1053
0
    return a->getCA(defport);
1054
0
  }
1055
0
  else if (auto aaaa = getRR<AAAARecordContent>(dr)) {
1056
0
    return aaaa->getCA(defport);
1057
0
  }
1058
0
  throw std::invalid_argument("not an A or AAAA record");
1059
0
}
1060
1061
/**
1062
 * Check if the DNSNames that should be hostnames, are hostnames
1063
 */
1064
void checkHostnameCorrectness(const DNSResourceRecord& rr, bool allowUnderscore) // NOLINT(readability-identifier-length)
1065
0
{
1066
0
  if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) {
1067
0
    DNSName toCheck;
1068
0
    if (rr.qtype.getCode() == QType::SRV) {
1069
0
      vector<string> parts;
1070
0
      stringtok(parts, rr.getZoneRepresentation());
1071
0
      if (parts.size() == 4) toCheck = DNSName(parts[3]);
1072
0
    } else if (rr.qtype.getCode() == QType::MX) {
1073
0
      vector<string> parts;
1074
0
      stringtok(parts, rr.getZoneRepresentation());
1075
0
      if (parts.size() == 2) toCheck = DNSName(parts[1]);
1076
0
    } else {
1077
0
      toCheck = DNSName(rr.content);
1078
0
    }
1079
1080
0
    if (toCheck.empty()) {
1081
0
      throw std::runtime_error("unable to extract hostname from content");
1082
0
    }
1083
0
    else if ((rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) && toCheck == g_rootdnsname) {
1084
      // allow null MX/SRV
1085
0
    } else if(!toCheck.isHostname(allowUnderscore)) {
1086
0
      throw std::runtime_error(boost::str(boost::format("non-hostname content %s") % toCheck.toString()));
1087
0
    }
1088
0
  }
1089
0
}
1090
1091
vector<pair<uint16_t, string>>::const_iterator EDNSOpts::getFirstOption(uint16_t optionCode) const
1092
0
{
1093
0
  for (auto iter = d_options.cbegin(); iter != d_options.cend(); ++iter) {
1094
0
    if (iter->first == optionCode) {
1095
0
      return iter;
1096
0
    }
1097
0
  }
1098
0
  return d_options.cend();
1099
0
}
1100
1101
#if 0
1102
static struct Reporter
1103
{
1104
  Reporter()
1105
  {
1106
    reportAllTypes();
1107
  }
1108
} reporter __attribute__((init_priority(65535)));
1109
#endif