• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.09
/pdns/dnsrecords.cc
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
void DNSResourceRecord::setContent(const string &cont) {
×
33
  content = cont;
×
34
  switch(qtype.getCode()) {
×
35
    case QType::SRV:
×
36
    case QType::MX:
×
37
      if (content.size() >= 2 && *(content.rbegin()+1) == ' ')
×
38
        return;
×
39
      /* Falls through. */
40
    case QType::CNAME:
×
41
    case QType::DNAME:
×
42
    case QType::NS:
×
43
    case QType::PTR:
×
44
      if (content.size() >= 2 && *(content.rbegin()) == '.')
×
45
        boost::erase_tail(content, 1);
×
46
  }
×
47
}
×
48

49
string DNSResourceRecord::getZoneRepresentation(bool noDot) const {
×
50
  ostringstream ret;
×
51
  vector<string> parts;
×
52
  string last;
×
53

54
  switch(qtype.getCode()) {
×
55
    case QType::SRV:
×
56
    case QType::MX:
×
57
      stringtok(parts, content);
×
58
      if (parts.empty())
×
59
        return "";
×
60
      last = *parts.rbegin();
×
61
      ret << content;
×
62
      if (last == ".")
×
63
        break;
×
64
      if (*(last.rbegin()) != '.' && !noDot)
×
65
        ret << ".";
×
66
      break;
×
67
    case QType::CNAME:
×
68
    case QType::DNAME:
×
69
    case QType::NS:
×
70
    case QType::PTR:
×
71
      ret<<content;
×
72
      if (*(content.rbegin()) != '.' && !noDot)
×
73
        ret<<".";
×
74
      break;
×
75
    default:
×
76
      ret<<content;
×
77
    break;
×
78
  }
×
79
  return ret.str();
×
80
}
×
81

82
bool DNSResourceRecord::operator==(const DNSResourceRecord& rhs)
83
{
×
84
  string lcontent=toLower(content);
×
85
  string rcontent=toLower(rhs.content);
×
86

87
  return
×
88
    std::tie(qname, qtype, lcontent, ttl) ==
×
89
    std::tie(rhs.qname, rhs.qtype, rcontent, rhs.ttl);
×
90
}
×
91

92
boilerplate_conv(A, conv.xfrIP(d_ip));
93

94
ARecordContent::ARecordContent(uint32_t ip)
95
{
×
96
  d_ip = ip;
×
97
}
×
98

99
ARecordContent::ARecordContent(const ComboAddress& ca)
100
{
9,377✔
101
  d_ip = ca.sin4.sin_addr.s_addr;
9,377✔
102
}
9,377✔
103

104
AAAARecordContent::AAAARecordContent(const ComboAddress& ca)
105
{
7,929✔
106
  d_ip6.assign((const char*)ca.sin6.sin6_addr.s6_addr, 16);
7,929✔
107
}
7,929✔
108

109

110

111
ComboAddress ARecordContent::getCA(int port) const
112
{
22,762✔
113
  ComboAddress ret;
22,762✔
114
  ret.sin4.sin_family=AF_INET;
22,762✔
115
  ret.sin4.sin_port=htons(port);
22,762✔
116
  memcpy(&ret.sin4.sin_addr.s_addr, &d_ip, sizeof(ret.sin4.sin_addr.s_addr));
22,762✔
117
  return ret;
22,762✔
118
}
22,762✔
119

120
ComboAddress AAAARecordContent::getCA(int port) const
121
{
595,430✔
122
  ComboAddress ret;
595,430✔
123
  ret.reset();
595,430✔
124

125
  ret.sin4.sin_family=AF_INET6;
595,430✔
126
  ret.sin6.sin6_port = htons(port);
595,430✔
127
  memcpy(&ret.sin6.sin6_addr.s6_addr, d_ip6.c_str(), sizeof(ret.sin6.sin6_addr.s6_addr));
595,430✔
128
  return ret;
595,430✔
129
}
595,430✔
130

131

132
void ARecordContent::doRecordCheck(const DNSRecord& dr)
133
{
416,288✔
134
  if(dr.d_clen!=4)
416,288!
135
    throw MOADNSException("Wrong size for A record ("+std::to_string(dr.d_clen)+")");
×
136
}
416,288✔
137

138
boilerplate_conv(AAAA, conv.xfrIP6(d_ip6); );
139

140
boilerplate_conv(NS, conv.xfrName(d_content, true));
141
boilerplate_conv(PTR, conv.xfrName(d_content, true));
142
boilerplate_conv(CNAME, conv.xfrName(d_content, true));
143
#if !defined(RECURSOR)
144
boilerplate_conv(ALIAS, conv.xfrName(d_content, false));
145
#endif
146
boilerplate_conv(DNAME, conv.xfrName(d_content));
147
boilerplate_conv(MB, conv.xfrName(d_madname, true));
148
boilerplate_conv(MG, conv.xfrName(d_mgmname, true));
149
boilerplate_conv(MR, conv.xfrName(d_alias, true));
150
boilerplate_conv(MINFO, conv.xfrName(d_rmailbx, true); conv.xfrName(d_emailbx, true));
151
boilerplate_conv(TXT, conv.xfrText(d_text, true));
152
#ifdef HAVE_LUA_RECORDS
153
boilerplate_conv(LUA, conv.xfrType(d_type); conv.xfrText(d_code, true));
154
#endif
155
boilerplate_conv(ENT, );
156
boilerplate_conv(SPF, conv.xfrText(d_text, true));
157
boilerplate_conv(HINFO, conv.xfrText(d_cpu);   conv.xfrText(d_host));
158

159
boilerplate_conv(RP,
160
                 conv.xfrName(d_mbox);
161
                 conv.xfrName(d_info)
162
                 );
163

164

165
boilerplate_conv(OPT,
166
                   conv.xfrBlob(d_data)
167
                 );
168

169
#ifdef HAVE_LUA_RECORDS
170

171
bool g_luaRecordInsertWhitespace;
172

173
string LUARecordContent::getCode() const
174
{
175
  // in d_code, series of "part1" "part2"
176
  vector<string> parts;
177
  stringtok(parts, d_code, "\"");
178
  string ret;
179
  if (g_luaRecordInsertWhitespace) { // default before 5.0
×
180
    for(const auto& part : parts) {
×
181
      ret += part;
182
      ret.append(1, ' ');
183
    }
184
  }
185
  else { // default since 5.0
186
    for(const auto& part : parts) {
×
187
      if (part != " ") {
×
188
        ret += part;
189
      }
190
    }
191
  }
192
  return ret;
193
}
194
#endif
195

196
void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options) const
197
{
9,869✔
198
  string::size_type pos=0;
9,869✔
199
  uint16_t code, len;
9,869✔
200
  while(d_data.size() >= 4 + pos) {
9,994✔
201
    code = 256 * (unsigned char)d_data.at(pos) + (unsigned char)d_data.at(pos+1);
125✔
202
    len = 256 * (unsigned char)d_data.at(pos+2) + (unsigned char)d_data.at(pos+3);
125✔
203
    pos+=4;
125✔
204

205
    if(pos + len > d_data.size())
125!
206
      break;
×
207

208
    string field(d_data.c_str() + pos, len);
125✔
209
    pos+=len;
125✔
210
    options.emplace_back(code, std::move(field));
125✔
211
  }
125✔
212
}
9,869✔
213

214
boilerplate_conv(TSIG,
215
                 conv.xfrName(d_algoName);
216
                 conv.xfr48BitInt(d_time);
217
                 conv.xfr16BitInt(d_fudge);
218
                 uint16_t size=d_mac.size();
219
                 conv.xfr16BitInt(size);
220
                 if (size>0) conv.xfrBlobNoSpaces(d_mac, size);
221
                 conv.xfr16BitInt(d_origID);
222
                 conv.xfr16BitInt(d_eRcode);
223
                 size=d_otherData.size();
224
                 conv.xfr16BitInt(size);
225
                 if (size>0) conv.xfrBlobNoSpaces(d_otherData, size);
226
                 );
227

228
MXRecordContent::MXRecordContent(uint16_t preference, DNSName  mxname):  d_preference(preference), d_mxname(std::move(mxname))
229
{
×
230
}
×
231

232
boilerplate_conv(MX,
233
                 conv.xfr16BitInt(d_preference);
234
                 conv.xfrName(d_mxname, true);
235
                 )
236

237
boilerplate_conv(KX,
238
                 conv.xfr16BitInt(d_preference);
239
                 conv.xfrName(d_exchanger, false);
240
                 )
241

242
boilerplate_conv(IPSECKEY,
243
   conv.xfr8BitInt(d_preference);
244
   conv.xfr8BitInt(d_gatewaytype);
245
   conv.xfr8BitInt(d_algorithm);
246

247
   // now we need to determine values
248
   switch(d_gatewaytype) {
249
   case 0: // NO KEY
250
     break;
251
   case 1: // IPv4 GW
252
     conv.xfrIP(d_ip4);
253
     break;
254
   case 2: // IPv6 GW
255
     conv.xfrIP6(d_ip6);
256
     break;
257
   case 3: // DNS label
258
     conv.xfrName(d_gateway, false);
259
     break;
260
   default:
261
     throw MOADNSException("Parsing record content: invalid gateway type");
262
   };
263

264
   switch(d_algorithm) {
265
   case 0:
266
     break;
267
   case 1:
268
   case 2:
269
     conv.xfrBlob(d_publickey);
270
     break;
271
   default:
272
     throw MOADNSException("Parsing record content: invalid algorithm type");
273
   }
274
)
275

276
boilerplate_conv(DHCID,
277
                 conv.xfrBlob(d_content);
278
                 )
279

280

281
boilerplate_conv(AFSDB,
282
                 conv.xfr16BitInt(d_subtype);
283
                 conv.xfrName(d_hostname);
284
                 )
285

286

287
boilerplate_conv(NAPTR,
288
                 conv.xfr16BitInt(d_order);    conv.xfr16BitInt(d_preference);
289
                 conv.xfrText(d_flags);        conv.xfrText(d_services);         conv.xfrText(d_regexp);
290
                 conv.xfrName(d_replacement);
291
                 )
292

293

294
SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, DNSName  target)
295
: d_weight(weight), d_port(port), d_target(std::move(target)), d_preference(preference)
296
{}
×
297

298
boilerplate_conv(SRV,
299
                 conv.xfr16BitInt(d_preference);   conv.xfr16BitInt(d_weight);   conv.xfr16BitInt(d_port);
300
                 conv.xfrName(d_target);
301
                 )
302

303
SOARecordContent::SOARecordContent(DNSName  mname, DNSName  rname, const struct soatimes& st)
304
: d_mname(std::move(mname)), d_rname(std::move(rname)), d_st(st)
305
{
1✔
306
}
1✔
307

308
boilerplate_conv(SOA,
309
                 conv.xfrName(d_mname, true);
310
                 conv.xfrName(d_rname, true);
311
                 conv.xfr32BitInt(d_st.serial);
312
                 conv.xfr32BitInt(d_st.refresh);
313
                 conv.xfr32BitInt(d_st.retry);
314
                 conv.xfr32BitInt(d_st.expire);
315
                 conv.xfr32BitInt(d_st.minimum);
316
                 );
317
#undef KEY
318
boilerplate_conv(KEY,
319
                 conv.xfr16BitInt(d_flags);
320
                 conv.xfr8BitInt(d_protocol);
321
                 conv.xfr8BitInt(d_algorithm);
322
                 conv.xfrBlob(d_certificate);
323
                 );
324

325
boilerplate_conv(ZONEMD,
326
                 conv.xfr32BitInt(d_serial);
327
                 conv.xfr8BitInt(d_scheme);
328
                 conv.xfr8BitInt(d_hashalgo);
329
                 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
330
                 );
331

332
boilerplate_conv(CERT,
333
                 conv.xfr16BitInt(d_type);
334
                 if (d_type == 0) throw MOADNSException("CERT type 0 is reserved");
335

336
                 conv.xfr16BitInt(d_tag);
337
                 conv.xfr8BitInt(d_algorithm);
338
                 conv.xfrBlob(d_certificate);
339
                 )
340

341
boilerplate_conv(TLSA,
342
                 conv.xfr8BitInt(d_certusage);
343
                 conv.xfr8BitInt(d_selector);
344
                 conv.xfr8BitInt(d_matchtype);
345
                 conv.xfrHexBlob(d_cert, true);
346
                 )
347

348
boilerplate_conv(OPENPGPKEY,
349
                 conv.xfrBlob(d_keyring);
350
                 )
351

352
boilerplate_conv(SVCB,
353
                 conv.xfr16BitInt(d_priority);
354
                 conv.xfrName(d_target, false, true);
355
                 if (d_priority != 0) {
356
                   conv.xfrSvcParamKeyVals(d_params);
357
                 }
358
                 )
359

360
boilerplate_conv(HTTPS,
361
                 conv.xfr16BitInt(d_priority);
362
                 conv.xfrName(d_target, false, true);
363
                 if (d_priority != 0) {
364
                   conv.xfrSvcParamKeyVals(d_params);
365
                 }
366
                 )
367

368
boilerplate_conv(SMIMEA,
369
                 conv.xfr8BitInt(d_certusage);
370
                 conv.xfr8BitInt(d_selector);
371
                 conv.xfr8BitInt(d_matchtype);
372
                 conv.xfrHexBlob(d_cert, true);
373
                 )
374

375
DSRecordContent::DSRecordContent() = default;
4,945✔
376
boilerplate_conv(DS,
377
                 conv.xfr16BitInt(d_tag);
378
                 conv.xfr8BitInt(d_algorithm);
379
                 conv.xfr8BitInt(d_digesttype);
380
                 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
381
                 )
382

383
CDSRecordContent::CDSRecordContent() = default;
×
384
boilerplate_conv(CDS,
385
                 conv.xfr16BitInt(d_tag);
386
                 conv.xfr8BitInt(d_algorithm);
387
                 conv.xfr8BitInt(d_digesttype);
388
                 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
389
                 )
390

391
DLVRecordContent::DLVRecordContent() = default;
×
392
boilerplate_conv(DLV,
393
                 conv.xfr16BitInt(d_tag);
394
                 conv.xfr8BitInt(d_algorithm);
395
                 conv.xfr8BitInt(d_digesttype);
396
                 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
397
                 )
398

399

400
boilerplate_conv(SSHFP,
401
                 conv.xfr8BitInt(d_algorithm);
402
                 conv.xfr8BitInt(d_fptype);
403
                 conv.xfrHexBlob(d_fingerprint, true);
404
                 )
405

406
boilerplate_conv(RRSIG,
407
                 conv.xfrType(d_type);
408
                   conv.xfr8BitInt(d_algorithm);
409
                   conv.xfr8BitInt(d_labels);
410
                   conv.xfr32BitInt(d_originalttl);
411
                   conv.xfrTime(d_sigexpire);
412
                   conv.xfrTime(d_siginception);
413
                 conv.xfr16BitInt(d_tag);
414
                 conv.xfrName(d_signer);
415
                 conv.xfrBlob(d_signature);
416
                 )
417

418
RRSIGRecordContent::RRSIGRecordContent() = default;
20,591✔
419

420
boilerplate_conv(DNSKEY,
421
                 conv.xfr16BitInt(d_flags);
422
                 conv.xfr8BitInt(d_protocol);
423
                 conv.xfr8BitInt(d_algorithm);
424
                 conv.xfrBlob(d_key);
425
                 )
426
DNSKEYRecordContent::DNSKEYRecordContent() = default;
2,316✔
427

428
boilerplate_conv(CDNSKEY,
429
                 conv.xfr16BitInt(d_flags);
430
                 conv.xfr8BitInt(d_protocol);
431
                 conv.xfr8BitInt(d_algorithm);
432
                 conv.xfrBlob(d_key);
433
                 )
434
CDNSKEYRecordContent::CDNSKEYRecordContent() = default;
×
435

436
boilerplate_conv(RKEY,
437
                 conv.xfr16BitInt(d_flags);
438
                 conv.xfr8BitInt(d_protocol);
439
                 conv.xfr8BitInt(d_algorithm);
440
                 conv.xfrBlob(d_key);
441
                 )
442
RKEYRecordContent::RKEYRecordContent() = default;
×
443

444
boilerplate_conv(NID,
445
                 conv.xfr16BitInt(d_preference);
446
                 conv.xfrNodeOrLocatorID(d_node_id);)
447

448
boilerplate_conv(L32,
449
                 conv.xfr16BitInt(d_preference);
450
                 conv.xfrIP(d_locator);)
451

452
boilerplate_conv(L64,
453
                 conv.xfr16BitInt(d_preference);
454
                 conv.xfrNodeOrLocatorID(d_locator);)
455

456
boilerplate_conv(LP,
457
                 conv.xfr16BitInt(d_preference);
458
                 conv.xfrName(d_fqdn, false);)
459

460
/* EUI48 start */
461
void EUI48RecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
462
{
164✔
463
  regist(1, QType::EUI48, &make, &make, "EUI48");
164✔
464
}
164✔
465
std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr)
466
{
3✔
467
    if(dr.d_clen!=6)
3!
468
      throw MOADNSException("Wrong size for EUI48 record");
×
469

470
    auto ret=std::make_shared<EUI48RecordContent>();
3✔
471
    pr.copyRecord((uint8_t*) &ret->d_eui48, 6);
3✔
472
    return ret;
3✔
473
}
3✔
474
std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const string& zone)
475
{
21✔
476
    // try to parse
477
    auto ret=std::make_shared<EUI48RecordContent>();
21✔
478
    // format is 6 hex bytes and dashes
479
    if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
21✔
480
           ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2,
21✔
481
           ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) {
21✔
482
       throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse");
3✔
483
    }
3✔
484
    return ret;
18✔
485
}
21✔
486
void EUI48RecordContent::toPacket(DNSPacketWriter& pw) const
487
{
3✔
488
    string blob(d_eui48, d_eui48+6);
3✔
489
    pw.xfrBlob(blob);
3✔
490
}
3✔
491

492
string EUI48RecordContent::getZoneRepresentation(bool /* noDot */) const
493
{
8✔
494
    char tmp[18];
8✔
495
    snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x",
8✔
496
           d_eui48[0], d_eui48[1], d_eui48[2],
8✔
497
           d_eui48[3], d_eui48[4], d_eui48[5]);
8✔
498
    return tmp;
8✔
499
}
8✔
500

501
/* EUI48 end */
502

503
/* EUI64 start */
504

505
void EUI64RecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
506
{
164✔
507
  regist(1, QType::EUI64, &make, &make, "EUI64");
164✔
508
}
164✔
509
std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr)
510
{
3✔
511
    if(dr.d_clen!=8)
3!
512
      throw MOADNSException("Wrong size for EUI64 record");
×
513

514
    auto ret=std::make_shared<EUI64RecordContent>();
3✔
515
    pr.copyRecord((uint8_t*) &ret->d_eui64, 8);
3✔
516
    return ret;
3✔
517
}
3✔
518
std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const string& zone)
519
{
21✔
520
    // try to parse
521
    auto ret=std::make_shared<EUI64RecordContent>();
21✔
522
    // format is 8 hex bytes and dashes
523
    if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
21✔
524
           ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2,
21✔
525
           ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5,
21✔
526
           ret->d_eui64+6, ret->d_eui64+7) != 8) {
21✔
527
       throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse");
3✔
528
    }
3✔
529
    return ret;
18✔
530
}
21✔
531
void EUI64RecordContent::toPacket(DNSPacketWriter& pw) const
532
{
3✔
533
    string blob(d_eui64, d_eui64+8);
3✔
534
    pw.xfrBlob(blob);
3✔
535
}
3✔
536

537
string EUI64RecordContent::getZoneRepresentation(bool /* noDot */) const
538
{
8✔
539
    char tmp[24];
8✔
540
    snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
8✔
541
           d_eui64[0], d_eui64[1], d_eui64[2],
8✔
542
           d_eui64[3], d_eui64[4], d_eui64[5],
8✔
543
           d_eui64[6], d_eui64[7]);
8✔
544
    return tmp;
8✔
545
}
8✔
546

547
/* EUI64 end */
548

549
/* APL start */
550
/* https://tools.ietf.org/html/rfc3123 */
551
void APLRecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */)
552
{
164✔
553
  regist(1, QType::APL, &make, &make, "APL");
164✔
554
}
164✔
555

556
// Parse incoming packets (e.g. nsupdate)
557
std::shared_ptr<DNSRecordContent> APLRecordContent::make(const DNSRecord &dr, PacketReader& pr) {
66✔
558
  uint8_t temp;
66✔
559
  APLRDataElement ard;
66✔
560
  size_t processed = 0;
66✔
561

562
  auto ret=std::make_shared<APLRecordContent>();
66✔
563

564
  while (processed<dr.d_clen) {
135✔
565
    pr.xfr16BitInt(ard.d_family);
69✔
566
    pr.xfr8BitInt(ard.d_prefix);
69✔
567
    pr.xfr8BitInt(temp);
69✔
568
    ard.d_n = (temp & 128) >> 7;
69✔
569
    ard.d_afdlength = temp & 127;
69✔
570

571
    if (ard.d_family == APL_FAMILY_IPV4) {
69✔
572
      if (ard.d_afdlength > 4) {
30!
573
        throw MOADNSException("Invalid IP length for IPv4 APL");
×
574
      }
×
575
      memset(ard.d_ip.d_ip4, 0, sizeof(ard.d_ip.d_ip4));
30✔
576
      for (u_int i=0; i < ard.d_afdlength; i++)
111✔
577
        pr.xfr8BitInt(ard.d_ip.d_ip4[i]);
81✔
578
    } else if (ard.d_family == APL_FAMILY_IPV6) {
39!
579
      if (ard.d_afdlength > 16) {
39!
580
        throw MOADNSException("Invalid IP length for IPv6 APL");
×
581
      }
×
582
      memset(ard.d_ip.d_ip6, 0, sizeof(ard.d_ip.d_ip6));
39✔
583
      for (u_int i=0; i < ard.d_afdlength; i++)
327✔
584
        pr.xfr8BitInt(ard.d_ip.d_ip6[i]);
288✔
585
    } else
39✔
586
    throw MOADNSException("Unknown family for APL record");
×
587

588
    processed += 4 + ard.d_afdlength;
69✔
589

590
    ret->aplrdata.push_back(ard);
69✔
591
  }
69✔
592

593
  return ret;
66✔
594
}
66✔
595

596
// Parse a single APL <apitem>
597
APLRDataElement APLRecordContent::parseAPLElement(const string& element) {
69✔
598
  string record;
69✔
599
  Netmask nm;
69✔
600
  unsigned int bytes;
69✔
601
  bool done_trimming;
69✔
602
  APLRDataElement ard;
69✔
603

604
  // Parse the optional leading ! (negate)
605
  if (element.at(0) == '!') {
69✔
606
    ard.d_n = true;
6✔
607
    record = element.substr(1, element.length()-1);
6✔
608
  } else {
63✔
609
    ard.d_n = false;
63✔
610
    record = element;
63✔
611
  }
63✔
612

613
  if (record.find('/') == string::npos) { // Required by RFC section 5
69!
614
    throw MOADNSException("Asked to decode '"+element+"' as an APL record, but missing subnet mask");
×
615
  }
×
616

617

618
  if (record.find("1:", 0) == 0) { // IPv4
69✔
619
    uint32_t v4ip;
30✔
620

621
    ard.d_family = APL_FAMILY_IPV4;
30✔
622

623
    // Ensure that a mask is provided
624

625
    // Read IPv4 string into a Netmask object
626
    nm = Netmask(record.substr(2, record.length() - 2));
30✔
627
    ard.d_prefix = nm.getBits();
30✔
628

629
    if (nm.getNetwork().isIPv4() == 0)
30!
630
      throw MOADNSException("Asked to decode '"+element+"' as an APL v4 record");
×
631

632
    // Section 4.1 of RFC 3123 (don't send trailing "0" bytes)
633
    // Copy data; using array of bytes since we might end up truncating them in the packet
634
    v4ip = ntohl(nm.getNetwork().sin4.sin_addr.s_addr);
30✔
635
    memset(ard.d_ip.d_ip4, 0, sizeof(ard.d_ip.d_ip4));
30✔
636
    bytes  = 4; // Start by assuming we'll send 4 bytes
30✔
637
    done_trimming = false;
30✔
638
    for (int i=0; i<4; i++) {
150✔
639
      ard.d_ip.d_ip4[3-i] = (v4ip & 255);
120✔
640
      // Remove trailing "0" bytes from packet and update length
641
      if ((v4ip & 255) == 0 and !done_trimming) {
120!
642
        bytes--;
39✔
643
      } else {
81✔
644
        done_trimming = true;
81✔
645
      }
81✔
646
      v4ip = v4ip >> 8;
120✔
647
    }
120✔
648
    ard.d_afdlength = bytes;
30✔
649

650
  } else if (record.find("2:", 0) == 0) { // IPv6
39!
651
    ard.d_family = APL_FAMILY_IPV6;
39✔
652

653
    // Parse IPv6 string into a Netmask object
654
    nm = Netmask(record.substr(2, record.length() - 2));
39✔
655
    ard.d_prefix = nm.getBits();
39✔
656

657
    if (nm.getNetwork().isIPv6() == 0)
39!
658
      throw MOADNSException("Asked to decode '"+element+"' as an APL v6 record");
×
659

660
    // Section 4.2 of RFC 3123 (don't send trailing "0" bytes)
661
    // Remove trailing "0" bytes from packet and reduce length
662
    memset(ard.d_ip.d_ip6, 0, sizeof(ard.d_ip.d_ip6));
39✔
663
    bytes = 16; // Start by assuming we'll send 16 bytes
39✔
664
    done_trimming = false;
39✔
665
    for (int i=0; i<16; i++) {
663✔
666
      ard.d_ip.d_ip6[15-i] = nm.getNetwork().sin6.sin6_addr.s6_addr[15-i];
624✔
667
      if (nm.getNetwork().sin6.sin6_addr.s6_addr[15-i] == 0 and !done_trimming) {
624✔
668
        // trailing 0 byte, update length
669
        bytes--;
336✔
670
      } else {
336✔
671
        done_trimming = true;
288✔
672
      }
288✔
673
    }
624✔
674
    ard.d_afdlength = bytes;
39✔
675

676
  } else {
39✔
677
      throw MOADNSException("Asked to encode '"+element+"' as an IPv6 APL record but got unknown Address Family");
×
678
  }
×
679
  return ard;
69✔
680

681
}
69✔
682

683
// Parse backend record (0, 1 or more <apitem>)
684
std::shared_ptr<DNSRecordContent> APLRecordContent::make(const string& zone) {
66✔
685
  APLRDataElement ard;
66✔
686
  vector<string> elements;
66✔
687

688
  auto ret=std::make_shared<APLRecordContent>();
66✔
689

690
  boost::split(elements, zone, boost::is_any_of(" "));
66✔
691
  for (auto & element : elements) {
72✔
692
    if (!element.empty()) {
72✔
693
      ard = ret->parseAPLElement(element);
69✔
694
      ret->aplrdata.push_back(ard);
69✔
695
    }
69✔
696
  }
72✔
697
  return ret;
66✔
698
}
66✔
699

700

701
// DNSRecord to Packet conversion
702
void APLRecordContent::toPacket(DNSPacketWriter& pw) const {
66✔
703
  for (auto & ard : aplrdata) {
69✔
704
    pw.xfr16BitInt(ard.d_family);
69✔
705
    pw.xfr8BitInt(ard.d_prefix);
69✔
706
    pw.xfr8BitInt((ard.d_n << 7) + ard.d_afdlength);
69✔
707
    if (ard.d_family == APL_FAMILY_IPV4) {
69✔
708
      for (int i=0; i<ard.d_afdlength; i++) {
111✔
709
        pw.xfr8BitInt(ard.d_ip.d_ip4[i]);
81✔
710
      }
81✔
711
    } else if (ard.d_family == APL_FAMILY_IPV6) {
39!
712
      for (int i=0; i<ard.d_afdlength; i++) {
327✔
713
        pw.xfr8BitInt(ard.d_ip.d_ip6[i]);
288✔
714
      }
288✔
715
    }
39✔
716
  }
69✔
717
}
66✔
718

719
// Decode record into string
720
string APLRecordContent::getZoneRepresentation(bool /* noDot */) const {
132✔
721
  string s_n, s_family, output;
132✔
722
  ComboAddress ca;
132✔
723
  Netmask nm;
132✔
724

725
  output = "";
132✔
726

727
  for (std::vector<APLRDataElement>::const_iterator ard = aplrdata.begin() ; ard != aplrdata.end(); ++ard) {
270✔
728

729
    // Negation flag
730
    if (ard->d_n) {
138✔
731
      s_n = "!";
12✔
732
    } else {
126✔
733
      s_n = "";
126✔
734
    }
126✔
735

736
    if (ard->d_family == APL_FAMILY_IPV4) { // IPv4
138✔
737
      s_family = std::to_string(APL_FAMILY_IPV4);
60✔
738
      ca = ComboAddress();
60✔
739
      memcpy(&ca.sin4.sin_addr.s_addr, ard->d_ip.d_ip4, sizeof(ca.sin4.sin_addr.s_addr));
60✔
740
    } else if (ard->d_family == APL_FAMILY_IPV6) { // IPv6
78!
741
      s_family = std::to_string(APL_FAMILY_IPV6);
78✔
742
      ca = ComboAddress();
78✔
743
      ca.sin4.sin_family = AF_INET6;
78✔
744
      memset(&ca.sin6.sin6_addr.s6_addr, 0, sizeof(ca.sin6.sin6_addr.s6_addr));
78✔
745
      memcpy(&ca.sin6.sin6_addr.s6_addr, ard->d_ip.d_ip6, ard->d_afdlength);
78✔
746
    } else {
78✔
747
      throw MOADNSException("Asked to decode APL record but got unknown Address Family");
×
748
    }
×
749

750
    nm = Netmask(ca, ard->d_prefix);
138✔
751

752
    output += s_n + s_family + ":" + nm.toString();
138✔
753
    if (std::next(ard) != aplrdata.end())
138✔
754
      output += " ";
12✔
755
  }
138✔
756
  return output;
132✔
757
}
132✔
758

759
/* APL end */
760

761
/* SVCB start */
762
bool SVCBBaseRecordContent::autoHint(const SvcParam::SvcParamKey &key) const {
×
763
  auto p = getParamIt(key);
×
764
  if (p == d_params.end()) {
×
765
    return false;
×
766
  }
×
767
  return p->getAutoHint();
×
768
}
×
769

770
void SVCBBaseRecordContent::setHints(const SvcParam::SvcParamKey &key, const std::vector<ComboAddress> &addresses) {
×
771
  auto p = getParamIt(key);
×
772
  if (p == d_params.end()) {
×
773
    return;
×
774
  }
×
775

776
  std::vector<ComboAddress> h;
×
777
  h.reserve(h.size() + addresses.size());
×
778
  h.insert(h.end(), addresses.begin(), addresses.end());
×
779

780
  try {
×
781
    auto newParam = SvcParam(key, std::move(h));
×
782
    d_params.erase(p);
×
783
    d_params.insert(newParam);
×
784
  } catch (...) {
×
785
    // XXX maybe we should SERVFAIL instead?
786
    return;
×
787
  }
×
788
}
×
789

790
void SVCBBaseRecordContent::removeParam(const SvcParam::SvcParamKey &key) {
×
791
  auto p = getParamIt(key);
×
792
  if (p == d_params.end()) {
×
793
    return;
×
794
  }
×
795
  d_params.erase(p);
×
796
}
×
797

798
bool SVCBBaseRecordContent::hasParams() const {
×
799
  return !d_params.empty();
×
800
}
×
801

802
bool SVCBBaseRecordContent::hasParam(const SvcParam::SvcParamKey &key) const {
×
803
  return getParamIt(key) != d_params.end();
×
804
}
×
805

806
SvcParam SVCBBaseRecordContent::getParam(const SvcParam::SvcParamKey &key) const {
×
807
  auto p = getParamIt(key);
×
808
  if (p == d_params.end()) {
×
809
    throw std::out_of_range("No param with key " + SvcParam::keyToString(key));
×
810
  }
×
811
  return *p;
×
812
}
×
813

814
set<SvcParam>::const_iterator SVCBBaseRecordContent::getParamIt(const SvcParam::SvcParamKey &key) const {
×
815
  auto p = std::find_if(d_params.begin(), d_params.end(),
×
816
      [&key](const SvcParam &param) {
×
817
        return param.getKey() == key;
×
818
      });
×
819
  return p;
×
820
}
×
821

822
std::shared_ptr<SVCBBaseRecordContent> SVCBRecordContent::clone() const
823
{
×
824
  return std::shared_ptr<SVCBBaseRecordContent>(std::make_shared<SVCBRecordContent>(*this));
×
825
}
×
826

827
std::shared_ptr<SVCBBaseRecordContent> HTTPSRecordContent::clone() const
828
{
×
829
  return std::shared_ptr<SVCBBaseRecordContent>(std::make_shared<HTTPSRecordContent>(*this));
×
830
}
×
831

832
/* SVCB end */
833

834
boilerplate_conv(TKEY,
835
                 conv.xfrName(d_algo);
836
                 conv.xfr32BitInt(d_inception);
837
                 conv.xfr32BitInt(d_expiration);
838
                 conv.xfr16BitInt(d_mode);
839
                 conv.xfr16BitInt(d_error);
840
                 conv.xfr16BitInt(d_keysize);
841
                 if (d_keysize>0) conv.xfrBlobNoSpaces(d_key, d_keysize);
842
                 conv.xfr16BitInt(d_othersize);
843
                 if (d_othersize>0) conv.xfrBlobNoSpaces(d_other, d_othersize);
844
                 )
845
TKEYRecordContent::TKEYRecordContent() { d_othersize = 0; } // fix CID#1288932
×
846

847
boilerplate_conv(URI,
848
                 conv.xfr16BitInt(d_priority);
849
                 conv.xfr16BitInt(d_weight);
850
                 conv.xfrText(d_target, true, false);
851
                 )
852

853
boilerplate_conv(CAA,
854
                 conv.xfr8BitInt(d_flags);
855
                 conv.xfrUnquotedText(d_tag, true);
856
                 conv.xfrText(d_value, true, false); /* no lenField */
857
                )
858

859
static uint16_t makeTag(const std::string& data)
860
{
13,003✔
861
  const unsigned char* key=(const unsigned char*)data.c_str();
13,003✔
862
  unsigned int keysize=data.length();
13,003✔
863

864
  unsigned long ac;     /* assumed to be 32 bits or larger */
13,003✔
865
  unsigned int i;                /* loop index */
13,003✔
866

867
  for ( ac = 0, i = 0; i < keysize; ++i )
1,122,674✔
868
    ac += (i & 1) ? key[i] : key[i] << 8;
1,109,671✔
869
  ac += (ac >> 16) & 0xFFFF;
13,003✔
870
  return ac & 0xFFFF;
13,003✔
871
}
13,003✔
872

873
uint16_t DNSKEYRecordContent::getTag() const
874
{
13,003✔
875
  return makeTag(this->serialize(DNSName()));
13,003✔
876
}
13,003✔
877

878

879
/*
880
 * Fills `eo` by parsing the EDNS(0) OPT RR (RFC 6891)
881
 */
882
bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo)
883
{
1,208,410✔
884
  eo->d_extFlags=0;
1,208,410✔
885
  if(mdp.d_header.arcount && !mdp.d_answers.empty()) {
1,208,410✔
886
    for(const MOADNSParser::answers_t::value_type& val :  mdp.d_answers) {
53,890✔
887
      if(val.d_place == DNSResourceRecord::ADDITIONAL && val.d_type == QType::OPT) {
53,890✔
888
        eo->d_packetsize=val.d_class;
9,868✔
889

890
        EDNS0Record stuff;
9,868✔
891
        uint32_t ttl=ntohl(val.d_ttl);
9,868✔
892
        static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
9,868✔
893
        memcpy(&stuff, &ttl, sizeof(stuff));
9,868✔
894

895
        eo->d_extRCode=stuff.extRCode;
9,868✔
896
        eo->d_version=stuff.version;
9,868✔
897
        eo->d_extFlags = ntohs(stuff.extFlags);
9,868✔
898
        auto orc = getRR<OPTRecordContent>(val);
9,868✔
899
        if(orc == nullptr)
9,868!
900
          return false;
×
901
        orc->getData(eo->d_options);
9,868✔
902
        return true;
9,868✔
903
      }
9,868✔
904
    }
53,890✔
905
  }
9,869✔
906
  return false;
1,198,542✔
907
}
1,208,410✔
908

909
static void reportBasicTypes(const ReportIsOnlyCallableByReportAllTypes& guard)
910
{
164✔
911
  ARecordContent::report(guard);
164✔
912
  AAAARecordContent::report(guard);
164✔
913
  NSRecordContent::report(guard);
164✔
914
  CNAMERecordContent::report(guard);
164✔
915
  MXRecordContent::report(guard);
164✔
916
  SOARecordContent::report(guard);
164✔
917
  SRVRecordContent::report(guard);
164✔
918
  PTRRecordContent::report(guard);
164✔
919
  DNSRecordContent::regist(QClass::CHAOS, QType::TXT, &TXTRecordContent::make, &TXTRecordContent::make, "TXT");
164✔
920
  TXTRecordContent::report(guard);
164✔
921
#ifdef HAVE_LUA_RECORDS
5✔
922
  LUARecordContent::report(guard);
5✔
923
#endif
5✔
924
  DNSRecordContent::regist(QClass::IN, QType::ANY, nullptr, nullptr, "ANY");
164✔
925
  DNSRecordContent::regist(QClass::IN, QType::AXFR, nullptr, nullptr, "AXFR");
164✔
926
  DNSRecordContent::regist(QClass::IN, QType::IXFR, nullptr, nullptr, "IXFR");
164✔
927
}
164✔
928

929
static void reportOtherTypes(const ReportIsOnlyCallableByReportAllTypes& guard)
930
{
164✔
931
   MBRecordContent::report(guard);
164✔
932
   MGRecordContent::report(guard);
164✔
933
   MRRecordContent::report(guard);
164✔
934
   AFSDBRecordContent::report(guard);
164✔
935
   DNAMERecordContent::report(guard);
164✔
936
#if !defined(RECURSOR)
5✔
937
   ALIASRecordContent::report(guard);
5✔
938
#endif
5✔
939
   SPFRecordContent::report(guard);
164✔
940
   NAPTRRecordContent::report(guard);
164✔
941
   KXRecordContent::report(guard);
164✔
942
   LOCRecordContent::report(guard);
164✔
943
   ENTRecordContent::report(guard);
164✔
944
   HINFORecordContent::report(guard);
164✔
945
   RPRecordContent::report(guard);
164✔
946
   KEYRecordContent::report(guard);
164✔
947
   DNSKEYRecordContent::report(guard);
164✔
948
   DHCIDRecordContent::report(guard);
164✔
949
   CDNSKEYRecordContent::report(guard);
164✔
950
   RKEYRecordContent::report(guard);
164✔
951
   RRSIGRecordContent::report(guard);
164✔
952
   DSRecordContent::report(guard);
164✔
953
   CDSRecordContent::report(guard);
164✔
954
   SSHFPRecordContent::report(guard);
164✔
955
   CERTRecordContent::report(guard);
164✔
956
   NSECRecordContent::report(guard);
164✔
957
   NSEC3RecordContent::report(guard);
164✔
958
   NSEC3PARAMRecordContent::report(guard);
164✔
959
   TLSARecordContent::report(guard);
164✔
960
   SMIMEARecordContent::report(guard);
164✔
961
   OPENPGPKEYRecordContent::report(guard);
164✔
962
   SVCBRecordContent::report(guard);
164✔
963
   HTTPSRecordContent::report(guard);
164✔
964
   DLVRecordContent::report(guard);
164✔
965
   DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG");
164✔
966
   DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY");
164✔
967
   //TSIGRecordContent::report(guard);
968
   OPTRecordContent::report(guard);
164✔
969
   EUI48RecordContent::report(guard);
164✔
970
   EUI64RecordContent::report(guard);
164✔
971
   MINFORecordContent::report(guard);
164✔
972
   URIRecordContent::report(guard);
164✔
973
   CAARecordContent::report(guard);
164✔
974
   APLRecordContent::report(guard);
164✔
975
   IPSECKEYRecordContent::report(guard);
164✔
976
   CSYNCRecordContent::report(guard);
164✔
977
   NIDRecordContent::report(guard);
164✔
978
   L32RecordContent::report(guard);
164✔
979
   L64RecordContent::report(guard);
164✔
980
   LPRecordContent::report(guard);
164✔
981
   ZONEMDRecordContent::report(guard);
164✔
982
}
164✔
983

984
struct ReportIsOnlyCallableByReportAllTypes
985
{
986
};
987

988
void reportAllTypes()
989
{
164✔
990
  ReportIsOnlyCallableByReportAllTypes guard;
164✔
991
  reportBasicTypes(guard);
164✔
992
  reportOtherTypes(guard);
164✔
993
  DNSRecordContent::lock();
164✔
994
}
164✔
995

996
ComboAddress getAddr(const DNSRecord& dr, uint16_t defport)
997
{
6✔
998
  if (auto a = getRR<ARecordContent>(dr)) {
6!
999
    return a->getCA(defport);
6✔
1000
  }
6✔
1001
  else if (auto aaaa = getRR<AAAARecordContent>(dr)) {
×
1002
    return aaaa->getCA(defport);
×
1003
  }
×
1004
  throw std::invalid_argument("not an A or AAAA record");
×
1005
}
6✔
1006

1007
/**
1008
 * Check if the DNSNames that should be hostnames, are hostnames
1009
 */
1010
void checkHostnameCorrectness(const DNSResourceRecord& rr)
1011
{
×
1012
  if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) {
×
1013
    DNSName toCheck;
×
1014
    if (rr.qtype.getCode() == QType::SRV) {
×
1015
      vector<string> parts;
×
1016
      stringtok(parts, rr.getZoneRepresentation());
×
1017
      if (parts.size() == 4) toCheck = DNSName(parts[3]);
×
1018
    } else if (rr.qtype.getCode() == QType::MX) {
×
1019
      vector<string> parts;
×
1020
      stringtok(parts, rr.getZoneRepresentation());
×
1021
      if (parts.size() == 2) toCheck = DNSName(parts[1]);
×
1022
    } else {
×
1023
      toCheck = DNSName(rr.content);
×
1024
    }
×
1025

1026
    if (toCheck.empty()) {
×
1027
      throw std::runtime_error("unable to extract hostname from content");
×
1028
    }
×
1029
    else if ((rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) && toCheck == g_rootdnsname) {
×
1030
      // allow null MX/SRV
1031
    } else if(!toCheck.isHostname()) {
×
1032
      throw std::runtime_error(boost::str(boost::format("non-hostname content %s") % toCheck.toString()));
×
1033
    }
×
1034
  }
×
1035
}
×
1036

1037
#if 0
1038
static struct Reporter
1039
{
1040
  Reporter()
1041
  {
1042
    reportAllTypes();
1043
  }
1044
} reporter __attribute__((init_priority(65535)));
1045
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc