]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsrecords.cc
Merge pull request #2180 from rubenk/sanitizers
[thirdparty/pdns.git] / pdns / dnsrecords.cc
CommitLineData
4192ca66
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
0407751c 3 Copyright (C) 2005 - 2009 PowerDNS.COM BV
4192ca66
BH
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation
ff6a1e7b 8
f782fe38
MH
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12
4192ca66
BH
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.
2770fad0 17
4192ca66
BH
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
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
4192ca66
BH
21*/
22
705f31ae 23#include "utility.hh"
4192ca66 24#include "dnsrecords.hh"
0e4ab7bc 25#include <boost/foreach.hpp>
2770fad0 26
f7a69a4c
RA
27void DNSResourceRecord::setContent(const string &cont) {
28 content = cont;
b9bafae0
KM
29 switch(qtype.getCode()) {
30 case QType::SRV:
31 case QType::MX:
32 if (content.size() >= 2 && *(content.rbegin()+1) == ' ')
33 return;
34 case QType::CNAME:
35 case QType::NS:
36 if(!content.empty())
37 boost::erase_tail(content, 1);
f7a69a4c
RA
38 }
39}
40
4c22f7c5 41string DNSResourceRecord::getZoneRepresentation() const {
f7a69a4c
RA
42 ostringstream ret;
43 switch(qtype.getCode()) {
44 case QType::SRV:
45 case QType::MX:
f7a69a4c
RA
46 case QType::CNAME:
47 case QType::NS:
b9bafae0
KM
48 if (*(content.rbegin()) != '.')
49 ret<<content<<".";
50 break;
f7a69a4c
RA
51 default:
52 ret<<content;
53 break;
54 }
55 return ret.str();
56}
57
58bool DNSResourceRecord::operator==(const DNSResourceRecord& rhs)
59{
60 string lcontent=toLower(content);
61 string rcontent=toLower(rhs.content);
914353ca 62
f7a69a4c
RA
63 string llabel=toLower(qname);
64 string rlabel=toLower(rhs.qname);
914353ca
KM
65
66 return
b9bafae0
KM
67 tie(llabel, qtype, lcontent, ttl) ==
68 tie(rlabel, rhs.qtype, rcontent, rhs.ttl);
f7a69a4c
RA
69}
70
71
72
73DNSResourceRecord::DNSResourceRecord(const DNSRecord &p) {
74 auth=true;
cea26350 75 disabled=false;
f7a69a4c
RA
76 qname = p.d_label;
77 if(!qname.empty())
78 boost::erase_tail(qname, 1); // strip .
914353ca 79
f7a69a4c
RA
80 qtype = p.d_type;
81 ttl = p.d_ttl;
f7a69a4c
RA
82 setContent(p.d_content->getZoneRepresentation());
83}
84
85
3bb50daa 86boilerplate_conv(A, QType::A, conv.xfrIP(d_ip));
8c1c9170 87
3bb50daa 88ARecordContent::ARecordContent(uint32_t ip) : DNSRecordContent(QType::A)
efb265e3
BH
89{
90 d_ip = ip;
91}
92
748eff9f
BH
93uint32_t ARecordContent::getIP() const
94{
95 return d_ip;
96}
97
2770fad0
BH
98void ARecordContent::doRecordCheck(const DNSRecord& dr)
99{
100 if(dr.d_clen!=4)
7738a23f 101 throw MOADNSException("Wrong size for A record ("+lexical_cast<string>(dr.d_clen)+")");
a0a276c2 102}
ff6a1e7b 103
3bb50daa 104boilerplate_conv(AAAA, QType::AAAA, conv.xfrIP6(d_ip6); );
9d9c52ef 105
3bb50daa 106boilerplate_conv(NS, QType::NS, conv.xfrLabel(d_content, true));
107boilerplate_conv(PTR, QType::PTR, conv.xfrLabel(d_content, true));
108boilerplate_conv(CNAME, QType::CNAME, conv.xfrLabel(d_content, true));
d59b894d 109boilerplate_conv(ALIAS, QType::ALIAS, conv.xfrLabel(d_content, true));
3bb50daa 110boilerplate_conv(DNAME, QType::DNAME, conv.xfrLabel(d_content));
111boilerplate_conv(MR, QType::MR, conv.xfrLabel(d_alias, true));
112boilerplate_conv(MINFO, QType::MINFO, conv.xfrLabel(d_rmailbx, true); conv.xfrLabel(d_emailbx, true));
113boilerplate_conv(TXT, QType::TXT, conv.xfrText(d_text, true));
ef6a78d5 114boilerplate_conv(SPF, 99, conv.xfrText(d_text, true));
3bb50daa 115boilerplate_conv(HINFO, QType::HINFO, conv.xfrText(d_cpu); conv.xfrText(d_host));
ff6a1e7b 116
3bb50daa 117boilerplate_conv(RP, QType::RP,
232f0877
CH
118 conv.xfrLabel(d_mbox);
119 conv.xfrLabel(d_info)
120 );
ff6a1e7b 121
ff6a1e7b 122
3bb50daa 123boilerplate_conv(OPT, QType::OPT,
232f0877
CH
124 conv.xfrBlob(d_data)
125 );
878435ce 126
7f7b8d55
BH
127void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options)
128{
129 string::size_type pos=0;
130 uint16_t code, len;
131 while(d_data.size() >= 4 + pos) {
17d6efc0
BH
132 code = 256 * (unsigned char)d_data[pos] + (unsigned char)d_data[pos+1];
133 len = 256 * (unsigned char)d_data[pos+2] + (unsigned char)d_data[pos+3];
7f7b8d55
BH
134 pos+=4;
135
136 if(pos + len > d_data.size())
137 break;
138
139 string field(d_data.c_str() + pos, len);
140 pos+=len;
7f7b8d55
BH
141 options.push_back(make_pair(code, field));
142 }
143}
06ffdc52 144
3bb50daa 145boilerplate_conv(TSIG, QType::TSIG,
232f0877
CH
146 conv.xfrLabel(d_algoName);
147 conv.xfr48BitInt(d_time);
148 conv.xfr16BitInt(d_fudge);
149 uint16_t size=d_mac.size();
150 conv.xfr16BitInt(size);
11c029c0 151 if (size>0) conv.xfrBlobNoSpaces(d_mac, size);
232f0877
CH
152 conv.xfr16BitInt(d_origID);
153 conv.xfr16BitInt(d_eRcode);
11c029c0 154 size=d_otherData.size();
232f0877 155 conv.xfr16BitInt(size);
11c029c0 156 if (size>0) conv.xfrBlobNoSpaces(d_otherData, size);
232f0877 157 );
06ffdc52 158
3bb50daa 159MXRecordContent::MXRecordContent(uint16_t preference, const string& mxname) : DNSRecordContent(QType::MX), d_preference(preference), d_mxname(mxname)
2770fad0
BH
160{
161}
ff6a1e7b 162
3bb50daa 163boilerplate_conv(MX, QType::MX,
232f0877
CH
164 conv.xfr16BitInt(d_preference);
165 conv.xfrLabel(d_mxname, true);
166 )
ff6a1e7b 167
3bb50daa 168boilerplate_conv(KX, QType::KX,
232f0877
CH
169 conv.xfr16BitInt(d_preference);
170 conv.xfrLabel(d_exchanger, false);
171 )
9fd71f2e 172
3bb50daa 173boilerplate_conv(IPSECKEY, QType::IPSECKEY,
1cafb958
AT
174 conv.xfr8BitInt(d_preference);
175 conv.xfr8BitInt(d_gatewaytype);
176 conv.xfr8BitInt(d_algorithm);
177
178 // now we need to determine values
179 switch(d_gatewaytype) {
180 case 0: // NO KEY
181 break;
182 case 1: // IPv4 GW
183 conv.xfrIP(d_ip4);
184 break;
185 case 2: // IPv6 GW
186 conv.xfrIP6(d_ip6);
187 break;
188 case 3: // DNS label
189 conv.xfrLabel(d_gateway, false);
190 break;
191 default:
192 throw MOADNSException("Parsing record content: invalid gateway type");
193 };
194
195 switch(d_algorithm) {
196 case 0:
197 break;
198 case 1:
199 case 2:
200 conv.xfrBlob(d_publickey);
201 break;
202 default:
203 throw MOADNSException("Parsing record content: invalid algorithm type");
74b3a069
AT
204 }
205)
9fd71f2e
BH
206
207boilerplate_conv(DHCID, 49,
232f0877
CH
208 conv.xfrBlob(d_content);
209 )
9fd71f2e
BH
210
211
3bb50daa 212boilerplate_conv(AFSDB, QType::AFSDB,
232f0877
CH
213 conv.xfr16BitInt(d_subtype);
214 conv.xfrLabel(d_hostname);
215 )
37f47031 216
ff6a1e7b 217
3bb50daa 218boilerplate_conv(NAPTR, QType::NAPTR,
232f0877
CH
219 conv.xfr16BitInt(d_order); conv.xfr16BitInt(d_preference);
220 conv.xfrText(d_flags); conv.xfrText(d_services); conv.xfrText(d_regexp);
221 conv.xfrLabel(d_replacement);
222 )
8c1c9170 223
ff6a1e7b 224
2770fad0 225SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const string& target)
3bb50daa 226: DNSRecordContent(QType::SRV), d_preference(preference), d_weight(weight), d_port(port), d_target(target)
2770fad0 227{}
ff6a1e7b 228
3bb50daa 229boilerplate_conv(SRV, QType::SRV,
232f0877
CH
230 conv.xfr16BitInt(d_preference); conv.xfr16BitInt(d_weight); conv.xfr16BitInt(d_port);
231 conv.xfrLabel(d_target);
232 )
9d9c52ef 233
2770fad0 234SOARecordContent::SOARecordContent(const string& mname, const string& rname, const struct soatimes& st)
3bb50daa 235: DNSRecordContent(QType::SOA), d_mname(mname), d_rname(rname)
a0a276c2 236{
2770fad0 237 d_st=st;
a0a276c2 238}
9d9c52ef 239
3bb50daa 240boilerplate_conv(SOA, QType::SOA,
232f0877
CH
241 conv.xfrLabel(d_mname, true);
242 conv.xfrLabel(d_rname, true);
243 conv.xfr32BitInt(d_st.serial);
244 conv.xfr32BitInt(d_st.refresh);
245 conv.xfr32BitInt(d_st.retry);
246 conv.xfr32BitInt(d_st.expire);
247 conv.xfr32BitInt(d_st.minimum);
248 );
4b5762f1 249#undef KEY
3bb50daa 250boilerplate_conv(KEY, QType::KEY,
232f0877
CH
251 conv.xfr16BitInt(d_flags);
252 conv.xfr8BitInt(d_protocol);
253 conv.xfr8BitInt(d_algorithm);
254 conv.xfrBlob(d_certificate);
255 );
8c1c9170 256
2475a4fc 257boilerplate_conv(CERT, 37,
232f0877 258 conv.xfr16BitInt(d_type);
689516b3
AT
259 if (d_type == 0) throw MOADNSException("CERT type 0 is reserved");
260
232f0877
CH
261 conv.xfr16BitInt(d_tag);
262 conv.xfr8BitInt(d_algorithm);
689516b3
AT
263 conv.xfrBlob(d_certificate);
264 )
265
2a4e06e9 266boilerplate_conv(TLSA, 52,
232f0877
CH
267 conv.xfr8BitInt(d_certusage);
268 conv.xfr8BitInt(d_selector);
269 conv.xfr8BitInt(d_matchtype);
270 conv.xfrHexBlob(d_cert, true);
271 )
272
6a5b669b 273#undef DS
1c4d88c5 274DSRecordContent::DSRecordContent() : DNSRecordContent(43) {}
8c1c9170 275boilerplate_conv(DS, 43,
232f0877
CH
276 conv.xfr16BitInt(d_tag);
277 conv.xfr8BitInt(d_algorithm);
278 conv.xfr8BitInt(d_digesttype);
279 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
280 )
8c1c9170 281
0b55f2f5
BH
282DLVRecordContent::DLVRecordContent() : DNSRecordContent(32769) {}
283boilerplate_conv(DLV,32769 ,
232f0877
CH
284 conv.xfr16BitInt(d_tag);
285 conv.xfr8BitInt(d_algorithm);
286 conv.xfr8BitInt(d_digesttype);
287 conv.xfrHexBlob(d_digest, true); // keep reading across spaces
288 )
0b55f2f5
BH
289
290
a40a693b 291boilerplate_conv(SSHFP, 44,
232f0877
CH
292 conv.xfr8BitInt(d_algorithm);
293 conv.xfr8BitInt(d_fptype);
02ca1c5b 294 conv.xfrHexBlob(d_fingerprint, true);
232f0877 295 )
a40a693b 296
8c1c9170 297boilerplate_conv(RRSIG, 46,
232f0877
CH
298 conv.xfrType(d_type);
299 conv.xfr8BitInt(d_algorithm);
300 conv.xfr8BitInt(d_labels);
301 conv.xfr32BitInt(d_originalttl);
302 conv.xfrTime(d_sigexpire);
303 conv.xfrTime(d_siginception);
304 conv.xfr16BitInt(d_tag);
305 conv.xfrLabel(d_signer);
306 conv.xfrBlob(d_signature);
307 )
308
1c4d88c5
BH
309RRSIGRecordContent::RRSIGRecordContent() : DNSRecordContent(46) {}
310
8c1c9170 311boilerplate_conv(DNSKEY, 48,
232f0877
CH
312 conv.xfr16BitInt(d_flags);
313 conv.xfr8BitInt(d_protocol);
314 conv.xfr8BitInt(d_algorithm);
315 conv.xfrBlob(d_key);
316 )
1c4d88c5
BH
317DNSKEYRecordContent::DNSKEYRecordContent() : DNSRecordContent(48) {}
318
3150a49c 319boilerplate_conv(RKEY, 57,
232f0877
CH
320 conv.xfr16BitInt(d_flags);
321 conv.xfr8BitInt(d_protocol);
322 conv.xfrBlob(d_key);
323 )
3150a49c 324RKEYRecordContent::RKEYRecordContent() : DNSRecordContent(57) {}
66a07c55 325
3150a49c 326/* EUI48 start */
66a07c55
AT
327void EUI48RecordContent::report(void)
328{
3bb50daa 329 regist(1, QType::EUI48, &make, &make, "EUI48");
66a07c55
AT
330}
331DNSRecordContent* EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr)
332{
333 if(dr.d_clen!=6)
334 throw MOADNSException("Wrong size for EUI48 record");
335
336 EUI48RecordContent* ret=new EUI48RecordContent();
337 pr.copyRecord((uint8_t*) &ret->d_eui48, 6);
338 return ret;
339}
340DNSRecordContent* EUI48RecordContent::make(const string& zone)
341{
342 // try to parse
343 EUI48RecordContent *ret=new EUI48RecordContent();
344 // format is 6 hex bytes and dashes
345 if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
346 ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2,
347 ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) {
0fc965fd 348 throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse");
66a07c55
AT
349 }
350 return ret;
351}
352void EUI48RecordContent::toPacket(DNSPacketWriter& pw)
353{
354 string blob(d_eui48, d_eui48+6);
355 pw.xfrBlob(blob);
356}
357string EUI48RecordContent::getZoneRepresentation() const
358{
359 char tmp[18];
360 snprintf(tmp,18,"%02x-%02x-%02x-%02x-%02x-%02x",
361 d_eui48[0], d_eui48[1], d_eui48[2],
362 d_eui48[3], d_eui48[4], d_eui48[5]);
363 return tmp;
364}
365
366/* EUI48 end */
367
368/* EUI64 start */
369
370void EUI64RecordContent::report(void)
371{
3bb50daa 372 regist(1, QType::EUI64, &make, &make, "EUI64");
66a07c55
AT
373}
374DNSRecordContent* EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr)
375{
376 if(dr.d_clen!=8)
377 throw MOADNSException("Wrong size for EUI64 record");
378
379 EUI64RecordContent* ret=new EUI64RecordContent();
380 pr.copyRecord((uint8_t*) &ret->d_eui64, 8);
381 return ret;
382}
383DNSRecordContent* EUI64RecordContent::make(const string& zone)
384{
385 // try to parse
386 EUI64RecordContent *ret=new EUI64RecordContent();
387 // format is 8 hex bytes and dashes
388 if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
389 ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2,
390 ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5,
391 ret->d_eui64+6, ret->d_eui64+7) != 8) {
392 throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse");
393 }
394 return ret;
395}
396void EUI64RecordContent::toPacket(DNSPacketWriter& pw)
397{
398 string blob(d_eui64, d_eui64+8);
399 pw.xfrBlob(blob);
400}
401string EUI64RecordContent::getZoneRepresentation() const
402{
403 char tmp[24];
404 snprintf(tmp,24,"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
405 d_eui64[0], d_eui64[1], d_eui64[2],
406 d_eui64[3], d_eui64[4], d_eui64[5],
407 d_eui64[6], d_eui64[7]);
408 return tmp;
409}
410
411/* EUI64 end */
412
413
1c4d88c5
BH
414uint16_t DNSKEYRecordContent::getTag()
415{
416 string data=this->serialize("");
417 const unsigned char* key=(const unsigned char*)data.c_str();
418 unsigned int keysize=data.length();
419
420 unsigned long ac; /* assumed to be 32 bits or larger */
421 unsigned int i; /* loop index */
422
423 for ( ac = 0, i = 0; i < keysize; ++i )
424 ac += (i & 1) ? key[i] : key[i] << 8;
425 ac += (ac >> 16) & 0xFFFF;
426 return ac & 0xFFFF;
427}
428
7f7b8d55
BH
429bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo)
430{
0e4ab7bc
BH
431 if(mdp.d_header.arcount && !mdp.d_answers.empty()) {
432 BOOST_FOREACH(const MOADNSParser::answers_t::value_type& val, mdp.d_answers) {
433 if(val.first.d_place == DNSRecord::Additional && val.first.d_type == QType::OPT) {
232f0877 434 eo->d_packetsize=val.first.d_class;
0e4ab7bc 435
232f0877
CH
436 EDNS0Record stuff;
437 uint32_t ttl=ntohl(val.first.d_ttl);
438 memcpy(&stuff, &ttl, sizeof(stuff));
439
440 eo->d_extRCode=stuff.extRCode;
441 eo->d_version=stuff.version;
442 eo->d_Z = ntohs(stuff.Z);
443 OPTRecordContent* orc =
444 dynamic_cast<OPTRecordContent*>(val.first.d_content.get());
445 if(!orc)
446 return false;
447 orc->getData(eo->d_options);
448 return true;
0e4ab7bc
BH
449 }
450 }
7f7b8d55 451 }
0e4ab7bc 452 return false;
7f7b8d55
BH
453}
454
455
ea634573 456void reportBasicTypes()
ff6a1e7b 457{
a9af3782
BH
458 ARecordContent::report();
459 AAAARecordContent::report();
460 NSRecordContent::report();
461 CNAMERecordContent::report();
462 MXRecordContent::report();
463 SOARecordContent::report();
464 SRVRecordContent::report();
465 PTRRecordContent::report();
3bb50daa 466 DNSRecordContent::regist(QClass::CHAOS, QType::TXT, &TXTRecordContent::make, &TXTRecordContent::make, "TXT");
a6a83beb 467 TXTRecordContent::report();
703761cc 468 DNSRecordContent::regist(QClass::IN, QType::ANY, 0, 0, "ANY");
ea634573
BH
469}
470
471void reportOtherTypes()
472{
37f47031 473 AFSDBRecordContent::report();
8dee0750 474 DNAMERecordContent::report();
d59b894d 475 ALIASRecordContent::report();
ea634573
BH
476 SPFRecordContent::report();
477 NAPTRRecordContent::report();
c6a60874 478 LOCRecordContent::report();
9770663f 479 HINFORecordContent::report();
ea634573 480 RPRecordContent::report();
4b5762f1 481 KEYRecordContent::report();
ea634573 482 DNSKEYRecordContent::report();
3150a49c 483 RKEYRecordContent::report();
ea634573
BH
484 RRSIGRecordContent::report();
485 DSRecordContent::report();
59a0f653 486 SSHFPRecordContent::report();
2475a4fc 487 CERTRecordContent::report();
ea634573 488 NSECRecordContent::report();
1c4d88c5
BH
489 NSEC3RecordContent::report();
490 NSEC3PARAMRecordContent::report();
07dbe87e 491 TLSARecordContent::report();
4fb75774 492 DLVRecordContent::report();
703761cc 493 DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG");
b7c7d872 494 //TSIGRecordContent::report();
ea634573 495 OPTRecordContent::report();
66a07c55
AT
496 EUI48RecordContent::report();
497 EUI64RecordContent::report();
5eea7309 498 MINFORecordContent::report();
ea634573
BH
499}
500
501void reportAllTypes()
502{
503 reportBasicTypes();
504 reportOtherTypes();
505}
506
507#if 0
508static struct Reporter
509{
510 Reporter()
511 {
512 reportAllTypes();
ff6a1e7b
BH
513 }
514} reporter __attribute__((init_priority(65535)));
250d1fd8 515#endif