]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsrecords.cc
rec: mention rust compiler in compiling docs
[thirdparty/pdns.git] / 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 {
101 d_ip = ca.sin4.sin_addr.s_addr;
102 }
103
104 AAAARecordContent::AAAARecordContent(const ComboAddress& ca)
105 {
106 d_ip6.assign((const char*)ca.sin6.sin6_addr.s6_addr, 16);
107 }
108
109
110
111 ComboAddress ARecordContent::getCA(int port) const
112 {
113 ComboAddress ret;
114 ret.sin4.sin_family=AF_INET;
115 ret.sin4.sin_port=htons(port);
116 memcpy(&ret.sin4.sin_addr.s_addr, &d_ip, sizeof(ret.sin4.sin_addr.s_addr));
117 return ret;
118 }
119
120 ComboAddress AAAARecordContent::getCA(int port) const
121 {
122 ComboAddress ret;
123 ret.reset();
124
125 ret.sin4.sin_family=AF_INET6;
126 ret.sin6.sin6_port = htons(port);
127 memcpy(&ret.sin6.sin6_addr.s6_addr, d_ip6.c_str(), sizeof(ret.sin6.sin6_addr.s6_addr));
128 return ret;
129 }
130
131
132 void ARecordContent::doRecordCheck(const DNSRecord& dr)
133 {
134 if(dr.d_clen!=4)
135 throw MOADNSException("Wrong size for A record ("+std::to_string(dr.d_clen)+")");
136 }
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 {
186 string::size_type pos=0;
187 uint16_t code, len;
188 while(d_data.size() >= 4 + pos) {
189 code = 256 * (unsigned char)d_data.at(pos) + (unsigned char)d_data.at(pos+1);
190 len = 256 * (unsigned char)d_data.at(pos+2) + (unsigned char)d_data.at(pos+3);
191 pos+=4;
192
193 if(pos + len > d_data.size())
194 break;
195
196 string field(d_data.c_str() + pos, len);
197 pos+=len;
198 options.emplace_back(code, std::move(field));
199 }
200 }
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 {
218 }
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 {}
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 {
294 }
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 DSRecordContent::DSRecordContent() = default;
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 CDSRecordContent::CDSRecordContent() = default;
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 DLVRecordContent::DLVRecordContent() = default;
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 RRSIGRecordContent::RRSIGRecordContent() = default;
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 DNSKEYRecordContent::DNSKEYRecordContent() = default;
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 CDNSKEYRecordContent::CDNSKEYRecordContent() = default;
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 RKEYRecordContent::RKEYRecordContent() = default;
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 {
451 regist(1, QType::EUI48, &make, &make, "EUI48");
452 }
453 std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr)
454 {
455 if(dr.d_clen!=6)
456 throw MOADNSException("Wrong size for EUI48 record");
457
458 auto ret=std::make_shared<EUI48RecordContent>();
459 pr.copyRecord((uint8_t*) &ret->d_eui48, 6);
460 return ret;
461 }
462 std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const string& zone)
463 {
464 // try to parse
465 auto ret=std::make_shared<EUI48RecordContent>();
466 // format is 6 hex bytes and dashes
467 if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
468 ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2,
469 ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) {
470 throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse");
471 }
472 return ret;
473 }
474 void EUI48RecordContent::toPacket(DNSPacketWriter& pw) const
475 {
476 string blob(d_eui48, d_eui48+6);
477 pw.xfrBlob(blob);
478 }
479
480 string EUI48RecordContent::getZoneRepresentation(bool /* noDot */) const
481 {
482 char tmp[18];
483 snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x",
484 d_eui48[0], d_eui48[1], d_eui48[2],
485 d_eui48[3], d_eui48[4], d_eui48[5]);
486 return tmp;
487 }
488
489 /* EUI48 end */
490
491 /* EUI64 start */
492
493 void EUI64RecordContent::report()
494 {
495 regist(1, QType::EUI64, &make, &make, "EUI64");
496 }
497 std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr)
498 {
499 if(dr.d_clen!=8)
500 throw MOADNSException("Wrong size for EUI64 record");
501
502 auto ret=std::make_shared<EUI64RecordContent>();
503 pr.copyRecord((uint8_t*) &ret->d_eui64, 8);
504 return ret;
505 }
506 std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const string& zone)
507 {
508 // try to parse
509 auto ret=std::make_shared<EUI64RecordContent>();
510 // format is 8 hex bytes and dashes
511 if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
512 ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2,
513 ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5,
514 ret->d_eui64+6, ret->d_eui64+7) != 8) {
515 throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse");
516 }
517 return ret;
518 }
519 void EUI64RecordContent::toPacket(DNSPacketWriter& pw) const
520 {
521 string blob(d_eui64, d_eui64+8);
522 pw.xfrBlob(blob);
523 }
524
525 string EUI64RecordContent::getZoneRepresentation(bool /* noDot */) const
526 {
527 char tmp[24];
528 snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
529 d_eui64[0], d_eui64[1], d_eui64[2],
530 d_eui64[3], d_eui64[4], d_eui64[5],
531 d_eui64[6], d_eui64[7]);
532 return tmp;
533 }
534
535 /* EUI64 end */
536
537 /* APL start */
538 /* https://tools.ietf.org/html/rfc3123 */
539 void APLRecordContent::report()
540 {
541 regist(1, QType::APL, &make, &make, "APL");
542 }
543
544 // Parse incoming packets (e.g. nsupdate)
545 std::shared_ptr<DNSRecordContent> APLRecordContent::make(const DNSRecord &dr, PacketReader& pr) {
546 uint8_t temp;
547 APLRDataElement ard;
548 size_t processed = 0;
549
550 auto ret=std::make_shared<APLRecordContent>();
551
552 while (processed<dr.d_clen) {
553 pr.xfr16BitInt(ard.d_family);
554 pr.xfr8BitInt(ard.d_prefix);
555 pr.xfr8BitInt(temp);
556 ard.d_n = (temp & 128) >> 7;
557 ard.d_afdlength = temp & 127;
558
559 if (ard.d_family == APL_FAMILY_IPV4) {
560 if (ard.d_afdlength > 4) {
561 throw MOADNSException("Invalid IP length for IPv4 APL");
562 }
563 memset(ard.d_ip.d_ip4, 0, sizeof(ard.d_ip.d_ip4));
564 for (u_int i=0; i < ard.d_afdlength; i++)
565 pr.xfr8BitInt(ard.d_ip.d_ip4[i]);
566 } else if (ard.d_family == APL_FAMILY_IPV6) {
567 if (ard.d_afdlength > 16) {
568 throw MOADNSException("Invalid IP length for IPv6 APL");
569 }
570 memset(ard.d_ip.d_ip6, 0, sizeof(ard.d_ip.d_ip6));
571 for (u_int i=0; i < ard.d_afdlength; i++)
572 pr.xfr8BitInt(ard.d_ip.d_ip6[i]);
573 } else
574 throw MOADNSException("Unknown family for APL record");
575
576 processed += 4 + ard.d_afdlength;
577
578 ret->aplrdata.push_back(ard);
579 }
580
581 return ret;
582 }
583
584 // Parse a single APL <apitem>
585 APLRDataElement APLRecordContent::parseAPLElement(const string& element) {
586 string record;
587 Netmask nm;
588 unsigned int bytes;
589 bool done_trimming;
590 APLRDataElement ard;
591
592 // Parse the optional leading ! (negate)
593 if (element.at(0) == '!') {
594 ard.d_n = true;
595 record = element.substr(1, element.length()-1);
596 } else {
597 ard.d_n = false;
598 record = element;
599 }
600
601 if (record.find('/') == string::npos) { // Required by RFC section 5
602 throw MOADNSException("Asked to decode '"+element+"' as an APL record, but missing subnet mask");
603 }
604
605
606 if (record.find("1:", 0) == 0) { // IPv4
607 uint32_t v4ip;
608
609 ard.d_family = APL_FAMILY_IPV4;
610
611 // Ensure that a mask is provided
612
613 // Read IPv4 string into a Netmask object
614 nm = Netmask(record.substr(2, record.length() - 2));
615 ard.d_prefix = nm.getBits();
616
617 if (nm.getNetwork().isIPv4() == 0)
618 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 v4ip = ntohl(nm.getNetwork().sin4.sin_addr.s_addr);
623 memset(ard.d_ip.d_ip4, 0, sizeof(ard.d_ip.d_ip4));
624 bytes = 4; // Start by assuming we'll send 4 bytes
625 done_trimming = false;
626 for (int i=0; i<4; i++) {
627 ard.d_ip.d_ip4[3-i] = (v4ip & 255);
628 // Remove trailing "0" bytes from packet and update length
629 if ((v4ip & 255) == 0 and !done_trimming) {
630 bytes--;
631 } else {
632 done_trimming = true;
633 }
634 v4ip = v4ip >> 8;
635 }
636 ard.d_afdlength = bytes;
637
638 } else if (record.find("2:", 0) == 0) { // IPv6
639 ard.d_family = APL_FAMILY_IPV6;
640
641 // Parse IPv6 string into a Netmask object
642 nm = Netmask(record.substr(2, record.length() - 2));
643 ard.d_prefix = nm.getBits();
644
645 if (nm.getNetwork().isIPv6() == 0)
646 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 memset(ard.d_ip.d_ip6, 0, sizeof(ard.d_ip.d_ip6));
651 bytes = 16; // Start by assuming we'll send 16 bytes
652 done_trimming = false;
653 for (int i=0; i<16; i++) {
654 ard.d_ip.d_ip6[15-i] = nm.getNetwork().sin6.sin6_addr.s6_addr[15-i];
655 if (nm.getNetwork().sin6.sin6_addr.s6_addr[15-i] == 0 and !done_trimming) {
656 // trailing 0 byte, update length
657 bytes--;
658 } else {
659 done_trimming = true;
660 }
661 }
662 ard.d_afdlength = bytes;
663
664 } else {
665 throw MOADNSException("Asked to encode '"+element+"' as an IPv6 APL record but got unknown Address Family");
666 }
667 return ard;
668
669 }
670
671 // Parse backend record (0, 1 or more <apitem>)
672 std::shared_ptr<DNSRecordContent> APLRecordContent::make(const string& zone) {
673 APLRDataElement ard;
674 vector<string> elements;
675
676 auto ret=std::make_shared<APLRecordContent>();
677
678 boost::split(elements, zone, boost::is_any_of(" "));
679 for (auto & element : elements) {
680 if (!element.empty()) {
681 ard = ret->parseAPLElement(element);
682 ret->aplrdata.push_back(ard);
683 }
684 }
685 return ret;
686 }
687
688
689 // DNSRecord to Packet conversion
690 void APLRecordContent::toPacket(DNSPacketWriter& pw) const {
691 for (auto & ard : aplrdata) {
692 pw.xfr16BitInt(ard.d_family);
693 pw.xfr8BitInt(ard.d_prefix);
694 pw.xfr8BitInt((ard.d_n << 7) + ard.d_afdlength);
695 if (ard.d_family == APL_FAMILY_IPV4) {
696 for (int i=0; i<ard.d_afdlength; i++) {
697 pw.xfr8BitInt(ard.d_ip.d_ip4[i]);
698 }
699 } else if (ard.d_family == APL_FAMILY_IPV6) {
700 for (int i=0; i<ard.d_afdlength; i++) {
701 pw.xfr8BitInt(ard.d_ip.d_ip6[i]);
702 }
703 }
704 }
705 }
706
707 // Decode record into string
708 string APLRecordContent::getZoneRepresentation(bool /* noDot */) const {
709 string s_n, s_family, output;
710 ComboAddress ca;
711 Netmask nm;
712
713 output = "";
714
715 for (std::vector<APLRDataElement>::const_iterator ard = aplrdata.begin() ; ard != aplrdata.end(); ++ard) {
716
717 // Negation flag
718 if (ard->d_n) {
719 s_n = "!";
720 } else {
721 s_n = "";
722 }
723
724 if (ard->d_family == APL_FAMILY_IPV4) { // IPv4
725 s_family = std::to_string(APL_FAMILY_IPV4);
726 ca = ComboAddress();
727 memcpy(&ca.sin4.sin_addr.s_addr, ard->d_ip.d_ip4, sizeof(ca.sin4.sin_addr.s_addr));
728 } else if (ard->d_family == APL_FAMILY_IPV6) { // IPv6
729 s_family = std::to_string(APL_FAMILY_IPV6);
730 ca = ComboAddress();
731 ca.sin4.sin_family = AF_INET6;
732 memset(&ca.sin6.sin6_addr.s6_addr, 0, sizeof(ca.sin6.sin6_addr.s6_addr));
733 memcpy(&ca.sin6.sin6_addr.s6_addr, ard->d_ip.d_ip6, ard->d_afdlength);
734 } else {
735 throw MOADNSException("Asked to decode APL record but got unknown Address Family");
736 }
737
738 nm = Netmask(ca, ard->d_prefix);
739
740 output += s_n + s_family + ":" + nm.toString();
741 if (std::next(ard) != aplrdata.end())
742 output += " ";
743 }
744 return output;
745 }
746
747 /* APL end */
748
749 /* SVCB start */
750 bool SVCBBaseRecordContent::autoHint(const SvcParam::SvcParamKey &key) const {
751 auto p = getParamIt(key);
752 if (p == d_params.end()) {
753 return false;
754 }
755 return p->getAutoHint();
756 }
757
758 void SVCBBaseRecordContent::setHints(const SvcParam::SvcParamKey &key, const std::vector<ComboAddress> &addresses) {
759 auto p = getParamIt(key);
760 if (p == d_params.end()) {
761 return;
762 }
763
764 std::vector<ComboAddress> h;
765 h.reserve(h.size() + addresses.size());
766 h.insert(h.end(), addresses.begin(), addresses.end());
767
768 try {
769 auto newParam = SvcParam(key, std::move(h));
770 d_params.erase(p);
771 d_params.insert(newParam);
772 } catch (...) {
773 // XXX maybe we should SERVFAIL instead?
774 return;
775 }
776 }
777
778 void SVCBBaseRecordContent::removeParam(const SvcParam::SvcParamKey &key) {
779 auto p = getParamIt(key);
780 if (p == d_params.end()) {
781 return;
782 }
783 d_params.erase(p);
784 }
785
786 bool SVCBBaseRecordContent::hasParams() const {
787 return !d_params.empty();
788 }
789
790 bool SVCBBaseRecordContent::hasParam(const SvcParam::SvcParamKey &key) const {
791 return getParamIt(key) != d_params.end();
792 }
793
794 SvcParam SVCBBaseRecordContent::getParam(const SvcParam::SvcParamKey &key) const {
795 auto p = getParamIt(key);
796 if (p == d_params.end()) {
797 throw std::out_of_range("No param with key " + SvcParam::keyToString(key));
798 }
799 return *p;
800 }
801
802 set<SvcParam>::const_iterator SVCBBaseRecordContent::getParamIt(const SvcParam::SvcParamKey &key) const {
803 auto p = std::find_if(d_params.begin(), d_params.end(),
804 [&key](const SvcParam &param) {
805 return param.getKey() == key;
806 });
807 return p;
808 }
809
810 std::shared_ptr<SVCBBaseRecordContent> SVCBRecordContent::clone() const
811 {
812 return std::shared_ptr<SVCBBaseRecordContent>(std::make_shared<SVCBRecordContent>(*this));
813 }
814
815 std::shared_ptr<SVCBBaseRecordContent> HTTPSRecordContent::clone() const
816 {
817 return std::shared_ptr<SVCBBaseRecordContent>(std::make_shared<HTTPSRecordContent>(*this));
818 }
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 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 {
849 const unsigned char* key=(const unsigned char*)data.c_str();
850 unsigned int keysize=data.length();
851
852 unsigned long ac; /* assumed to be 32 bits or larger */
853 unsigned int i; /* loop index */
854
855 for ( ac = 0, i = 0; i < keysize; ++i )
856 ac += (i & 1) ? key[i] : key[i] << 8;
857 ac += (ac >> 16) & 0xFFFF;
858 return ac & 0xFFFF;
859 }
860
861 uint16_t DNSKEYRecordContent::getTag() const
862 {
863 return makeTag(this->serialize(DNSName()));
864 }
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 {
872 eo->d_extFlags=0;
873 if(mdp.d_header.arcount && !mdp.d_answers.empty()) {
874 for(const MOADNSParser::answers_t::value_type& val : mdp.d_answers) {
875 if(val.first.d_place == DNSResourceRecord::ADDITIONAL && val.first.d_type == QType::OPT) {
876 eo->d_packetsize=val.first.d_class;
877
878 EDNS0Record stuff;
879 uint32_t ttl=ntohl(val.first.d_ttl);
880 static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
881 memcpy(&stuff, &ttl, sizeof(stuff));
882
883 eo->d_extRCode=stuff.extRCode;
884 eo->d_version=stuff.version;
885 eo->d_extFlags = ntohs(stuff.extFlags);
886 auto orc = getRR<OPTRecordContent>(val.first);
887 if(orc == nullptr)
888 return false;
889 orc->getData(eo->d_options);
890 return true;
891 }
892 }
893 }
894 return false;
895 }
896
897 void reportBasicTypes()
898 {
899 ARecordContent::report();
900 AAAARecordContent::report();
901 NSRecordContent::report();
902 CNAMERecordContent::report();
903 MXRecordContent::report();
904 SOARecordContent::report();
905 SRVRecordContent::report();
906 PTRRecordContent::report();
907 DNSRecordContent::regist(QClass::CHAOS, QType::TXT, &TXTRecordContent::make, &TXTRecordContent::make, "TXT");
908 TXTRecordContent::report();
909 #ifdef HAVE_LUA_RECORDS
910 LUARecordContent::report();
911 #endif
912 DNSRecordContent::regist(QClass::IN, QType::ANY, nullptr, nullptr, "ANY");
913 DNSRecordContent::regist(QClass::IN, QType::AXFR, nullptr, nullptr, "AXFR");
914 DNSRecordContent::regist(QClass::IN, QType::IXFR, nullptr, nullptr, "IXFR");
915 }
916
917 void reportOtherTypes()
918 {
919 MBRecordContent::report();
920 MGRecordContent::report();
921 MRRecordContent::report();
922 AFSDBRecordContent::report();
923 DNAMERecordContent::report();
924 #if !defined(RECURSOR)
925 ALIASRecordContent::report();
926 #endif
927 SPFRecordContent::report();
928 NAPTRRecordContent::report();
929 KXRecordContent::report();
930 LOCRecordContent::report();
931 ENTRecordContent::report();
932 HINFORecordContent::report();
933 RPRecordContent::report();
934 KEYRecordContent::report();
935 DNSKEYRecordContent::report();
936 DHCIDRecordContent::report();
937 CDNSKEYRecordContent::report();
938 RKEYRecordContent::report();
939 RRSIGRecordContent::report();
940 DSRecordContent::report();
941 CDSRecordContent::report();
942 SSHFPRecordContent::report();
943 CERTRecordContent::report();
944 NSECRecordContent::report();
945 NSEC3RecordContent::report();
946 NSEC3PARAMRecordContent::report();
947 TLSARecordContent::report();
948 SMIMEARecordContent::report();
949 OPENPGPKEYRecordContent::report();
950 SVCBRecordContent::report();
951 HTTPSRecordContent::report();
952 DLVRecordContent::report();
953 DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG");
954 DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY");
955 //TSIGRecordContent::report();
956 OPTRecordContent::report();
957 EUI48RecordContent::report();
958 EUI64RecordContent::report();
959 MINFORecordContent::report();
960 URIRecordContent::report();
961 CAARecordContent::report();
962 APLRecordContent::report();
963 IPSECKEYRecordContent::report();
964 CSYNCRecordContent::report();
965 NIDRecordContent::report();
966 L32RecordContent::report();
967 L64RecordContent::report();
968 LPRecordContent::report();
969 ZONEMDRecordContent::report();
970 }
971
972 void reportAllTypes()
973 {
974 reportBasicTypes();
975 reportOtherTypes();
976 }
977
978 ComboAddress getAddr(const DNSRecord& dr, uint16_t defport)
979 {
980 if (auto a = getRR<ARecordContent>(dr)) {
981 return a->getCA(defport);
982 }
983 else if (auto aaaa = getRR<AAAARecordContent>(dr)) {
984 return aaaa->getCA(defport);
985 }
986 throw std::invalid_argument("not an A or AAAA record");
987 }
988
989 /**
990 * Check if the DNSNames that should be hostnames, are hostnames
991 */
992 void checkHostnameCorrectness(const DNSResourceRecord& rr)
993 {
994 if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) {
995 DNSName toCheck;
996 if (rr.qtype.getCode() == QType::SRV) {
997 vector<string> parts;
998 stringtok(parts, rr.getZoneRepresentation());
999 if (parts.size() == 4) toCheck = DNSName(parts[3]);
1000 } else if (rr.qtype.getCode() == QType::MX) {
1001 vector<string> parts;
1002 stringtok(parts, rr.getZoneRepresentation());
1003 if (parts.size() == 2) toCheck = DNSName(parts[1]);
1004 } else {
1005 toCheck = DNSName(rr.content);
1006 }
1007
1008 if (toCheck.empty()) {
1009 throw std::runtime_error("unable to extract hostname from content");
1010 }
1011 else if ((rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) && toCheck == g_rootdnsname) {
1012 // allow null MX/SRV
1013 } else if(!toCheck.isHostname()) {
1014 throw std::runtime_error(boost::str(boost::format("non-hostname content %s") % toCheck.toString()));
1015 }
1016 }
1017 }
1018
1019 #if 0
1020 static struct Reporter
1021 {
1022 Reporter()
1023 {
1024 reportAllTypes();
1025 }
1026 } reporter __attribute__((init_priority(65535)));
1027 #endif