]>
Commit | Line | Data |
---|---|---|
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 | |
4192ca66 BH |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
2770fad0 | 13 | |
4192ca66 BH |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software | |
06bd9ccf | 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
4192ca66 BH |
17 | */ |
18 | ||
705f31ae | 19 | #include "utility.hh" |
4192ca66 | 20 | #include "dnsrecords.hh" |
0e4ab7bc | 21 | #include <boost/foreach.hpp> |
2770fad0 | 22 | |
8c1c9170 BH |
23 | boilerplate_conv(A, ns_t_a, conv.xfrIP(d_ip)); |
24 | ||
efb265e3 BH |
25 | ARecordContent::ARecordContent(uint32_t ip) : DNSRecordContent(ns_t_a) |
26 | { | |
27 | d_ip = ip; | |
28 | } | |
29 | ||
748eff9f BH |
30 | uint32_t ARecordContent::getIP() const |
31 | { | |
32 | return d_ip; | |
33 | } | |
34 | ||
2770fad0 BH |
35 | void ARecordContent::doRecordCheck(const DNSRecord& dr) |
36 | { | |
37 | if(dr.d_clen!=4) | |
7738a23f | 38 | throw MOADNSException("Wrong size for A record ("+lexical_cast<string>(dr.d_clen)+")"); |
a0a276c2 | 39 | } |
ff6a1e7b | 40 | |
fc465b41 | 41 | boilerplate_conv(AAAA, ns_t_aaaa, conv.xfrIP6(d_ip6); ); |
9d9c52ef | 42 | |
bca6643b BH |
43 | boilerplate_conv(NS, ns_t_ns, conv.xfrLabel(d_content, true)); |
44 | boilerplate_conv(PTR, ns_t_ptr, conv.xfrLabel(d_content, true)); | |
45 | boilerplate_conv(CNAME, ns_t_cname, conv.xfrLabel(d_content, true)); | |
2dd20a07 | 46 | boilerplate_conv(MR, ns_t_mr, conv.xfrLabel(d_alias, true)); |
7c0b8593 | 47 | boilerplate_conv(MINFO, ns_t_minfo, conv.xfrLabel(d_rmailbx, true); conv.xfrLabel(d_emailbx, true)); |
ef6a78d5 BH |
48 | boilerplate_conv(TXT, ns_t_txt, conv.xfrText(d_text, true)); |
49 | boilerplate_conv(SPF, 99, conv.xfrText(d_text, true)); | |
8c1c9170 | 50 | boilerplate_conv(HINFO, ns_t_hinfo, conv.xfrText(d_cpu); conv.xfrText(d_host)); |
ff6a1e7b | 51 | |
8c1c9170 | 52 | boilerplate_conv(RP, ns_t_rp, |
4957a608 BH |
53 | conv.xfrLabel(d_mbox); |
54 | conv.xfrLabel(d_info) | |
55 | ); | |
ff6a1e7b | 56 | |
ff6a1e7b | 57 | |
7f7b8d55 | 58 | boilerplate_conv(OPT, ns_t_opt, |
4957a608 BH |
59 | conv.xfrBlob(d_data) |
60 | ); | |
878435ce | 61 | |
7f7b8d55 BH |
62 | void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options) |
63 | { | |
64 | string::size_type pos=0; | |
65 | uint16_t code, len; | |
66 | while(d_data.size() >= 4 + pos) { | |
17d6efc0 BH |
67 | code = 256 * (unsigned char)d_data[pos] + (unsigned char)d_data[pos+1]; |
68 | len = 256 * (unsigned char)d_data[pos+2] + (unsigned char)d_data[pos+3]; | |
7f7b8d55 BH |
69 | pos+=4; |
70 | ||
71 | if(pos + len > d_data.size()) | |
72 | break; | |
73 | ||
74 | string field(d_data.c_str() + pos, len); | |
75 | pos+=len; | |
7f7b8d55 BH |
76 | options.push_back(make_pair(code, field)); |
77 | } | |
78 | } | |
06ffdc52 | 79 | |
a6a83beb | 80 | boilerplate_conv(TSIG, ns_t_tsig, |
4957a608 BH |
81 | conv.xfrLabel(d_algoName); |
82 | conv.xfr48BitInt(d_time); | |
83 | conv.xfr16BitInt(d_fudge); | |
84 | uint16_t size=d_mac.size(); | |
85 | conv.xfr16BitInt(size); | |
86 | conv.xfrBlob(d_mac, size); | |
87 | conv.xfr16BitInt(d_origID); | |
88 | conv.xfr16BitInt(d_eRcode); | |
a6a83beb AT |
89 | size=d_otherData.size(); |
90 | conv.xfr16BitInt(size); | |
91 | if (size>0) conv.xfrBlob(d_otherData, size); | |
4957a608 | 92 | ); |
06ffdc52 | 93 | |
ea634573 | 94 | MXRecordContent::MXRecordContent(uint16_t preference, const string& mxname) : DNSRecordContent(ns_t_mx), d_preference(preference), d_mxname(mxname) |
2770fad0 BH |
95 | { |
96 | } | |
ff6a1e7b | 97 | |
8c1c9170 | 98 | boilerplate_conv(MX, ns_t_mx, |
4957a608 BH |
99 | conv.xfr16BitInt(d_preference); |
100 | conv.xfrLabel(d_mxname, true); | |
101 | ) | |
ff6a1e7b | 102 | |
39d464c4 | 103 | boilerplate_conv(KX, ns_t_kx, |
4957a608 BH |
104 | conv.xfr16BitInt(d_preference); |
105 | conv.xfrLabel(d_exchanger, false); | |
106 | ) | |
9fd71f2e | 107 | |
74b3a069 | 108 | boilerplate_conv(IPSECKEY, ns_t_ipseckey, |
1cafb958 AT |
109 | conv.xfr8BitInt(d_preference); |
110 | conv.xfr8BitInt(d_gatewaytype); | |
111 | conv.xfr8BitInt(d_algorithm); | |
112 | ||
113 | // now we need to determine values | |
114 | switch(d_gatewaytype) { | |
115 | case 0: // NO KEY | |
116 | break; | |
117 | case 1: // IPv4 GW | |
118 | conv.xfrIP(d_ip4); | |
119 | break; | |
120 | case 2: // IPv6 GW | |
121 | conv.xfrIP6(d_ip6); | |
122 | break; | |
123 | case 3: // DNS label | |
124 | conv.xfrLabel(d_gateway, false); | |
125 | break; | |
126 | default: | |
127 | throw MOADNSException("Parsing record content: invalid gateway type"); | |
128 | }; | |
129 | ||
130 | switch(d_algorithm) { | |
131 | case 0: | |
132 | break; | |
133 | case 1: | |
134 | case 2: | |
135 | conv.xfrBlob(d_publickey); | |
136 | break; | |
137 | default: | |
138 | throw MOADNSException("Parsing record content: invalid algorithm type"); | |
74b3a069 AT |
139 | } |
140 | ) | |
9fd71f2e BH |
141 | |
142 | boilerplate_conv(DHCID, 49, | |
4957a608 BH |
143 | conv.xfrBlob(d_content); |
144 | ) | |
9fd71f2e BH |
145 | |
146 | ||
37f47031 | 147 | boilerplate_conv(AFSDB, ns_t_afsdb, |
4957a608 BH |
148 | conv.xfr16BitInt(d_subtype); |
149 | conv.xfrLabel(d_hostname); | |
150 | ) | |
37f47031 | 151 | |
ff6a1e7b | 152 | |
8c1c9170 | 153 | boilerplate_conv(NAPTR, ns_t_naptr, |
4957a608 BH |
154 | conv.xfr16BitInt(d_order); conv.xfr16BitInt(d_preference); |
155 | conv.xfrText(d_flags); conv.xfrText(d_services); conv.xfrText(d_regexp); | |
156 | conv.xfrLabel(d_replacement); | |
157 | ) | |
8c1c9170 | 158 | |
ff6a1e7b | 159 | |
2770fad0 | 160 | SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const string& target) |
ea634573 | 161 | : DNSRecordContent(ns_t_srv), d_preference(preference), d_weight(weight), d_port(port), d_target(target) |
2770fad0 | 162 | {} |
ff6a1e7b | 163 | |
8c1c9170 | 164 | boilerplate_conv(SRV, ns_t_srv, |
4957a608 | 165 | conv.xfr16BitInt(d_preference); conv.xfr16BitInt(d_weight); conv.xfr16BitInt(d_port); |
8655a427 | 166 | conv.xfrLabel(d_target); |
4957a608 | 167 | ) |
9d9c52ef | 168 | |
2770fad0 | 169 | SOARecordContent::SOARecordContent(const string& mname, const string& rname, const struct soatimes& st) |
ea634573 | 170 | : DNSRecordContent(ns_t_soa), d_mname(mname), d_rname(rname) |
a0a276c2 | 171 | { |
2770fad0 | 172 | d_st=st; |
a0a276c2 | 173 | } |
9d9c52ef | 174 | |
8c1c9170 | 175 | boilerplate_conv(SOA, ns_t_soa, |
4957a608 BH |
176 | conv.xfrLabel(d_mname, true); |
177 | conv.xfrLabel(d_rname, true); | |
178 | conv.xfr32BitInt(d_st.serial); | |
179 | conv.xfr32BitInt(d_st.refresh); | |
180 | conv.xfr32BitInt(d_st.retry); | |
181 | conv.xfr32BitInt(d_st.expire); | |
182 | conv.xfr32BitInt(d_st.minimum); | |
183 | ); | |
4b5762f1 BH |
184 | #undef KEY |
185 | boilerplate_conv(KEY, ns_t_key, | |
4957a608 BH |
186 | conv.xfr16BitInt(d_flags); |
187 | conv.xfr8BitInt(d_protocol); | |
188 | conv.xfr8BitInt(d_algorithm); | |
189 | conv.xfrBlob(d_certificate); | |
190 | ); | |
8c1c9170 | 191 | |
2475a4fc | 192 | boilerplate_conv(CERT, 37, |
4957a608 | 193 | conv.xfr16BitInt(d_type); |
689516b3 AT |
194 | if (d_type == 0) throw MOADNSException("CERT type 0 is reserved"); |
195 | ||
4957a608 BH |
196 | conv.xfr16BitInt(d_tag); |
197 | conv.xfr8BitInt(d_algorithm); | |
689516b3 AT |
198 | conv.xfrBlob(d_certificate); |
199 | ) | |
200 | ||
2a4e06e9 | 201 | boilerplate_conv(TLSA, 52, |
f5a09796 PD |
202 | conv.xfr8BitInt(d_certusage); |
203 | conv.xfr8BitInt(d_selector); | |
204 | conv.xfr8BitInt(d_matchtype); | |
b9ec21ad | 205 | conv.xfrHexBlob(d_cert, true); |
07dbe87e BH |
206 | ) |
207 | ||
6a5b669b | 208 | #undef DS |
1c4d88c5 | 209 | DSRecordContent::DSRecordContent() : DNSRecordContent(43) {} |
8c1c9170 | 210 | boilerplate_conv(DS, 43, |
4957a608 BH |
211 | conv.xfr16BitInt(d_tag); |
212 | conv.xfr8BitInt(d_algorithm); | |
213 | conv.xfr8BitInt(d_digesttype); | |
e4090157 | 214 | conv.xfrHexBlob(d_digest, true); // keep reading across spaces |
4957a608 | 215 | ) |
8c1c9170 | 216 | |
0b55f2f5 BH |
217 | DLVRecordContent::DLVRecordContent() : DNSRecordContent(32769) {} |
218 | boilerplate_conv(DLV,32769 , | |
219 | conv.xfr16BitInt(d_tag); | |
220 | conv.xfr8BitInt(d_algorithm); | |
221 | conv.xfr8BitInt(d_digesttype); | |
222 | conv.xfrHexBlob(d_digest, true); // keep reading across spaces | |
223 | ) | |
224 | ||
225 | ||
a40a693b | 226 | boilerplate_conv(SSHFP, 44, |
4957a608 BH |
227 | conv.xfr8BitInt(d_algorithm); |
228 | conv.xfr8BitInt(d_fptype); | |
229 | conv.xfrHexBlob(d_fingerprint); | |
230 | ) | |
a40a693b | 231 | |
8c1c9170 | 232 | boilerplate_conv(RRSIG, 46, |
4957a608 BH |
233 | conv.xfrType(d_type); |
234 | conv.xfr8BitInt(d_algorithm); | |
235 | conv.xfr8BitInt(d_labels); | |
4957a608 BH |
236 | conv.xfr32BitInt(d_originalttl); |
237 | conv.xfrTime(d_sigexpire); | |
238 | conv.xfrTime(d_siginception); | |
239 | conv.xfr16BitInt(d_tag); | |
240 | conv.xfrLabel(d_signer); | |
241 | conv.xfrBlob(d_signature); | |
242 | ) | |
243 | ||
1c4d88c5 BH |
244 | RRSIGRecordContent::RRSIGRecordContent() : DNSRecordContent(46) {} |
245 | ||
8c1c9170 | 246 | boilerplate_conv(DNSKEY, 48, |
4957a608 BH |
247 | conv.xfr16BitInt(d_flags); |
248 | conv.xfr8BitInt(d_protocol); | |
249 | conv.xfr8BitInt(d_algorithm); | |
250 | conv.xfrBlob(d_key); | |
251 | ) | |
1c4d88c5 BH |
252 | DNSKEYRecordContent::DNSKEYRecordContent() : DNSRecordContent(48) {} |
253 | ||
66a07c55 AT |
254 | /* EUI48 start */ |
255 | ||
256 | void EUI48RecordContent::report(void) | |
257 | { | |
258 | regist(1, ns_t_eui48, &make, &make, "EUI48"); | |
259 | } | |
260 | DNSRecordContent* EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr) | |
261 | { | |
262 | if(dr.d_clen!=6) | |
263 | throw MOADNSException("Wrong size for EUI48 record"); | |
264 | ||
265 | EUI48RecordContent* ret=new EUI48RecordContent(); | |
266 | pr.copyRecord((uint8_t*) &ret->d_eui48, 6); | |
267 | return ret; | |
268 | } | |
269 | DNSRecordContent* EUI48RecordContent::make(const string& zone) | |
270 | { | |
271 | // try to parse | |
272 | EUI48RecordContent *ret=new EUI48RecordContent(); | |
273 | // format is 6 hex bytes and dashes | |
274 | if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx", | |
275 | ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2, | |
276 | ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) { | |
0fc965fd | 277 | throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse"); |
66a07c55 AT |
278 | } |
279 | return ret; | |
280 | } | |
281 | void EUI48RecordContent::toPacket(DNSPacketWriter& pw) | |
282 | { | |
283 | string blob(d_eui48, d_eui48+6); | |
284 | pw.xfrBlob(blob); | |
285 | } | |
286 | string EUI48RecordContent::getZoneRepresentation() const | |
287 | { | |
288 | char tmp[18]; | |
289 | snprintf(tmp,18,"%02x-%02x-%02x-%02x-%02x-%02x", | |
290 | d_eui48[0], d_eui48[1], d_eui48[2], | |
291 | d_eui48[3], d_eui48[4], d_eui48[5]); | |
292 | return tmp; | |
293 | } | |
294 | ||
295 | /* EUI48 end */ | |
296 | ||
297 | /* EUI64 start */ | |
298 | ||
299 | void EUI64RecordContent::report(void) | |
300 | { | |
301 | regist(1, ns_t_eui64, &make, &make, "EUI64"); | |
302 | } | |
303 | DNSRecordContent* EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr) | |
304 | { | |
305 | if(dr.d_clen!=8) | |
306 | throw MOADNSException("Wrong size for EUI64 record"); | |
307 | ||
308 | EUI64RecordContent* ret=new EUI64RecordContent(); | |
309 | pr.copyRecord((uint8_t*) &ret->d_eui64, 8); | |
310 | return ret; | |
311 | } | |
312 | DNSRecordContent* EUI64RecordContent::make(const string& zone) | |
313 | { | |
314 | // try to parse | |
315 | EUI64RecordContent *ret=new EUI64RecordContent(); | |
316 | // format is 8 hex bytes and dashes | |
317 | if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx", | |
318 | ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2, | |
319 | ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5, | |
320 | ret->d_eui64+6, ret->d_eui64+7) != 8) { | |
321 | throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse"); | |
322 | } | |
323 | return ret; | |
324 | } | |
325 | void EUI64RecordContent::toPacket(DNSPacketWriter& pw) | |
326 | { | |
327 | string blob(d_eui64, d_eui64+8); | |
328 | pw.xfrBlob(blob); | |
329 | } | |
330 | string EUI64RecordContent::getZoneRepresentation() const | |
331 | { | |
332 | char tmp[24]; | |
333 | snprintf(tmp,24,"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", | |
334 | d_eui64[0], d_eui64[1], d_eui64[2], | |
335 | d_eui64[3], d_eui64[4], d_eui64[5], | |
336 | d_eui64[6], d_eui64[7]); | |
337 | return tmp; | |
338 | } | |
339 | ||
340 | /* EUI64 end */ | |
341 | ||
342 | ||
1c4d88c5 BH |
343 | uint16_t DNSKEYRecordContent::getTag() |
344 | { | |
345 | string data=this->serialize(""); | |
346 | const unsigned char* key=(const unsigned char*)data.c_str(); | |
347 | unsigned int keysize=data.length(); | |
348 | ||
349 | unsigned long ac; /* assumed to be 32 bits or larger */ | |
350 | unsigned int i; /* loop index */ | |
351 | ||
352 | for ( ac = 0, i = 0; i < keysize; ++i ) | |
353 | ac += (i & 1) ? key[i] : key[i] << 8; | |
354 | ac += (ac >> 16) & 0xFFFF; | |
355 | return ac & 0xFFFF; | |
356 | } | |
357 | ||
d34d3e01 BH |
358 | // "fancy records" |
359 | boilerplate_conv(URL, QType::URL, | |
4957a608 BH |
360 | conv.xfrLabel(d_url); |
361 | ) | |
7f7b8d55 | 362 | |
d34d3e01 | 363 | boilerplate_conv(MBOXFW, QType::MBOXFW, |
4957a608 BH |
364 | conv.xfrLabel(d_mboxfw); |
365 | ) | |
d34d3e01 | 366 | |
0e4ab7bc BH |
367 | |
368 | ||
7f7b8d55 BH |
369 | bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo) |
370 | { | |
0e4ab7bc BH |
371 | if(mdp.d_header.arcount && !mdp.d_answers.empty()) { |
372 | BOOST_FOREACH(const MOADNSParser::answers_t::value_type& val, mdp.d_answers) { | |
373 | if(val.first.d_place == DNSRecord::Additional && val.first.d_type == QType::OPT) { | |
374 | eo->d_packetsize=val.first.d_class; | |
375 | ||
376 | EDNS0Record stuff; | |
377 | uint32_t ttl=ntohl(val.first.d_ttl); | |
378 | memcpy(&stuff, &ttl, sizeof(stuff)); | |
379 | ||
380 | eo->d_extRCode=stuff.extRCode; | |
381 | eo->d_version=stuff.version; | |
382 | eo->d_Z = ntohs(stuff.Z); | |
383 | OPTRecordContent* orc = | |
384 | dynamic_cast<OPTRecordContent*>(val.first.d_content.get()); | |
385 | if(!orc) | |
386 | return false; | |
387 | orc->getData(eo->d_options); | |
388 | return true; | |
389 | } | |
390 | } | |
7f7b8d55 | 391 | } |
0e4ab7bc | 392 | return false; |
7f7b8d55 BH |
393 | } |
394 | ||
395 | ||
ea634573 | 396 | void reportBasicTypes() |
ff6a1e7b | 397 | { |
a9af3782 BH |
398 | ARecordContent::report(); |
399 | AAAARecordContent::report(); | |
400 | NSRecordContent::report(); | |
401 | CNAMERecordContent::report(); | |
402 | MXRecordContent::report(); | |
403 | SOARecordContent::report(); | |
404 | SRVRecordContent::report(); | |
405 | PTRRecordContent::report(); | |
a6a83beb AT |
406 | //DNSRecordContent::regist(3, ns_t_txt, &TXTRecordContent::make, &TXTRecordContent::make, "TXT"); |
407 | TXTRecordContent::report(); | |
0407751c | 408 | DNSRecordContent::regist(1, QType::ANY, 0, 0, "ANY"); |
ea634573 BH |
409 | } |
410 | ||
411 | void reportOtherTypes() | |
412 | { | |
37f47031 | 413 | AFSDBRecordContent::report(); |
ea634573 BH |
414 | SPFRecordContent::report(); |
415 | NAPTRRecordContent::report(); | |
c6a60874 | 416 | LOCRecordContent::report(); |
9770663f | 417 | HINFORecordContent::report(); |
ea634573 | 418 | RPRecordContent::report(); |
4b5762f1 | 419 | KEYRecordContent::report(); |
ea634573 BH |
420 | DNSKEYRecordContent::report(); |
421 | RRSIGRecordContent::report(); | |
422 | DSRecordContent::report(); | |
59a0f653 | 423 | SSHFPRecordContent::report(); |
2475a4fc | 424 | CERTRecordContent::report(); |
ea634573 | 425 | NSECRecordContent::report(); |
1c4d88c5 BH |
426 | NSEC3RecordContent::report(); |
427 | NSEC3PARAMRecordContent::report(); | |
07dbe87e | 428 | TLSARecordContent::report(); |
4fb75774 | 429 | DLVRecordContent::report(); |
a6a83beb AT |
430 | //DNSRecordContent::regist(0xff, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG"); |
431 | TSIGRecordContent::report(); | |
ea634573 | 432 | OPTRecordContent::report(); |
66a07c55 AT |
433 | EUI48RecordContent::report(); |
434 | EUI64RecordContent::report(); | |
5eea7309 | 435 | MINFORecordContent::report(); |
ea634573 BH |
436 | } |
437 | ||
afbb76cd BH |
438 | void reportFancyTypes() |
439 | { | |
440 | URLRecordContent::report(); | |
d34d3e01 | 441 | MBOXFWRecordContent::report(); |
afbb76cd BH |
442 | } |
443 | ||
ea634573 BH |
444 | void reportAllTypes() |
445 | { | |
446 | reportBasicTypes(); | |
447 | reportOtherTypes(); | |
448 | } | |
449 | ||
450 | #if 0 | |
451 | static struct Reporter | |
452 | { | |
453 | Reporter() | |
454 | { | |
455 | reportAllTypes(); | |
ff6a1e7b BH |
456 | } |
457 | } reporter __attribute__((init_priority(65535))); | |
250d1fd8 | 458 | #endif |