]>
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 "dnsrecords.hh"
30 void DNSResourceRecord::setContent(const string
&cont
) {
32 switch(qtype
.getCode()) {
35 if (content
.size() >= 2 && *(content
.rbegin()+1) == ' ')
42 if (content
.size() >= 2 && *(content
.rbegin()) == '.')
43 boost::erase_tail(content
, 1);
47 string
DNSResourceRecord::getZoneRepresentation(bool noDot
) const {
52 switch(qtype
.getCode()) {
55 stringtok(parts
, content
);
58 last
= *parts
.rbegin();
62 if (*(last
.rbegin()) != '.' && !noDot
)
70 if (*(content
.rbegin()) != '.' && !noDot
)
80 bool DNSResourceRecord::operator==(const DNSResourceRecord
& rhs
)
82 string lcontent
=toLower(content
);
83 string rcontent
=toLower(rhs
.content
);
86 tie(qname
, qtype
, lcontent
, ttl
) ==
87 tie(rhs
.qname
, rhs
.qtype
, rcontent
, rhs
.ttl
);
90 boilerplate_conv(A
, QType::A
, conv
.xfrIP(d_ip
));
92 ARecordContent::ARecordContent(uint32_t ip
)
97 ARecordContent::ARecordContent(const ComboAddress
& ca
)
99 d_ip
= ca
.sin4
.sin_addr
.s_addr
;
102 AAAARecordContent::AAAARecordContent(const ComboAddress
& ca
)
104 d_ip6
.assign((const char*)ca
.sin6
.sin6_addr
.s6_addr
, 16);
109 ComboAddress
ARecordContent::getCA(int port
) const
112 ret
.sin4
.sin_family
=AF_INET
;
113 ret
.sin4
.sin_port
=htons(port
);
114 memcpy(&ret
.sin4
.sin_addr
.s_addr
, &d_ip
, sizeof(ret
.sin4
.sin_addr
.s_addr
));
118 ComboAddress
AAAARecordContent::getCA(int port
) const
123 ret
.sin4
.sin_family
=AF_INET6
;
124 ret
.sin6
.sin6_port
= htons(port
);
125 memcpy(&ret
.sin6
.sin6_addr
.s6_addr
, d_ip6
.c_str(), sizeof(ret
.sin6
.sin6_addr
.s6_addr
));
130 void ARecordContent::doRecordCheck(const DNSRecord
& dr
)
133 throw MOADNSException("Wrong size for A record ("+std::to_string(dr
.d_clen
)+")");
136 boilerplate_conv(AAAA
, QType::AAAA
, conv
.xfrIP6(d_ip6
); );
138 boilerplate_conv(NS
, QType::NS
, conv
.xfrName(d_content
, true));
139 boilerplate_conv(PTR
, QType::PTR
, conv
.xfrName(d_content
, true));
140 boilerplate_conv(CNAME
, QType::CNAME
, conv
.xfrName(d_content
, true));
141 boilerplate_conv(ALIAS
, QType::ALIAS
, conv
.xfrName(d_content
, false));
142 boilerplate_conv(DNAME
, QType::DNAME
, conv
.xfrName(d_content
));
143 boilerplate_conv(MB
, QType::MB
, conv
.xfrName(d_madname
, true));
144 boilerplate_conv(MG
, QType::MG
, conv
.xfrName(d_mgmname
, true));
145 boilerplate_conv(MR
, QType::MR
, conv
.xfrName(d_alias
, true));
146 boilerplate_conv(MINFO
, QType::MINFO
, conv
.xfrName(d_rmailbx
, true); conv
.xfrName(d_emailbx
, true));
147 boilerplate_conv(TXT
, QType::TXT
, conv
.xfrText(d_text
, true));
148 #ifdef HAVE_LUA_RECORDS
149 boilerplate_conv(LUA
, QType::LUA
, conv
.xfrType(d_type
); conv
.xfrText(d_code
, true));
151 boilerplate_conv(ENT
, 0, );
152 boilerplate_conv(SPF
, 99, conv
.xfrText(d_text
, true));
153 boilerplate_conv(HINFO
, QType::HINFO
, conv
.xfrText(d_cpu
); conv
.xfrText(d_host
));
155 boilerplate_conv(RP
, QType::RP
,
156 conv
.xfrName(d_mbox
);
161 boilerplate_conv(OPT
, QType::OPT
,
165 #ifdef HAVE_LUA_RECORDS
166 string
LUARecordContent::getCode() const
168 // in d_code, series of "part1" "part2"
169 vector
<string
> parts
;
170 stringtok(parts
, d_code
, "\"");
172 for(const auto& p
: parts
) {
180 void OPTRecordContent::getData(vector
<pair
<uint16_t, string
> >& options
)
182 string::size_type pos
=0;
184 while(d_data
.size() >= 4 + pos
) {
185 code
= 256 * (unsigned char)d_data
[pos
] + (unsigned char)d_data
[pos
+1];
186 len
= 256 * (unsigned char)d_data
[pos
+2] + (unsigned char)d_data
[pos
+3];
189 if(pos
+ len
> d_data
.size())
192 string
field(d_data
.c_str() + pos
, len
);
194 options
.push_back(make_pair(code
, field
));
198 boilerplate_conv(TSIG
, QType::TSIG
,
199 conv
.xfrName(d_algoName
);
200 conv
.xfr48BitInt(d_time
);
201 conv
.xfr16BitInt(d_fudge
);
202 uint16_t size
=d_mac
.size();
203 conv
.xfr16BitInt(size
);
204 if (size
>0) conv
.xfrBlobNoSpaces(d_mac
, size
);
205 conv
.xfr16BitInt(d_origID
);
206 conv
.xfr16BitInt(d_eRcode
);
207 size
=d_otherData
.size();
208 conv
.xfr16BitInt(size
);
209 if (size
>0) conv
.xfrBlobNoSpaces(d_otherData
, size
);
212 MXRecordContent::MXRecordContent(uint16_t preference
, const DNSName
& mxname
): d_preference(preference
), d_mxname(mxname
)
216 boilerplate_conv(MX
, QType::MX
,
217 conv
.xfr16BitInt(d_preference
);
218 conv
.xfrName(d_mxname
, true);
221 boilerplate_conv(KX
, QType::KX
,
222 conv
.xfr16BitInt(d_preference
);
223 conv
.xfrName(d_exchanger
, false);
226 boilerplate_conv(IPSECKEY
, QType::IPSECKEY
,
227 conv
.xfr8BitInt(d_preference
);
228 conv
.xfr8BitInt(d_gatewaytype
);
229 conv
.xfr8BitInt(d_algorithm
);
231 // now we need to determine values
232 switch(d_gatewaytype
) {
242 conv
.xfrName(d_gateway
, false);
245 throw MOADNSException("Parsing record content: invalid gateway type");
248 switch(d_algorithm
) {
253 conv
.xfrBlob(d_publickey
);
256 throw MOADNSException("Parsing record content: invalid algorithm type");
260 boilerplate_conv(DHCID
, 49,
261 conv
.xfrBlob(d_content
);
265 boilerplate_conv(AFSDB
, QType::AFSDB
,
266 conv
.xfr16BitInt(d_subtype
);
267 conv
.xfrName(d_hostname
);
271 boilerplate_conv(NAPTR
, QType::NAPTR
,
272 conv
.xfr16BitInt(d_order
); conv
.xfr16BitInt(d_preference
);
273 conv
.xfrText(d_flags
); conv
.xfrText(d_services
); conv
.xfrText(d_regexp
);
274 conv
.xfrName(d_replacement
);
278 SRVRecordContent::SRVRecordContent(uint16_t preference
, uint16_t weight
, uint16_t port
, const DNSName
& target
)
279 : d_weight(weight
), d_port(port
), d_target(target
), d_preference(preference
)
282 boilerplate_conv(SRV
, QType::SRV
,
283 conv
.xfr16BitInt(d_preference
); conv
.xfr16BitInt(d_weight
); conv
.xfr16BitInt(d_port
);
284 conv
.xfrName(d_target
);
287 SOARecordContent::SOARecordContent(const DNSName
& mname
, const DNSName
& rname
, const struct soatimes
& st
)
288 : d_mname(mname
), d_rname(rname
), d_st(st
)
292 boilerplate_conv(SOA
, QType::SOA
,
293 conv
.xfrName(d_mname
, true);
294 conv
.xfrName(d_rname
, true);
295 conv
.xfr32BitInt(d_st
.serial
);
296 conv
.xfr32BitInt(d_st
.refresh
);
297 conv
.xfr32BitInt(d_st
.retry
);
298 conv
.xfr32BitInt(d_st
.expire
);
299 conv
.xfr32BitInt(d_st
.minimum
);
302 boilerplate_conv(KEY
, QType::KEY
,
303 conv
.xfr16BitInt(d_flags
);
304 conv
.xfr8BitInt(d_protocol
);
305 conv
.xfr8BitInt(d_algorithm
);
306 conv
.xfrBlob(d_certificate
);
309 boilerplate_conv(CERT
, 37,
310 conv
.xfr16BitInt(d_type
);
311 if (d_type
== 0) throw MOADNSException("CERT type 0 is reserved");
313 conv
.xfr16BitInt(d_tag
);
314 conv
.xfr8BitInt(d_algorithm
);
315 conv
.xfrBlob(d_certificate
);
318 boilerplate_conv(TLSA
, 52,
319 conv
.xfr8BitInt(d_certusage
);
320 conv
.xfr8BitInt(d_selector
);
321 conv
.xfr8BitInt(d_matchtype
);
322 conv
.xfrHexBlob(d_cert
, true);
325 boilerplate_conv(OPENPGPKEY
, 61,
326 conv
.xfrBlob(d_keyring
);
329 boilerplate_conv(SMIMEA
, 53,
330 conv
.xfr8BitInt(d_certusage
);
331 conv
.xfr8BitInt(d_selector
);
332 conv
.xfr8BitInt(d_matchtype
);
333 conv
.xfrHexBlob(d_cert
, true);
336 DSRecordContent::DSRecordContent() {}
337 boilerplate_conv(DS
, 43,
338 conv
.xfr16BitInt(d_tag
);
339 conv
.xfr8BitInt(d_algorithm
);
340 conv
.xfr8BitInt(d_digesttype
);
341 conv
.xfrHexBlob(d_digest
, true); // keep reading across spaces
344 CDSRecordContent::CDSRecordContent() {}
345 boilerplate_conv(CDS
, 59,
346 conv
.xfr16BitInt(d_tag
);
347 conv
.xfr8BitInt(d_algorithm
);
348 conv
.xfr8BitInt(d_digesttype
);
349 conv
.xfrHexBlob(d_digest
, true); // keep reading across spaces
352 DLVRecordContent::DLVRecordContent() {}
353 boilerplate_conv(DLV
,32769 ,
354 conv
.xfr16BitInt(d_tag
);
355 conv
.xfr8BitInt(d_algorithm
);
356 conv
.xfr8BitInt(d_digesttype
);
357 conv
.xfrHexBlob(d_digest
, true); // keep reading across spaces
361 boilerplate_conv(SSHFP
, 44,
362 conv
.xfr8BitInt(d_algorithm
);
363 conv
.xfr8BitInt(d_fptype
);
364 conv
.xfrHexBlob(d_fingerprint
, true);
367 boilerplate_conv(RRSIG
, 46,
368 conv
.xfrType(d_type
);
369 conv
.xfr8BitInt(d_algorithm
);
370 conv
.xfr8BitInt(d_labels
);
371 conv
.xfr32BitInt(d_originalttl
);
372 conv
.xfrTime(d_sigexpire
);
373 conv
.xfrTime(d_siginception
);
374 conv
.xfr16BitInt(d_tag
);
375 conv
.xfrName(d_signer
);
376 conv
.xfrBlob(d_signature
);
379 RRSIGRecordContent::RRSIGRecordContent() {}
381 boilerplate_conv(DNSKEY
, 48,
382 conv
.xfr16BitInt(d_flags
);
383 conv
.xfr8BitInt(d_protocol
);
384 conv
.xfr8BitInt(d_algorithm
);
387 DNSKEYRecordContent::DNSKEYRecordContent() {}
389 boilerplate_conv(CDNSKEY
, 60,
390 conv
.xfr16BitInt(d_flags
);
391 conv
.xfr8BitInt(d_protocol
);
392 conv
.xfr8BitInt(d_algorithm
);
395 CDNSKEYRecordContent::CDNSKEYRecordContent() {}
397 boilerplate_conv(RKEY
, 57,
398 conv
.xfr16BitInt(d_flags
);
399 conv
.xfr8BitInt(d_protocol
);
402 RKEYRecordContent::RKEYRecordContent() {}
405 void EUI48RecordContent::report(void)
407 regist(1, QType::EUI48
, &make
, &make
, "EUI48");
409 std::shared_ptr
<DNSRecordContent
> EUI48RecordContent::make(const DNSRecord
&dr
, PacketReader
& pr
)
412 throw MOADNSException("Wrong size for EUI48 record");
414 auto ret
=std::make_shared
<EUI48RecordContent
>();
415 pr
.copyRecord((uint8_t*) &ret
->d_eui48
, 6);
418 std::shared_ptr
<DNSRecordContent
> EUI48RecordContent::make(const string
& zone
)
421 auto ret
=std::make_shared
<EUI48RecordContent
>();
422 // format is 6 hex bytes and dashes
423 if (sscanf(zone
.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
424 ret
->d_eui48
, ret
->d_eui48
+1, ret
->d_eui48
+2,
425 ret
->d_eui48
+3, ret
->d_eui48
+4, ret
->d_eui48
+5) != 6) {
426 throw MOADNSException("Asked to encode '"+zone
+"' as an EUI48 address, but does not parse");
430 void EUI48RecordContent::toPacket(DNSPacketWriter
& pw
)
432 string
blob(d_eui48
, d_eui48
+6);
435 string
EUI48RecordContent::getZoneRepresentation(bool noDot
) const
438 snprintf(tmp
,sizeof(tmp
),"%02x-%02x-%02x-%02x-%02x-%02x",
439 d_eui48
[0], d_eui48
[1], d_eui48
[2],
440 d_eui48
[3], d_eui48
[4], d_eui48
[5]);
448 void EUI64RecordContent::report(void)
450 regist(1, QType::EUI64
, &make
, &make
, "EUI64");
452 std::shared_ptr
<DNSRecordContent
> EUI64RecordContent::make(const DNSRecord
&dr
, PacketReader
& pr
)
455 throw MOADNSException("Wrong size for EUI64 record");
457 auto ret
=std::make_shared
<EUI64RecordContent
>();
458 pr
.copyRecord((uint8_t*) &ret
->d_eui64
, 8);
461 std::shared_ptr
<DNSRecordContent
> EUI64RecordContent::make(const string
& zone
)
464 auto ret
=std::make_shared
<EUI64RecordContent
>();
465 // format is 8 hex bytes and dashes
466 if (sscanf(zone
.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
467 ret
->d_eui64
, ret
->d_eui64
+1, ret
->d_eui64
+2,
468 ret
->d_eui64
+3, ret
->d_eui64
+4, ret
->d_eui64
+5,
469 ret
->d_eui64
+6, ret
->d_eui64
+7) != 8) {
470 throw MOADNSException("Asked to encode '"+zone
+"' as an EUI64 address, but does not parse");
474 void EUI64RecordContent::toPacket(DNSPacketWriter
& pw
)
476 string
blob(d_eui64
, d_eui64
+8);
479 string
EUI64RecordContent::getZoneRepresentation(bool noDot
) const
482 snprintf(tmp
,sizeof(tmp
),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
483 d_eui64
[0], d_eui64
[1], d_eui64
[2],
484 d_eui64
[3], d_eui64
[4], d_eui64
[5],
485 d_eui64
[6], d_eui64
[7]);
491 boilerplate_conv(TKEY
, QType::TKEY
,
492 conv
.xfrName(d_algo
);
493 conv
.xfr32BitInt(d_inception
);
494 conv
.xfr32BitInt(d_expiration
);
495 conv
.xfr16BitInt(d_mode
);
496 conv
.xfr16BitInt(d_error
);
497 conv
.xfr16BitInt(d_keysize
);
498 if (d_keysize
>0) conv
.xfrBlobNoSpaces(d_key
, d_keysize
);
499 conv
.xfr16BitInt(d_othersize
);
500 if (d_othersize
>0) conv
.xfrBlobNoSpaces(d_other
, d_othersize
);
502 TKEYRecordContent::TKEYRecordContent() { d_othersize
= 0; } // fix CID#1288932
504 boilerplate_conv(URI
, QType::URI
,
505 conv
.xfr16BitInt(d_priority
);
506 conv
.xfr16BitInt(d_weight
);
507 conv
.xfrText(d_target
, true, false);
510 boilerplate_conv(CAA
, QType::CAA
,
511 conv
.xfr8BitInt(d_flags
);
512 conv
.xfrUnquotedText(d_tag
, true);
513 conv
.xfrText(d_value
, true, false); /* no lenField */
516 static uint16_t makeTag(const std::string
& data
)
518 const unsigned char* key
=(const unsigned char*)data
.c_str();
519 unsigned int keysize
=data
.length();
521 unsigned long ac
; /* assumed to be 32 bits or larger */
522 unsigned int i
; /* loop index */
524 for ( ac
= 0, i
= 0; i
< keysize
; ++i
)
525 ac
+= (i
& 1) ? key
[i
] : key
[i
] << 8;
526 ac
+= (ac
>> 16) & 0xFFFF;
530 uint16_t DNSKEYRecordContent::getTag() const
532 DNSKEYRecordContent
tmp(*this);
533 return makeTag(tmp
.serialize(DNSName())); // this can't be const for some reason
536 uint16_t DNSKEYRecordContent::getTag()
538 return makeTag(this->serialize(DNSName()));
543 * Fills `eo` by parsing the EDNS(0) OPT RR (RFC 6891)
545 bool getEDNSOpts(const MOADNSParser
& mdp
, EDNSOpts
* eo
)
548 if(mdp
.d_header
.arcount
&& !mdp
.d_answers
.empty()) {
549 for(const MOADNSParser::answers_t::value_type
& val
: mdp
.d_answers
) {
550 if(val
.first
.d_place
== DNSResourceRecord::ADDITIONAL
&& val
.first
.d_type
== QType::OPT
) {
551 eo
->d_packetsize
=val
.first
.d_class
;
554 uint32_t ttl
=ntohl(val
.first
.d_ttl
);
555 static_assert(sizeof(EDNS0Record
) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
556 memcpy(&stuff
, &ttl
, sizeof(stuff
));
558 eo
->d_extRCode
=stuff
.extRCode
;
559 eo
->d_version
=stuff
.version
;
560 eo
->d_extFlags
= ntohs(stuff
.extFlags
);
561 auto orc
= getRR
<OPTRecordContent
>(val
.first
);
564 orc
->getData(eo
->d_options
);
572 DNSRecord
makeOpt(const uint16_t udpsize
, const uint16_t extRCode
, const uint16_t extFlags
)
577 stuff
.extFlags
=htons(extFlags
);
579 static_assert(sizeof(EDNS0Record
) == sizeof(dr
.d_ttl
), "sizeof(EDNS0Record) must match sizeof(DNSRecord.d_ttl)");
580 memcpy(&dr
.d_ttl
, &stuff
, sizeof(stuff
));
581 dr
.d_ttl
=ntohl(dr
.d_ttl
);
582 dr
.d_name
=g_rootdnsname
;
583 dr
.d_type
= QType::OPT
;
585 dr
.d_place
=DNSResourceRecord::ADDITIONAL
;
586 dr
.d_content
= std::make_shared
<OPTRecordContent
>();
587 // if we ever do options, I think we stuff them into OPTRecordContent::data
591 void reportBasicTypes()
593 ARecordContent::report();
594 AAAARecordContent::report();
595 NSRecordContent::report();
596 CNAMERecordContent::report();
597 MXRecordContent::report();
598 SOARecordContent::report();
599 SRVRecordContent::report();
600 PTRRecordContent::report();
601 DNSRecordContent::regist(QClass::CHAOS
, QType::TXT
, &TXTRecordContent::make
, &TXTRecordContent::make
, "TXT");
602 TXTRecordContent::report();
603 #ifdef HAVE_LUA_RECORDS
604 LUARecordContent::report();
606 DNSRecordContent::regist(QClass::IN
, QType::ANY
, 0, 0, "ANY");
607 DNSRecordContent::regist(QClass::IN
, QType::AXFR
, 0, 0, "AXFR");
608 DNSRecordContent::regist(QClass::IN
, QType::IXFR
, 0, 0, "IXFR");
611 void reportOtherTypes()
613 MBRecordContent::report();
614 MGRecordContent::report();
615 MRRecordContent::report();
616 AFSDBRecordContent::report();
617 DNAMERecordContent::report();
618 ALIASRecordContent::report();
619 SPFRecordContent::report();
620 NAPTRRecordContent::report();
621 LOCRecordContent::report();
622 ENTRecordContent::report();
623 HINFORecordContent::report();
624 RPRecordContent::report();
625 KEYRecordContent::report();
626 DNSKEYRecordContent::report();
627 DHCIDRecordContent::report();
628 CDNSKEYRecordContent::report();
629 RKEYRecordContent::report();
630 RRSIGRecordContent::report();
631 DSRecordContent::report();
632 CDSRecordContent::report();
633 SSHFPRecordContent::report();
634 CERTRecordContent::report();
635 NSECRecordContent::report();
636 NSEC3RecordContent::report();
637 NSEC3PARAMRecordContent::report();
638 TLSARecordContent::report();
639 SMIMEARecordContent::report();
640 OPENPGPKEYRecordContent::report();
641 DLVRecordContent::report();
642 DNSRecordContent::regist(QClass::ANY
, QType::TSIG
, &TSIGRecordContent::make
, &TSIGRecordContent::make
, "TSIG");
643 DNSRecordContent::regist(QClass::ANY
, QType::TKEY
, &TKEYRecordContent::make
, &TKEYRecordContent::make
, "TKEY");
644 //TSIGRecordContent::report();
645 OPTRecordContent::report();
646 EUI48RecordContent::report();
647 EUI64RecordContent::report();
648 MINFORecordContent::report();
649 URIRecordContent::report();
650 CAARecordContent::report();
653 void reportAllTypes()
659 ComboAddress
getAddr(const DNSRecord
& dr
, uint16_t defport
)
661 if(auto addr
=getRR
<ARecordContent
>(dr
)) {
662 return addr
->getCA(defport
);
665 return getRR
<AAAARecordContent
>(dr
)->getCA(defport
);
669 * Check if the DNSNames that should be hostnames, are hostnames
671 void checkHostnameCorrectness(const DNSResourceRecord
& rr
)
673 if (rr
.qtype
.getCode() == QType::NS
|| rr
.qtype
.getCode() == QType::MX
|| rr
.qtype
.getCode() == QType::SRV
) {
675 if (rr
.qtype
.getCode() == QType::SRV
) {
676 vector
<string
> parts
;
677 stringtok(parts
, rr
.getZoneRepresentation());
678 if (parts
.size() == 4) toCheck
= DNSName(parts
[3]);
679 } else if (rr
.qtype
.getCode() == QType::MX
) {
680 vector
<string
> parts
;
681 stringtok(parts
, rr
.getZoneRepresentation());
682 if (parts
.size() == 2) toCheck
= DNSName(parts
[1]);
684 toCheck
= DNSName(rr
.content
);
687 if (toCheck
.empty()) {
688 throw std::runtime_error("unable to extract hostname from content");
690 else if ((rr
.qtype
.getCode() == QType::MX
|| rr
.qtype
.getCode() == QType::SRV
) && toCheck
== g_rootdnsname
) {
692 } else if(!toCheck
.isHostname()) {
693 throw std::runtime_error(boost::str(boost::format("non-hostname content %s") % toCheck
.toString()));
699 static struct Reporter
705 } reporter
__attribute__((init_priority(65535)));