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