]>
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 boost::erase_tail(content
, 1);
46 string
DNSResourceRecord::getZoneRepresentation(bool noDot
) const {
48 switch(qtype
.getCode()) {
55 if (*(content
.rbegin()) != '.') {
68 bool DNSResourceRecord::operator==(const DNSResourceRecord
& rhs
)
70 string lcontent
=toLower(content
);
71 string rcontent
=toLower(rhs
.content
);
74 tie(qname
, qtype
, lcontent
, ttl
) ==
75 tie(rhs
.qname
, rhs
.qtype
, rcontent
, rhs
.ttl
);
78 DNSResourceRecord::DNSResourceRecord(const DNSRecord
&p
) {
85 // boost::erase_tail(qname, 1); // strip .
89 setContent(p
.d_content
->getZoneRepresentation());
98 boilerplate_conv(A
, QType::A
, conv
.xfrIP(d_ip
));
100 ARecordContent::ARecordContent(uint32_t ip
)
105 ARecordContent::ARecordContent(const ComboAddress
& ca
)
107 d_ip
= ca
.sin4
.sin_addr
.s_addr
;
110 AAAARecordContent::AAAARecordContent(const ComboAddress
& ca
)
112 d_ip6
.assign((const char*)ca
.sin6
.sin6_addr
.s6_addr
, 16);
116 ComboAddress
ARecordContent::getCA(int port
) const
119 ret
.sin4
.sin_family
=AF_INET
;
120 ret
.sin4
.sin_port
=htons(port
);
121 memcpy(&ret
.sin4
.sin_addr
.s_addr
, &d_ip
, sizeof(ret
.sin4
.sin_addr
.s_addr
));
125 ComboAddress
AAAARecordContent::getCA(int port
) const
128 memset(&ret
, 0, sizeof(ret
));
130 ret
.sin4
.sin_family
=AF_INET6
;
131 ret
.sin6
.sin6_port
= htons(port
);
132 memcpy(&ret
.sin6
.sin6_addr
.s6_addr
, d_ip6
.c_str(), sizeof(ret
.sin6
.sin6_addr
.s6_addr
));
137 void ARecordContent::doRecordCheck(const DNSRecord
& dr
)
140 throw MOADNSException("Wrong size for A record ("+std::to_string(dr
.d_clen
)+")");
143 boilerplate_conv(AAAA
, QType::AAAA
, conv
.xfrIP6(d_ip6
); );
145 boilerplate_conv(NS
, QType::NS
, conv
.xfrName(d_content
, true));
146 boilerplate_conv(PTR
, QType::PTR
, conv
.xfrName(d_content
, true));
147 boilerplate_conv(CNAME
, QType::CNAME
, conv
.xfrName(d_content
, true));
148 boilerplate_conv(ALIAS
, QType::ALIAS
, conv
.xfrName(d_content
, true));
149 boilerplate_conv(DNAME
, QType::DNAME
, conv
.xfrName(d_content
));
150 boilerplate_conv(MR
, QType::MR
, conv
.xfrName(d_alias
, true));
151 boilerplate_conv(MINFO
, QType::MINFO
, conv
.xfrName(d_rmailbx
, true); conv
.xfrName(d_emailbx
, true));
152 boilerplate_conv(TXT
, QType::TXT
, conv
.xfrText(d_text
, true));
153 boilerplate_conv(SPF
, 99, conv
.xfrText(d_text
, true));
154 boilerplate_conv(HINFO
, QType::HINFO
, conv
.xfrText(d_cpu
); conv
.xfrText(d_host
));
156 boilerplate_conv(RP
, QType::RP
,
157 conv
.xfrName(d_mbox
);
162 boilerplate_conv(OPT
, QType::OPT
,
166 void OPTRecordContent::getData(vector
<pair
<uint16_t, string
> >& options
)
168 string::size_type pos
=0;
170 while(d_data
.size() >= 4 + pos
) {
171 code
= 256 * (unsigned char)d_data
[pos
] + (unsigned char)d_data
[pos
+1];
172 len
= 256 * (unsigned char)d_data
[pos
+2] + (unsigned char)d_data
[pos
+3];
175 if(pos
+ len
> d_data
.size())
178 string
field(d_data
.c_str() + pos
, len
);
180 options
.push_back(make_pair(code
, field
));
184 boilerplate_conv(TSIG
, QType::TSIG
,
185 conv
.xfrName(d_algoName
);
186 conv
.xfr48BitInt(d_time
);
187 conv
.xfr16BitInt(d_fudge
);
188 uint16_t size
=d_mac
.size();
189 conv
.xfr16BitInt(size
);
190 if (size
>0) conv
.xfrBlobNoSpaces(d_mac
, size
);
191 conv
.xfr16BitInt(d_origID
);
192 conv
.xfr16BitInt(d_eRcode
);
193 size
=d_otherData
.size();
194 conv
.xfr16BitInt(size
);
195 if (size
>0) conv
.xfrBlobNoSpaces(d_otherData
, size
);
198 MXRecordContent::MXRecordContent(uint16_t preference
, const DNSName
& mxname
): d_preference(preference
), d_mxname(mxname
)
202 boilerplate_conv(MX
, QType::MX
,
203 conv
.xfr16BitInt(d_preference
);
204 conv
.xfrName(d_mxname
, true);
207 boilerplate_conv(KX
, QType::KX
,
208 conv
.xfr16BitInt(d_preference
);
209 conv
.xfrName(d_exchanger
, false);
212 boilerplate_conv(IPSECKEY
, QType::IPSECKEY
,
213 conv
.xfr8BitInt(d_preference
);
214 conv
.xfr8BitInt(d_gatewaytype
);
215 conv
.xfr8BitInt(d_algorithm
);
217 // now we need to determine values
218 switch(d_gatewaytype
) {
228 conv
.xfrName(d_gateway
, false);
231 throw MOADNSException("Parsing record content: invalid gateway type");
234 switch(d_algorithm
) {
239 conv
.xfrBlob(d_publickey
);
242 throw MOADNSException("Parsing record content: invalid algorithm type");
246 boilerplate_conv(DHCID
, 49,
247 conv
.xfrBlob(d_content
);
251 boilerplate_conv(AFSDB
, QType::AFSDB
,
252 conv
.xfr16BitInt(d_subtype
);
253 conv
.xfrName(d_hostname
);
257 boilerplate_conv(NAPTR
, QType::NAPTR
,
258 conv
.xfr16BitInt(d_order
); conv
.xfr16BitInt(d_preference
);
259 conv
.xfrText(d_flags
); conv
.xfrText(d_services
); conv
.xfrText(d_regexp
);
260 conv
.xfrName(d_replacement
);
264 SRVRecordContent::SRVRecordContent(uint16_t preference
, uint16_t weight
, uint16_t port
, const DNSName
& target
)
265 : d_weight(weight
), d_port(port
), d_target(target
), d_preference(preference
)
268 boilerplate_conv(SRV
, QType::SRV
,
269 conv
.xfr16BitInt(d_preference
); conv
.xfr16BitInt(d_weight
); conv
.xfr16BitInt(d_port
);
270 conv
.xfrName(d_target
);
273 SOARecordContent::SOARecordContent(const DNSName
& mname
, const DNSName
& rname
, const struct soatimes
& st
)
274 : d_mname(mname
), d_rname(rname
)
279 boilerplate_conv(SOA
, QType::SOA
,
280 conv
.xfrName(d_mname
, true);
281 conv
.xfrName(d_rname
, true);
282 conv
.xfr32BitInt(d_st
.serial
);
283 conv
.xfr32BitInt(d_st
.refresh
);
284 conv
.xfr32BitInt(d_st
.retry
);
285 conv
.xfr32BitInt(d_st
.expire
);
286 conv
.xfr32BitInt(d_st
.minimum
);
289 boilerplate_conv(KEY
, QType::KEY
,
290 conv
.xfr16BitInt(d_flags
);
291 conv
.xfr8BitInt(d_protocol
);
292 conv
.xfr8BitInt(d_algorithm
);
293 conv
.xfrBlob(d_certificate
);
296 boilerplate_conv(CERT
, 37,
297 conv
.xfr16BitInt(d_type
);
298 if (d_type
== 0) throw MOADNSException("CERT type 0 is reserved");
300 conv
.xfr16BitInt(d_tag
);
301 conv
.xfr8BitInt(d_algorithm
);
302 conv
.xfrBlob(d_certificate
);
305 boilerplate_conv(TLSA
, 52,
306 conv
.xfr8BitInt(d_certusage
);
307 conv
.xfr8BitInt(d_selector
);
308 conv
.xfr8BitInt(d_matchtype
);
309 conv
.xfrHexBlob(d_cert
, true);
312 boilerplate_conv(OPENPGPKEY
, 61,
313 conv
.xfrBlob(d_keyring
);
316 DSRecordContent::DSRecordContent() {}
317 boilerplate_conv(DS
, 43,
318 conv
.xfr16BitInt(d_tag
);
319 conv
.xfr8BitInt(d_algorithm
);
320 conv
.xfr8BitInt(d_digesttype
);
321 conv
.xfrHexBlob(d_digest
, true); // keep reading across spaces
324 CDSRecordContent::CDSRecordContent() {}
325 boilerplate_conv(CDS
, 59,
326 conv
.xfr16BitInt(d_tag
);
327 conv
.xfr8BitInt(d_algorithm
);
328 conv
.xfr8BitInt(d_digesttype
);
329 conv
.xfrHexBlob(d_digest
, true); // keep reading across spaces
332 DLVRecordContent::DLVRecordContent() {}
333 boilerplate_conv(DLV
,32769 ,
334 conv
.xfr16BitInt(d_tag
);
335 conv
.xfr8BitInt(d_algorithm
);
336 conv
.xfr8BitInt(d_digesttype
);
337 conv
.xfrHexBlob(d_digest
, true); // keep reading across spaces
341 boilerplate_conv(SSHFP
, 44,
342 conv
.xfr8BitInt(d_algorithm
);
343 conv
.xfr8BitInt(d_fptype
);
344 conv
.xfrHexBlob(d_fingerprint
, true);
347 boilerplate_conv(RRSIG
, 46,
348 conv
.xfrType(d_type
);
349 conv
.xfr8BitInt(d_algorithm
);
350 conv
.xfr8BitInt(d_labels
);
351 conv
.xfr32BitInt(d_originalttl
);
352 conv
.xfrTime(d_sigexpire
);
353 conv
.xfrTime(d_siginception
);
354 conv
.xfr16BitInt(d_tag
);
355 conv
.xfrName(d_signer
);
356 conv
.xfrBlob(d_signature
);
359 RRSIGRecordContent::RRSIGRecordContent() {}
361 boilerplate_conv(DNSKEY
, 48,
362 conv
.xfr16BitInt(d_flags
);
363 conv
.xfr8BitInt(d_protocol
);
364 conv
.xfr8BitInt(d_algorithm
);
367 DNSKEYRecordContent::DNSKEYRecordContent() {}
369 boilerplate_conv(CDNSKEY
, 60,
370 conv
.xfr16BitInt(d_flags
);
371 conv
.xfr8BitInt(d_protocol
);
372 conv
.xfr8BitInt(d_algorithm
);
375 CDNSKEYRecordContent::CDNSKEYRecordContent() {}
377 boilerplate_conv(RKEY
, 57,
378 conv
.xfr16BitInt(d_flags
);
379 conv
.xfr8BitInt(d_protocol
);
382 RKEYRecordContent::RKEYRecordContent() {}
385 void EUI48RecordContent::report(void)
387 regist(1, QType::EUI48
, &make
, &make
, "EUI48");
389 DNSRecordContent
* EUI48RecordContent::make(const DNSRecord
&dr
, PacketReader
& pr
)
392 throw MOADNSException("Wrong size for EUI48 record");
394 EUI48RecordContent
* ret
=new EUI48RecordContent();
395 pr
.copyRecord((uint8_t*) &ret
->d_eui48
, 6);
398 DNSRecordContent
* EUI48RecordContent::make(const string
& zone
)
401 EUI48RecordContent
*ret
=new EUI48RecordContent();
402 // format is 6 hex bytes and dashes
403 if (sscanf(zone
.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
404 ret
->d_eui48
, ret
->d_eui48
+1, ret
->d_eui48
+2,
405 ret
->d_eui48
+3, ret
->d_eui48
+4, ret
->d_eui48
+5) != 6) {
406 throw MOADNSException("Asked to encode '"+zone
+"' as an EUI48 address, but does not parse");
410 void EUI48RecordContent::toPacket(DNSPacketWriter
& pw
)
412 string
blob(d_eui48
, d_eui48
+6);
415 string
EUI48RecordContent::getZoneRepresentation(bool noDot
) const
418 snprintf(tmp
,sizeof(tmp
),"%02x-%02x-%02x-%02x-%02x-%02x",
419 d_eui48
[0], d_eui48
[1], d_eui48
[2],
420 d_eui48
[3], d_eui48
[4], d_eui48
[5]);
428 void EUI64RecordContent::report(void)
430 regist(1, QType::EUI64
, &make
, &make
, "EUI64");
432 DNSRecordContent
* EUI64RecordContent::make(const DNSRecord
&dr
, PacketReader
& pr
)
435 throw MOADNSException("Wrong size for EUI64 record");
437 EUI64RecordContent
* ret
=new EUI64RecordContent();
438 pr
.copyRecord((uint8_t*) &ret
->d_eui64
, 8);
441 DNSRecordContent
* EUI64RecordContent::make(const string
& zone
)
444 EUI64RecordContent
*ret
=new EUI64RecordContent();
445 // format is 8 hex bytes and dashes
446 if (sscanf(zone
.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
447 ret
->d_eui64
, ret
->d_eui64
+1, ret
->d_eui64
+2,
448 ret
->d_eui64
+3, ret
->d_eui64
+4, ret
->d_eui64
+5,
449 ret
->d_eui64
+6, ret
->d_eui64
+7) != 8) {
450 throw MOADNSException("Asked to encode '"+zone
+"' as an EUI64 address, but does not parse");
454 void EUI64RecordContent::toPacket(DNSPacketWriter
& pw
)
456 string
blob(d_eui64
, d_eui64
+8);
459 string
EUI64RecordContent::getZoneRepresentation(bool noDot
) const
462 snprintf(tmp
,sizeof(tmp
),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
463 d_eui64
[0], d_eui64
[1], d_eui64
[2],
464 d_eui64
[3], d_eui64
[4], d_eui64
[5],
465 d_eui64
[6], d_eui64
[7]);
471 boilerplate_conv(TKEY
, QType::TKEY
,
472 conv
.xfrName(d_algo
);
473 conv
.xfr32BitInt(d_inception
);
474 conv
.xfr32BitInt(d_expiration
);
475 conv
.xfr16BitInt(d_mode
);
476 conv
.xfr16BitInt(d_error
);
477 conv
.xfr16BitInt(d_keysize
);
478 if (d_keysize
>0) conv
.xfrBlobNoSpaces(d_key
, d_keysize
);
479 conv
.xfr16BitInt(d_othersize
);
480 if (d_othersize
>0) conv
.xfrBlobNoSpaces(d_other
, d_othersize
);
482 TKEYRecordContent::TKEYRecordContent() { d_othersize
= 0; } // fix CID#1288932
484 boilerplate_conv(URI
, QType::URI
,
485 conv
.xfr8BitInt(d_priority
);
486 conv
.xfr8BitInt(d_weight
);
487 conv
.xfrText(d_target
, true, false);
490 boilerplate_conv(CAA
, QType::CAA
,
491 conv
.xfr8BitInt(d_flags
);
492 conv
.xfrUnquotedText(d_tag
, true);
493 conv
.xfrText(d_value
, true, false); /* no lenField */
496 static uint16_t makeTag(const std::string
& data
)
498 const unsigned char* key
=(const unsigned char*)data
.c_str();
499 unsigned int keysize
=data
.length();
501 unsigned long ac
; /* assumed to be 32 bits or larger */
502 unsigned int i
; /* loop index */
504 for ( ac
= 0, i
= 0; i
< keysize
; ++i
)
505 ac
+= (i
& 1) ? key
[i
] : key
[i
] << 8;
506 ac
+= (ac
>> 16) & 0xFFFF;
510 uint16_t DNSKEYRecordContent::getTag() const
512 DNSKEYRecordContent
tmp(*this);
513 return makeTag(tmp
.serialize(DNSName())); // this can't be const for some reason
516 uint16_t DNSKEYRecordContent::getTag()
518 return makeTag(this->serialize(DNSName()));
522 bool getEDNSOpts(const MOADNSParser
& mdp
, EDNSOpts
* eo
)
525 if(mdp
.d_header
.arcount
&& !mdp
.d_answers
.empty()) {
526 for(const MOADNSParser::answers_t::value_type
& val
: mdp
.d_answers
) {
527 if(val
.first
.d_place
== DNSResourceRecord::ADDITIONAL
&& val
.first
.d_type
== QType::OPT
) {
528 eo
->d_packetsize
=val
.first
.d_class
;
531 uint32_t ttl
=ntohl(val
.first
.d_ttl
);
532 static_assert(sizeof(EDNS0Record
) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
533 memcpy(&stuff
, &ttl
, sizeof(stuff
));
535 eo
->d_extRCode
=stuff
.extRCode
;
536 eo
->d_version
=stuff
.version
;
537 eo
->d_Z
= ntohs(stuff
.Z
);
538 OPTRecordContent
* orc
=
539 dynamic_cast<OPTRecordContent
*>(val
.first
.d_content
.get());
542 orc
->getData(eo
->d_options
);
550 DNSRecord
makeOpt(int udpsize
, int extRCode
, int Z
)
557 static_assert(sizeof(EDNS0Record
) == sizeof(dr
.d_ttl
), "sizeof(EDNS0Record) must match sizeof(DNSRecord.d_ttl)");
558 memcpy(&dr
.d_ttl
, &stuff
, sizeof(stuff
));
559 dr
.d_ttl
=ntohl(dr
.d_ttl
);
560 dr
.d_name
=DNSName(".");
561 dr
.d_type
= QType::OPT
;
563 dr
.d_place
=DNSResourceRecord::ADDITIONAL
;
564 dr
.d_content
= std::make_shared
<OPTRecordContent
>();
565 // if we ever do options, I think we stuff them into OPTRecordContent::data
570 void reportBasicTypes()
572 ARecordContent::report();
573 AAAARecordContent::report();
574 NSRecordContent::report();
575 CNAMERecordContent::report();
576 MXRecordContent::report();
577 SOARecordContent::report();
578 SRVRecordContent::report();
579 PTRRecordContent::report();
580 DNSRecordContent::regist(QClass::CHAOS
, QType::TXT
, &TXTRecordContent::make
, &TXTRecordContent::make
, "TXT");
581 TXTRecordContent::report();
582 DNSRecordContent::regist(QClass::IN
, QType::ANY
, 0, 0, "ANY");
583 DNSRecordContent::regist(QClass::IN
, QType::AXFR
, 0, 0, "AXFR");
584 DNSRecordContent::regist(QClass::IN
, QType::IXFR
, 0, 0, "IXFR");
587 void reportOtherTypes()
589 AFSDBRecordContent::report();
590 DNAMERecordContent::report();
591 ALIASRecordContent::report();
592 SPFRecordContent::report();
593 NAPTRRecordContent::report();
594 LOCRecordContent::report();
595 HINFORecordContent::report();
596 RPRecordContent::report();
597 KEYRecordContent::report();
598 DNSKEYRecordContent::report();
599 DHCIDRecordContent::report();
600 CDNSKEYRecordContent::report();
601 RKEYRecordContent::report();
602 RRSIGRecordContent::report();
603 DSRecordContent::report();
604 CDSRecordContent::report();
605 SSHFPRecordContent::report();
606 CERTRecordContent::report();
607 NSECRecordContent::report();
608 NSEC3RecordContent::report();
609 NSEC3PARAMRecordContent::report();
610 TLSARecordContent::report();
611 OPENPGPKEYRecordContent::report();
612 DLVRecordContent::report();
613 DNSRecordContent::regist(QClass::ANY
, QType::TSIG
, &TSIGRecordContent::make
, &TSIGRecordContent::make
, "TSIG");
614 DNSRecordContent::regist(QClass::ANY
, QType::TKEY
, &TKEYRecordContent::make
, &TKEYRecordContent::make
, "TKEY");
615 //TSIGRecordContent::report();
616 OPTRecordContent::report();
617 EUI48RecordContent::report();
618 EUI64RecordContent::report();
619 MINFORecordContent::report();
620 URIRecordContent::report();
621 CAARecordContent::report();
624 void reportAllTypes()
630 ComboAddress
getAddr(const DNSRecord
& dr
, uint16_t defport
)
632 if(auto addr
=getRR
<ARecordContent
>(dr
)) {
633 return addr
->getCA(defport
);
636 return getRR
<AAAARecordContent
>(dr
)->getCA(defport
);
641 static struct Reporter
647 } reporter
__attribute__((init_priority(65535)));