]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsrecords.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
26 #include <boost/format.hpp>
29 #include "dnsrecords.hh"
32 void DNSResourceRecord::setContent(const string
&cont
) {
34 switch(qtype
.getCode()) {
37 if (content
.size() >= 2 && *(content
.rbegin()+1) == ' ')
44 if (content
.size() >= 2 && *(content
.rbegin()) == '.')
45 boost::erase_tail(content
, 1);
49 string
DNSResourceRecord::getZoneRepresentation(bool noDot
) const {
54 switch(qtype
.getCode()) {
57 stringtok(parts
, content
);
60 last
= *parts
.rbegin();
64 if (*(last
.rbegin()) != '.' && !noDot
)
72 if (*(content
.rbegin()) != '.' && !noDot
)
82 bool DNSResourceRecord::operator==(const DNSResourceRecord
& rhs
)
84 string lcontent
=toLower(content
);
85 string rcontent
=toLower(rhs
.content
);
88 std::tie(qname
, qtype
, lcontent
, ttl
) ==
89 std::tie(rhs
.qname
, rhs
.qtype
, rcontent
, rhs
.ttl
);
92 boilerplate_conv(A
, conv
.xfrIP(d_ip
));
94 ARecordContent::ARecordContent(uint32_t ip
)
99 ARecordContent::ARecordContent(const ComboAddress
& ca
)
101 d_ip
= ca
.sin4
.sin_addr
.s_addr
;
104 AAAARecordContent::AAAARecordContent(const ComboAddress
& ca
)
106 d_ip6
.assign((const char*)ca
.sin6
.sin6_addr
.s6_addr
, 16);
111 ComboAddress
ARecordContent::getCA(int port
) const
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
));
120 ComboAddress
AAAARecordContent::getCA(int port
) const
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
));
132 void ARecordContent::doRecordCheck(const DNSRecord
& dr
)
135 throw MOADNSException("Wrong size for A record ("+std::to_string(dr
.d_clen
)+")");
138 boilerplate_conv(AAAA
, conv
.xfrIP6(d_ip6
); );
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));
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));
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
));
160 conv
.xfrName(d_mbox
);
165 boilerplate_conv(OPT
,
169 #ifdef HAVE_LUA_RECORDS
170 string
LUARecordContent::getCode() const
172 // in d_code, series of "part1" "part2"
173 vector
<string
> parts
;
174 stringtok(parts
, d_code
, "\"");
176 for(const auto& p
: parts
) {
184 void OPTRecordContent::getData(vector
<pair
<uint16_t, string
> >& options
) const
186 string::size_type pos
=0;
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);
193 if(pos
+ len
> d_data
.size())
196 string
field(d_data
.c_str() + pos
, len
);
198 options
.emplace_back(code
, std::move(field
));
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
);
216 MXRecordContent::MXRecordContent(uint16_t preference
, DNSName mxname
): d_preference(preference
), d_mxname(std::move(mxname
))
221 conv
.xfr16BitInt(d_preference
);
222 conv
.xfrName(d_mxname
, true);
226 conv
.xfr16BitInt(d_preference
);
227 conv
.xfrName(d_exchanger
, false);
230 boilerplate_conv(IPSECKEY
,
231 conv
.xfr8BitInt(d_preference
);
232 conv
.xfr8BitInt(d_gatewaytype
);
233 conv
.xfr8BitInt(d_algorithm
);
235 // now we need to determine values
236 switch(d_gatewaytype
) {
246 conv
.xfrName(d_gateway
, false);
249 throw MOADNSException("Parsing record content: invalid gateway type");
252 switch(d_algorithm
) {
257 conv
.xfrBlob(d_publickey
);
260 throw MOADNSException("Parsing record content: invalid algorithm type");
264 boilerplate_conv(DHCID
,
265 conv
.xfrBlob(d_content
);
269 boilerplate_conv(AFSDB
,
270 conv
.xfr16BitInt(d_subtype
);
271 conv
.xfrName(d_hostname
);
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
);
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
)
286 boilerplate_conv(SRV
,
287 conv
.xfr16BitInt(d_preference
); conv
.xfr16BitInt(d_weight
); conv
.xfr16BitInt(d_port
);
288 conv
.xfrName(d_target
);
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
)
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
);
306 boilerplate_conv(KEY
,
307 conv
.xfr16BitInt(d_flags
);
308 conv
.xfr8BitInt(d_protocol
);
309 conv
.xfr8BitInt(d_algorithm
);
310 conv
.xfrBlob(d_certificate
);
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
320 boilerplate_conv(CERT
,
321 conv
.xfr16BitInt(d_type
);
322 if (d_type
== 0) throw MOADNSException("CERT type 0 is reserved");
324 conv
.xfr16BitInt(d_tag
);
325 conv
.xfr8BitInt(d_algorithm
);
326 conv
.xfrBlob(d_certificate
);
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);
336 boilerplate_conv(OPENPGPKEY
,
337 conv
.xfrBlob(d_keyring
);
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
);
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
);
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);
363 DSRecordContent::DSRecordContent() = default;
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
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
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
388 boilerplate_conv(SSHFP
,
389 conv
.xfr8BitInt(d_algorithm
);
390 conv
.xfr8BitInt(d_fptype
);
391 conv
.xfrHexBlob(d_fingerprint
, true);
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
);
406 RRSIGRecordContent::RRSIGRecordContent() = default;
408 boilerplate_conv(DNSKEY
,
409 conv
.xfr16BitInt(d_flags
);
410 conv
.xfr8BitInt(d_protocol
);
411 conv
.xfr8BitInt(d_algorithm
);
414 DNSKEYRecordContent::DNSKEYRecordContent() = default;
416 boilerplate_conv(CDNSKEY
,
417 conv
.xfr16BitInt(d_flags
);
418 conv
.xfr8BitInt(d_protocol
);
419 conv
.xfr8BitInt(d_algorithm
);
422 CDNSKEYRecordContent::CDNSKEYRecordContent() = default;
424 boilerplate_conv(RKEY
,
425 conv
.xfr16BitInt(d_flags
);
426 conv
.xfr8BitInt(d_protocol
);
427 conv
.xfr8BitInt(d_algorithm
);
430 RKEYRecordContent::RKEYRecordContent() = default;
432 boilerplate_conv(NID
,
433 conv
.xfr16BitInt(d_preference
);
434 conv
.xfrNodeOrLocatorID(d_node_id
);)
436 boilerplate_conv(L32
,
437 conv
.xfr16BitInt(d_preference
);
438 conv
.xfrIP(d_locator
);)
440 boilerplate_conv(L64
,
441 conv
.xfr16BitInt(d_preference
);
442 conv
.xfrNodeOrLocatorID(d_locator
);)
445 conv
.xfr16BitInt(d_preference
);
446 conv
.xfrName(d_fqdn
, false);)
449 void EUI48RecordContent::report()
451 regist(1, QType::EUI48
, &make
, &make
, "EUI48");
453 std::shared_ptr
<DNSRecordContent
> EUI48RecordContent::make(const DNSRecord
&dr
, PacketReader
& pr
)
456 throw MOADNSException("Wrong size for EUI48 record");
458 auto ret
=std::make_shared
<EUI48RecordContent
>();
459 pr
.copyRecord((uint8_t*) &ret
->d_eui48
, 6);
462 std::shared_ptr
<DNSRecordContent
> EUI48RecordContent::make(const string
& zone
)
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");
474 void EUI48RecordContent::toPacket(DNSPacketWriter
& pw
) const
476 string
blob(d_eui48
, d_eui48
+6);
480 string
EUI48RecordContent::getZoneRepresentation(bool /* noDot */) const
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]);
493 void EUI64RecordContent::report()
495 regist(1, QType::EUI64
, &make
, &make
, "EUI64");
497 std::shared_ptr
<DNSRecordContent
> EUI64RecordContent::make(const DNSRecord
&dr
, PacketReader
& pr
)
500 throw MOADNSException("Wrong size for EUI64 record");
502 auto ret
=std::make_shared
<EUI64RecordContent
>();
503 pr
.copyRecord((uint8_t*) &ret
->d_eui64
, 8);
506 std::shared_ptr
<DNSRecordContent
> EUI64RecordContent::make(const string
& zone
)
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");
519 void EUI64RecordContent::toPacket(DNSPacketWriter
& pw
) const
521 string
blob(d_eui64
, d_eui64
+8);
525 string
EUI64RecordContent::getZoneRepresentation(bool /* noDot */) const
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]);
538 /* https://tools.ietf.org/html/rfc3123 */
539 void APLRecordContent::report()
541 regist(1, QType::APL
, &make
, &make
, "APL");
544 // Parse incoming packets (e.g. nsupdate)
545 std::shared_ptr
<DNSRecordContent
> APLRecordContent::make(const DNSRecord
&dr
, PacketReader
& pr
) {
548 size_t processed
= 0;
550 auto ret
=std::make_shared
<APLRecordContent
>();
552 while (processed
<dr
.d_clen
) {
553 pr
.xfr16BitInt(ard
.d_family
);
554 pr
.xfr8BitInt(ard
.d_prefix
);
556 ard
.d_n
= (temp
& 128) >> 7;
557 ard
.d_afdlength
= temp
& 127;
559 if (ard
.d_family
== APL_FAMILY_IPV4
) {
560 if (ard
.d_afdlength
> 4) {
561 throw MOADNSException("Invalid IP length for IPv4 APL");
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");
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
]);
574 throw MOADNSException("Unknown family for APL record");
576 processed
+= 4 + ard
.d_afdlength
;
578 ret
->aplrdata
.push_back(ard
);
584 // Parse a single APL <apitem>
585 APLRDataElement
APLRecordContent::parseAPLElement(const string
& element
) {
592 // Parse the optional leading ! (negate)
593 if (element
.at(0) == '!') {
595 record
= element
.substr(1, element
.length()-1);
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");
606 if (record
.find("1:", 0) == 0) { // IPv4
609 ard
.d_family
= APL_FAMILY_IPV4
;
611 // Ensure that a mask is provided
613 // Read IPv4 string into a Netmask object
614 nm
= Netmask(record
.substr(2, record
.length() - 2));
615 ard
.d_prefix
= nm
.getBits();
617 if (nm
.getNetwork().isIPv4() == 0)
618 throw MOADNSException("Asked to decode '"+element
+"' as an APL v4 record");
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
) {
632 done_trimming
= true;
636 ard
.d_afdlength
= bytes
;
638 } else if (record
.find("2:", 0) == 0) { // IPv6
639 ard
.d_family
= APL_FAMILY_IPV6
;
641 // Parse IPv6 string into a Netmask object
642 nm
= Netmask(record
.substr(2, record
.length() - 2));
643 ard
.d_prefix
= nm
.getBits();
645 if (nm
.getNetwork().isIPv6() == 0)
646 throw MOADNSException("Asked to decode '"+element
+"' as an APL v6 record");
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
659 done_trimming
= true;
662 ard
.d_afdlength
= bytes
;
665 throw MOADNSException("Asked to encode '"+element
+"' as an IPv6 APL record but got unknown Address Family");
671 // Parse backend record (0, 1 or more <apitem>)
672 std::shared_ptr
<DNSRecordContent
> APLRecordContent::make(const string
& zone
) {
674 vector
<string
> elements
;
676 auto ret
=std::make_shared
<APLRecordContent
>();
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
);
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
]);
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
]);
707 // Decode record into string
708 string
APLRecordContent::getZoneRepresentation(bool /* noDot */) const {
709 string s_n
, s_family
, output
;
715 for (std::vector
<APLRDataElement
>::const_iterator ard
= aplrdata
.begin() ; ard
!= aplrdata
.end(); ++ard
) {
724 if (ard
->d_family
== APL_FAMILY_IPV4
) { // IPv4
725 s_family
= std::to_string(APL_FAMILY_IPV4
);
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
);
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
);
735 throw MOADNSException("Asked to decode APL record but got unknown Address Family");
738 nm
= Netmask(ca
, ard
->d_prefix
);
740 output
+= s_n
+ s_family
+ ":" + nm
.toString();
741 if (std::next(ard
) != aplrdata
.end())
750 bool SVCBBaseRecordContent::autoHint(const SvcParam::SvcParamKey
&key
) const {
751 auto p
= getParamIt(key
);
752 if (p
== d_params
.end()) {
755 return p
->getAutoHint();
758 void SVCBBaseRecordContent::setHints(const SvcParam::SvcParamKey
&key
, const std::vector
<ComboAddress
> &addresses
) {
759 auto p
= getParamIt(key
);
760 if (p
== d_params
.end()) {
764 std::vector
<ComboAddress
> h
;
765 h
.reserve(h
.size() + addresses
.size());
766 h
.insert(h
.end(), addresses
.begin(), addresses
.end());
769 auto newParam
= SvcParam(key
, std::move(h
));
771 d_params
.insert(newParam
);
773 // XXX maybe we should SERVFAIL instead?
778 void SVCBBaseRecordContent::removeParam(const SvcParam::SvcParamKey
&key
) {
779 auto p
= getParamIt(key
);
780 if (p
== d_params
.end()) {
786 bool SVCBBaseRecordContent::hasParams() const {
787 return !d_params
.empty();
790 bool SVCBBaseRecordContent::hasParam(const SvcParam::SvcParamKey
&key
) const {
791 return getParamIt(key
) != d_params
.end();
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
));
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
¶m
) {
805 return param
.getKey() == key
;
810 std::shared_ptr
<SVCBBaseRecordContent
> SVCBRecordContent::clone() const
812 return std::shared_ptr
<SVCBBaseRecordContent
>(std::make_shared
<SVCBRecordContent
>(*this));
815 std::shared_ptr
<SVCBBaseRecordContent
> HTTPSRecordContent::clone() const
817 return std::shared_ptr
<SVCBBaseRecordContent
>(std::make_shared
<HTTPSRecordContent
>(*this));
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
);
833 TKEYRecordContent::TKEYRecordContent() { d_othersize
= 0; } // fix CID#1288932
835 boilerplate_conv(URI
,
836 conv
.xfr16BitInt(d_priority
);
837 conv
.xfr16BitInt(d_weight
);
838 conv
.xfrText(d_target
, true, false);
841 boilerplate_conv(CAA
,
842 conv
.xfr8BitInt(d_flags
);
843 conv
.xfrUnquotedText(d_tag
, true);
844 conv
.xfrText(d_value
, true, false); /* no lenField */
847 static uint16_t makeTag(const std::string
& data
)
849 const unsigned char* key
=(const unsigned char*)data
.c_str();
850 unsigned int keysize
=data
.length();
852 unsigned long ac
; /* assumed to be 32 bits or larger */
853 unsigned int i
; /* loop index */
855 for ( ac
= 0, i
= 0; i
< keysize
; ++i
)
856 ac
+= (i
& 1) ? key
[i
] : key
[i
] << 8;
857 ac
+= (ac
>> 16) & 0xFFFF;
861 uint16_t DNSKEYRecordContent::getTag() const
863 return makeTag(this->serialize(DNSName()));
868 * Fills `eo` by parsing the EDNS(0) OPT RR (RFC 6891)
870 bool getEDNSOpts(const MOADNSParser
& mdp
, EDNSOpts
* eo
)
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
;
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
));
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
);
889 orc
->getData(eo
->d_options
);
897 void reportBasicTypes()
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();
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");
917 void reportOtherTypes()
919 MBRecordContent::report();
920 MGRecordContent::report();
921 MRRecordContent::report();
922 AFSDBRecordContent::report();
923 DNAMERecordContent::report();
924 #if !defined(RECURSOR)
925 ALIASRecordContent::report();
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();
972 void reportAllTypes()
978 ComboAddress
getAddr(const DNSRecord
& dr
, uint16_t defport
)
980 if (auto a
= getRR
<ARecordContent
>(dr
)) {
981 return a
->getCA(defport
);
983 else if (auto aaaa
= getRR
<AAAARecordContent
>(dr
)) {
984 return aaaa
->getCA(defport
);
986 throw std::invalid_argument("not an A or AAAA record");
990 * Check if the DNSNames that should be hostnames, are hostnames
992 void checkHostnameCorrectness(const DNSResourceRecord
& rr
)
994 if (rr
.qtype
.getCode() == QType::NS
|| rr
.qtype
.getCode() == QType::MX
|| rr
.qtype
.getCode() == QType::SRV
) {
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]);
1005 toCheck
= DNSName(rr
.content
);
1008 if (toCheck
.empty()) {
1009 throw std::runtime_error("unable to extract hostname from content");
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()));
1020 static struct Reporter
1026 } reporter
__attribute__((init_priority(65535)));