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