Coverage Report

Created: 2023-11-19 07:05

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