]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
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. | |
8 | * | |
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. | |
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 Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
22 | #ifdef HAVE_CONFIG_H | |
23 | #include "config.h" | |
24 | #endif | |
25 | #include "utility.hh" | |
26 | #include "dnsrecords.hh" | |
27 | #include "iputils.hh" | |
28 | ||
29 | ||
30 | void DNSResourceRecord::setContent(const string &cont) { | |
31 | content = cont; | |
32 | switch(qtype.getCode()) { | |
33 | case QType::SRV: | |
34 | case QType::MX: | |
35 | if (content.size() >= 2 && *(content.rbegin()+1) == ' ') | |
36 | return; | |
37 | /* Falls through. */ | |
38 | case QType::CNAME: | |
39 | case QType::DNAME: | |
40 | case QType::NS: | |
41 | case QType::PTR: | |
42 | if (content.size() >= 2 && *(content.rbegin()) == '.') | |
43 | boost::erase_tail(content, 1); | |
44 | } | |
45 | } | |
46 | ||
47 | string DNSResourceRecord::getZoneRepresentation(bool noDot) const { | |
48 | ostringstream ret; | |
49 | vector<string> parts; | |
50 | string last; | |
51 | ||
52 | switch(qtype.getCode()) { | |
53 | case QType::SRV: | |
54 | case QType::MX: | |
55 | stringtok(parts, content); | |
56 | if (!parts.size()) | |
57 | return ""; | |
58 | last = *parts.rbegin(); | |
59 | ret << content; | |
60 | if (last == ".") | |
61 | break; | |
62 | if (*(last.rbegin()) != '.' && !noDot) | |
63 | ret << "."; | |
64 | break; | |
65 | case QType::CNAME: | |
66 | case QType::DNAME: | |
67 | case QType::NS: | |
68 | case QType::PTR: | |
69 | ret<<content; | |
70 | if (*(content.rbegin()) != '.' && !noDot) | |
71 | ret<<"."; | |
72 | break; | |
73 | default: | |
74 | ret<<content; | |
75 | break; | |
76 | } | |
77 | return ret.str(); | |
78 | } | |
79 | ||
80 | bool DNSResourceRecord::operator==(const DNSResourceRecord& rhs) | |
81 | { | |
82 | string lcontent=toLower(content); | |
83 | string rcontent=toLower(rhs.content); | |
84 | ||
85 | return | |
86 | tie(qname, qtype, lcontent, ttl) == | |
87 | tie(rhs.qname, rhs.qtype, rcontent, rhs.ttl); | |
88 | } | |
89 | ||
90 | boilerplate_conv(A, QType::A, conv.xfrIP(d_ip)); | |
91 | ||
92 | ARecordContent::ARecordContent(uint32_t ip) | |
93 | { | |
94 | d_ip = ip; | |
95 | } | |
96 | ||
97 | ARecordContent::ARecordContent(const ComboAddress& ca) | |
98 | { | |
99 | d_ip = ca.sin4.sin_addr.s_addr; | |
100 | } | |
101 | ||
102 | AAAARecordContent::AAAARecordContent(const ComboAddress& ca) | |
103 | { | |
104 | d_ip6.assign((const char*)ca.sin6.sin6_addr.s6_addr, 16); | |
105 | } | |
106 | ||
107 | ||
108 | ||
109 | ComboAddress ARecordContent::getCA(int port) const | |
110 | { | |
111 | ComboAddress ret; | |
112 | ret.sin4.sin_family=AF_INET; | |
113 | ret.sin4.sin_port=htons(port); | |
114 | memcpy(&ret.sin4.sin_addr.s_addr, &d_ip, sizeof(ret.sin4.sin_addr.s_addr)); | |
115 | return ret; | |
116 | } | |
117 | ||
118 | ComboAddress AAAARecordContent::getCA(int port) const | |
119 | { | |
120 | ComboAddress ret; | |
121 | ret.reset(); | |
122 | ||
123 | ret.sin4.sin_family=AF_INET6; | |
124 | ret.sin6.sin6_port = htons(port); | |
125 | memcpy(&ret.sin6.sin6_addr.s6_addr, d_ip6.c_str(), sizeof(ret.sin6.sin6_addr.s6_addr)); | |
126 | return ret; | |
127 | } | |
128 | ||
129 | ||
130 | void ARecordContent::doRecordCheck(const DNSRecord& dr) | |
131 | { | |
132 | if(dr.d_clen!=4) | |
133 | throw MOADNSException("Wrong size for A record ("+std::to_string(dr.d_clen)+")"); | |
134 | } | |
135 | ||
136 | boilerplate_conv(AAAA, QType::AAAA, conv.xfrIP6(d_ip6); ); | |
137 | ||
138 | boilerplate_conv(NS, QType::NS, conv.xfrName(d_content, true)); | |
139 | boilerplate_conv(PTR, QType::PTR, conv.xfrName(d_content, true)); | |
140 | boilerplate_conv(CNAME, QType::CNAME, conv.xfrName(d_content, true)); | |
141 | boilerplate_conv(ALIAS, QType::ALIAS, conv.xfrName(d_content, false)); | |
142 | boilerplate_conv(DNAME, QType::DNAME, conv.xfrName(d_content)); | |
143 | boilerplate_conv(MB, QType::MB, conv.xfrName(d_madname, true)); | |
144 | boilerplate_conv(MG, QType::MG, conv.xfrName(d_mgmname, true)); | |
145 | boilerplate_conv(MR, QType::MR, conv.xfrName(d_alias, true)); | |
146 | boilerplate_conv(MINFO, QType::MINFO, conv.xfrName(d_rmailbx, true); conv.xfrName(d_emailbx, true)); | |
147 | boilerplate_conv(TXT, QType::TXT, conv.xfrText(d_text, true)); | |
148 | #ifdef HAVE_LUA_RECORDS | |
149 | boilerplate_conv(LUA, QType::LUA, conv.xfrType(d_type); conv.xfrText(d_code, true)); | |
150 | #endif | |
151 | boilerplate_conv(ENT, 0, ); | |
152 | boilerplate_conv(SPF, 99, conv.xfrText(d_text, true)); | |
153 | boilerplate_conv(HINFO, QType::HINFO, conv.xfrText(d_cpu); conv.xfrText(d_host)); | |
154 | ||
155 | boilerplate_conv(RP, QType::RP, | |
156 | conv.xfrName(d_mbox); | |
157 | conv.xfrName(d_info) | |
158 | ); | |
159 | ||
160 | ||
161 | boilerplate_conv(OPT, QType::OPT, | |
162 | conv.xfrBlob(d_data) | |
163 | ); | |
164 | ||
165 | #ifdef HAVE_LUA_RECORDS | |
166 | string LUARecordContent::getCode() const | |
167 | { | |
168 | // in d_code, series of "part1" "part2" | |
169 | vector<string> parts; | |
170 | stringtok(parts, d_code, "\""); | |
171 | string ret; | |
172 | for(const auto& p : parts) { | |
173 | ret += p; | |
174 | ret.append(1, ' '); | |
175 | } | |
176 | return ret; | |
177 | } | |
178 | #endif | |
179 | ||
180 | void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options) | |
181 | { | |
182 | string::size_type pos=0; | |
183 | uint16_t code, len; | |
184 | while(d_data.size() >= 4 + pos) { | |
185 | code = 256 * (unsigned char)d_data[pos] + (unsigned char)d_data[pos+1]; | |
186 | len = 256 * (unsigned char)d_data[pos+2] + (unsigned char)d_data[pos+3]; | |
187 | pos+=4; | |
188 | ||
189 | if(pos + len > d_data.size()) | |
190 | break; | |
191 | ||
192 | string field(d_data.c_str() + pos, len); | |
193 | pos+=len; | |
194 | options.push_back(make_pair(code, field)); | |
195 | } | |
196 | } | |
197 | ||
198 | boilerplate_conv(TSIG, QType::TSIG, | |
199 | conv.xfrName(d_algoName); | |
200 | conv.xfr48BitInt(d_time); | |
201 | conv.xfr16BitInt(d_fudge); | |
202 | uint16_t size=d_mac.size(); | |
203 | conv.xfr16BitInt(size); | |
204 | if (size>0) conv.xfrBlobNoSpaces(d_mac, size); | |
205 | conv.xfr16BitInt(d_origID); | |
206 | conv.xfr16BitInt(d_eRcode); | |
207 | size=d_otherData.size(); | |
208 | conv.xfr16BitInt(size); | |
209 | if (size>0) conv.xfrBlobNoSpaces(d_otherData, size); | |
210 | ); | |
211 | ||
212 | MXRecordContent::MXRecordContent(uint16_t preference, const DNSName& mxname): d_preference(preference), d_mxname(mxname) | |
213 | { | |
214 | } | |
215 | ||
216 | boilerplate_conv(MX, QType::MX, | |
217 | conv.xfr16BitInt(d_preference); | |
218 | conv.xfrName(d_mxname, true); | |
219 | ) | |
220 | ||
221 | boilerplate_conv(KX, QType::KX, | |
222 | conv.xfr16BitInt(d_preference); | |
223 | conv.xfrName(d_exchanger, false); | |
224 | ) | |
225 | ||
226 | boilerplate_conv(IPSECKEY, QType::IPSECKEY, | |
227 | conv.xfr8BitInt(d_preference); | |
228 | conv.xfr8BitInt(d_gatewaytype); | |
229 | conv.xfr8BitInt(d_algorithm); | |
230 | ||
231 | // now we need to determine values | |
232 | switch(d_gatewaytype) { | |
233 | case 0: // NO KEY | |
234 | break; | |
235 | case 1: // IPv4 GW | |
236 | conv.xfrIP(d_ip4); | |
237 | break; | |
238 | case 2: // IPv6 GW | |
239 | conv.xfrIP6(d_ip6); | |
240 | break; | |
241 | case 3: // DNS label | |
242 | conv.xfrName(d_gateway, false); | |
243 | break; | |
244 | default: | |
245 | throw MOADNSException("Parsing record content: invalid gateway type"); | |
246 | }; | |
247 | ||
248 | switch(d_algorithm) { | |
249 | case 0: | |
250 | break; | |
251 | case 1: | |
252 | case 2: | |
253 | conv.xfrBlob(d_publickey); | |
254 | break; | |
255 | default: | |
256 | throw MOADNSException("Parsing record content: invalid algorithm type"); | |
257 | } | |
258 | ) | |
259 | ||
260 | boilerplate_conv(DHCID, 49, | |
261 | conv.xfrBlob(d_content); | |
262 | ) | |
263 | ||
264 | ||
265 | boilerplate_conv(AFSDB, QType::AFSDB, | |
266 | conv.xfr16BitInt(d_subtype); | |
267 | conv.xfrName(d_hostname); | |
268 | ) | |
269 | ||
270 | ||
271 | boilerplate_conv(NAPTR, QType::NAPTR, | |
272 | conv.xfr16BitInt(d_order); conv.xfr16BitInt(d_preference); | |
273 | conv.xfrText(d_flags); conv.xfrText(d_services); conv.xfrText(d_regexp); | |
274 | conv.xfrName(d_replacement); | |
275 | ) | |
276 | ||
277 | ||
278 | SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const DNSName& target) | |
279 | : d_weight(weight), d_port(port), d_target(target), d_preference(preference) | |
280 | {} | |
281 | ||
282 | boilerplate_conv(SRV, QType::SRV, | |
283 | conv.xfr16BitInt(d_preference); conv.xfr16BitInt(d_weight); conv.xfr16BitInt(d_port); | |
284 | conv.xfrName(d_target); | |
285 | ) | |
286 | ||
287 | SOARecordContent::SOARecordContent(const DNSName& mname, const DNSName& rname, const struct soatimes& st) | |
288 | : d_mname(mname), d_rname(rname), d_st(st) | |
289 | { | |
290 | } | |
291 | ||
292 | boilerplate_conv(SOA, QType::SOA, | |
293 | conv.xfrName(d_mname, true); | |
294 | conv.xfrName(d_rname, true); | |
295 | conv.xfr32BitInt(d_st.serial); | |
296 | conv.xfr32BitInt(d_st.refresh); | |
297 | conv.xfr32BitInt(d_st.retry); | |
298 | conv.xfr32BitInt(d_st.expire); | |
299 | conv.xfr32BitInt(d_st.minimum); | |
300 | ); | |
301 | #undef KEY | |
302 | boilerplate_conv(KEY, QType::KEY, | |
303 | conv.xfr16BitInt(d_flags); | |
304 | conv.xfr8BitInt(d_protocol); | |
305 | conv.xfr8BitInt(d_algorithm); | |
306 | conv.xfrBlob(d_certificate); | |
307 | ); | |
308 | ||
309 | boilerplate_conv(CERT, 37, | |
310 | conv.xfr16BitInt(d_type); | |
311 | if (d_type == 0) throw MOADNSException("CERT type 0 is reserved"); | |
312 | ||
313 | conv.xfr16BitInt(d_tag); | |
314 | conv.xfr8BitInt(d_algorithm); | |
315 | conv.xfrBlob(d_certificate); | |
316 | ) | |
317 | ||
318 | boilerplate_conv(TLSA, 52, | |
319 | conv.xfr8BitInt(d_certusage); | |
320 | conv.xfr8BitInt(d_selector); | |
321 | conv.xfr8BitInt(d_matchtype); | |
322 | conv.xfrHexBlob(d_cert, true); | |
323 | ) | |
324 | ||
325 | boilerplate_conv(OPENPGPKEY, 61, | |
326 | conv.xfrBlob(d_keyring); | |
327 | ) | |
328 | ||
329 | boilerplate_conv(SMIMEA, 53, | |
330 | conv.xfr8BitInt(d_certusage); | |
331 | conv.xfr8BitInt(d_selector); | |
332 | conv.xfr8BitInt(d_matchtype); | |
333 | conv.xfrHexBlob(d_cert, true); | |
334 | ) | |
335 | ||
336 | DSRecordContent::DSRecordContent() {} | |
337 | boilerplate_conv(DS, 43, | |
338 | conv.xfr16BitInt(d_tag); | |
339 | conv.xfr8BitInt(d_algorithm); | |
340 | conv.xfr8BitInt(d_digesttype); | |
341 | conv.xfrHexBlob(d_digest, true); // keep reading across spaces | |
342 | ) | |
343 | ||
344 | CDSRecordContent::CDSRecordContent() {} | |
345 | boilerplate_conv(CDS, 59, | |
346 | conv.xfr16BitInt(d_tag); | |
347 | conv.xfr8BitInt(d_algorithm); | |
348 | conv.xfr8BitInt(d_digesttype); | |
349 | conv.xfrHexBlob(d_digest, true); // keep reading across spaces | |
350 | ) | |
351 | ||
352 | DLVRecordContent::DLVRecordContent() {} | |
353 | boilerplate_conv(DLV,32769 , | |
354 | conv.xfr16BitInt(d_tag); | |
355 | conv.xfr8BitInt(d_algorithm); | |
356 | conv.xfr8BitInt(d_digesttype); | |
357 | conv.xfrHexBlob(d_digest, true); // keep reading across spaces | |
358 | ) | |
359 | ||
360 | ||
361 | boilerplate_conv(SSHFP, 44, | |
362 | conv.xfr8BitInt(d_algorithm); | |
363 | conv.xfr8BitInt(d_fptype); | |
364 | conv.xfrHexBlob(d_fingerprint, true); | |
365 | ) | |
366 | ||
367 | boilerplate_conv(RRSIG, 46, | |
368 | conv.xfrType(d_type); | |
369 | conv.xfr8BitInt(d_algorithm); | |
370 | conv.xfr8BitInt(d_labels); | |
371 | conv.xfr32BitInt(d_originalttl); | |
372 | conv.xfrTime(d_sigexpire); | |
373 | conv.xfrTime(d_siginception); | |
374 | conv.xfr16BitInt(d_tag); | |
375 | conv.xfrName(d_signer); | |
376 | conv.xfrBlob(d_signature); | |
377 | ) | |
378 | ||
379 | RRSIGRecordContent::RRSIGRecordContent() {} | |
380 | ||
381 | boilerplate_conv(DNSKEY, 48, | |
382 | conv.xfr16BitInt(d_flags); | |
383 | conv.xfr8BitInt(d_protocol); | |
384 | conv.xfr8BitInt(d_algorithm); | |
385 | conv.xfrBlob(d_key); | |
386 | ) | |
387 | DNSKEYRecordContent::DNSKEYRecordContent() {} | |
388 | ||
389 | boilerplate_conv(CDNSKEY, 60, | |
390 | conv.xfr16BitInt(d_flags); | |
391 | conv.xfr8BitInt(d_protocol); | |
392 | conv.xfr8BitInt(d_algorithm); | |
393 | conv.xfrBlob(d_key); | |
394 | ) | |
395 | CDNSKEYRecordContent::CDNSKEYRecordContent() {} | |
396 | ||
397 | boilerplate_conv(RKEY, 57, | |
398 | conv.xfr16BitInt(d_flags); | |
399 | conv.xfr8BitInt(d_protocol); | |
400 | conv.xfr8BitInt(d_algorithm); | |
401 | conv.xfrBlob(d_key); | |
402 | ) | |
403 | RKEYRecordContent::RKEYRecordContent() {} | |
404 | ||
405 | /* EUI48 start */ | |
406 | void EUI48RecordContent::report(void) | |
407 | { | |
408 | regist(1, QType::EUI48, &make, &make, "EUI48"); | |
409 | } | |
410 | std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr) | |
411 | { | |
412 | if(dr.d_clen!=6) | |
413 | throw MOADNSException("Wrong size for EUI48 record"); | |
414 | ||
415 | auto ret=std::make_shared<EUI48RecordContent>(); | |
416 | pr.copyRecord((uint8_t*) &ret->d_eui48, 6); | |
417 | return ret; | |
418 | } | |
419 | std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const string& zone) | |
420 | { | |
421 | // try to parse | |
422 | auto ret=std::make_shared<EUI48RecordContent>(); | |
423 | // format is 6 hex bytes and dashes | |
424 | if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx", | |
425 | ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2, | |
426 | ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) { | |
427 | throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse"); | |
428 | } | |
429 | return ret; | |
430 | } | |
431 | void EUI48RecordContent::toPacket(DNSPacketWriter& pw) | |
432 | { | |
433 | string blob(d_eui48, d_eui48+6); | |
434 | pw.xfrBlob(blob); | |
435 | } | |
436 | string EUI48RecordContent::getZoneRepresentation(bool noDot) const | |
437 | { | |
438 | char tmp[18]; | |
439 | snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x", | |
440 | d_eui48[0], d_eui48[1], d_eui48[2], | |
441 | d_eui48[3], d_eui48[4], d_eui48[5]); | |
442 | return tmp; | |
443 | } | |
444 | ||
445 | /* EUI48 end */ | |
446 | ||
447 | /* EUI64 start */ | |
448 | ||
449 | void EUI64RecordContent::report(void) | |
450 | { | |
451 | regist(1, QType::EUI64, &make, &make, "EUI64"); | |
452 | } | |
453 | std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr) | |
454 | { | |
455 | if(dr.d_clen!=8) | |
456 | throw MOADNSException("Wrong size for EUI64 record"); | |
457 | ||
458 | auto ret=std::make_shared<EUI64RecordContent>(); | |
459 | pr.copyRecord((uint8_t*) &ret->d_eui64, 8); | |
460 | return ret; | |
461 | } | |
462 | std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const string& zone) | |
463 | { | |
464 | // try to parse | |
465 | auto ret=std::make_shared<EUI64RecordContent>(); | |
466 | // format is 8 hex bytes and dashes | |
467 | if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx", | |
468 | ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2, | |
469 | ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5, | |
470 | ret->d_eui64+6, ret->d_eui64+7) != 8) { | |
471 | throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse"); | |
472 | } | |
473 | return ret; | |
474 | } | |
475 | void EUI64RecordContent::toPacket(DNSPacketWriter& pw) | |
476 | { | |
477 | string blob(d_eui64, d_eui64+8); | |
478 | pw.xfrBlob(blob); | |
479 | } | |
480 | string EUI64RecordContent::getZoneRepresentation(bool noDot) const | |
481 | { | |
482 | char tmp[24]; | |
483 | snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", | |
484 | d_eui64[0], d_eui64[1], d_eui64[2], | |
485 | d_eui64[3], d_eui64[4], d_eui64[5], | |
486 | d_eui64[6], d_eui64[7]); | |
487 | return tmp; | |
488 | } | |
489 | ||
490 | /* EUI64 end */ | |
491 | ||
492 | boilerplate_conv(TKEY, QType::TKEY, | |
493 | conv.xfrName(d_algo); | |
494 | conv.xfr32BitInt(d_inception); | |
495 | conv.xfr32BitInt(d_expiration); | |
496 | conv.xfr16BitInt(d_mode); | |
497 | conv.xfr16BitInt(d_error); | |
498 | conv.xfr16BitInt(d_keysize); | |
499 | if (d_keysize>0) conv.xfrBlobNoSpaces(d_key, d_keysize); | |
500 | conv.xfr16BitInt(d_othersize); | |
501 | if (d_othersize>0) conv.xfrBlobNoSpaces(d_other, d_othersize); | |
502 | ) | |
503 | TKEYRecordContent::TKEYRecordContent() { d_othersize = 0; } // fix CID#1288932 | |
504 | ||
505 | boilerplate_conv(URI, QType::URI, | |
506 | conv.xfr16BitInt(d_priority); | |
507 | conv.xfr16BitInt(d_weight); | |
508 | conv.xfrText(d_target, true, false); | |
509 | ) | |
510 | ||
511 | boilerplate_conv(CAA, QType::CAA, | |
512 | conv.xfr8BitInt(d_flags); | |
513 | conv.xfrUnquotedText(d_tag, true); | |
514 | conv.xfrText(d_value, true, false); /* no lenField */ | |
515 | ) | |
516 | ||
517 | static uint16_t makeTag(const std::string& data) | |
518 | { | |
519 | const unsigned char* key=(const unsigned char*)data.c_str(); | |
520 | unsigned int keysize=data.length(); | |
521 | ||
522 | unsigned long ac; /* assumed to be 32 bits or larger */ | |
523 | unsigned int i; /* loop index */ | |
524 | ||
525 | for ( ac = 0, i = 0; i < keysize; ++i ) | |
526 | ac += (i & 1) ? key[i] : key[i] << 8; | |
527 | ac += (ac >> 16) & 0xFFFF; | |
528 | return ac & 0xFFFF; | |
529 | } | |
530 | ||
531 | uint16_t DNSKEYRecordContent::getTag() const | |
532 | { | |
533 | DNSKEYRecordContent tmp(*this); | |
534 | return makeTag(tmp.serialize(DNSName())); // this can't be const for some reason | |
535 | } | |
536 | ||
537 | uint16_t DNSKEYRecordContent::getTag() | |
538 | { | |
539 | return makeTag(this->serialize(DNSName())); | |
540 | } | |
541 | ||
542 | ||
543 | /* | |
544 | * Fills `eo` by parsing the EDNS(0) OPT RR (RFC 6891) | |
545 | */ | |
546 | bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo) | |
547 | { | |
548 | eo->d_extFlags=0; | |
549 | if(mdp.d_header.arcount && !mdp.d_answers.empty()) { | |
550 | for(const MOADNSParser::answers_t::value_type& val : mdp.d_answers) { | |
551 | if(val.first.d_place == DNSResourceRecord::ADDITIONAL && val.first.d_type == QType::OPT) { | |
552 | eo->d_packetsize=val.first.d_class; | |
553 | ||
554 | EDNS0Record stuff; | |
555 | uint32_t ttl=ntohl(val.first.d_ttl); | |
556 | static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)"); | |
557 | memcpy(&stuff, &ttl, sizeof(stuff)); | |
558 | ||
559 | eo->d_extRCode=stuff.extRCode; | |
560 | eo->d_version=stuff.version; | |
561 | eo->d_extFlags = ntohs(stuff.extFlags); | |
562 | auto orc = getRR<OPTRecordContent>(val.first); | |
563 | if(orc == nullptr) | |
564 | return false; | |
565 | orc->getData(eo->d_options); | |
566 | return true; | |
567 | } | |
568 | } | |
569 | } | |
570 | return false; | |
571 | } | |
572 | ||
573 | DNSRecord makeOpt(const uint16_t udpsize, const uint16_t extRCode, const uint16_t extFlags) | |
574 | { | |
575 | EDNS0Record stuff; | |
576 | stuff.extRCode=0; | |
577 | stuff.version=0; | |
578 | stuff.extFlags=htons(extFlags); | |
579 | DNSRecord dr; | |
580 | static_assert(sizeof(EDNS0Record) == sizeof(dr.d_ttl), "sizeof(EDNS0Record) must match sizeof(DNSRecord.d_ttl)"); | |
581 | memcpy(&dr.d_ttl, &stuff, sizeof(stuff)); | |
582 | dr.d_ttl=ntohl(dr.d_ttl); | |
583 | dr.d_name=g_rootdnsname; | |
584 | dr.d_type = QType::OPT; | |
585 | dr.d_class=udpsize; | |
586 | dr.d_place=DNSResourceRecord::ADDITIONAL; | |
587 | dr.d_content = std::make_shared<OPTRecordContent>(); | |
588 | // if we ever do options, I think we stuff them into OPTRecordContent::data | |
589 | return dr; | |
590 | } | |
591 | ||
592 | void reportBasicTypes() | |
593 | { | |
594 | ARecordContent::report(); | |
595 | AAAARecordContent::report(); | |
596 | NSRecordContent::report(); | |
597 | CNAMERecordContent::report(); | |
598 | MXRecordContent::report(); | |
599 | SOARecordContent::report(); | |
600 | SRVRecordContent::report(); | |
601 | PTRRecordContent::report(); | |
602 | DNSRecordContent::regist(QClass::CHAOS, QType::TXT, &TXTRecordContent::make, &TXTRecordContent::make, "TXT"); | |
603 | TXTRecordContent::report(); | |
604 | #ifdef HAVE_LUA_RECORDS | |
605 | LUARecordContent::report(); | |
606 | #endif | |
607 | DNSRecordContent::regist(QClass::IN, QType::ANY, 0, 0, "ANY"); | |
608 | DNSRecordContent::regist(QClass::IN, QType::AXFR, 0, 0, "AXFR"); | |
609 | DNSRecordContent::regist(QClass::IN, QType::IXFR, 0, 0, "IXFR"); | |
610 | } | |
611 | ||
612 | void reportOtherTypes() | |
613 | { | |
614 | MBRecordContent::report(); | |
615 | MGRecordContent::report(); | |
616 | MRRecordContent::report(); | |
617 | AFSDBRecordContent::report(); | |
618 | DNAMERecordContent::report(); | |
619 | ALIASRecordContent::report(); | |
620 | SPFRecordContent::report(); | |
621 | NAPTRRecordContent::report(); | |
622 | LOCRecordContent::report(); | |
623 | ENTRecordContent::report(); | |
624 | HINFORecordContent::report(); | |
625 | RPRecordContent::report(); | |
626 | KEYRecordContent::report(); | |
627 | DNSKEYRecordContent::report(); | |
628 | DHCIDRecordContent::report(); | |
629 | CDNSKEYRecordContent::report(); | |
630 | RKEYRecordContent::report(); | |
631 | RRSIGRecordContent::report(); | |
632 | DSRecordContent::report(); | |
633 | CDSRecordContent::report(); | |
634 | SSHFPRecordContent::report(); | |
635 | CERTRecordContent::report(); | |
636 | NSECRecordContent::report(); | |
637 | NSEC3RecordContent::report(); | |
638 | NSEC3PARAMRecordContent::report(); | |
639 | TLSARecordContent::report(); | |
640 | SMIMEARecordContent::report(); | |
641 | OPENPGPKEYRecordContent::report(); | |
642 | DLVRecordContent::report(); | |
643 | DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG"); | |
644 | DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY"); | |
645 | //TSIGRecordContent::report(); | |
646 | OPTRecordContent::report(); | |
647 | EUI48RecordContent::report(); | |
648 | EUI64RecordContent::report(); | |
649 | MINFORecordContent::report(); | |
650 | URIRecordContent::report(); | |
651 | CAARecordContent::report(); | |
652 | } | |
653 | ||
654 | void reportAllTypes() | |
655 | { | |
656 | reportBasicTypes(); | |
657 | reportOtherTypes(); | |
658 | } | |
659 | ||
660 | ComboAddress getAddr(const DNSRecord& dr, uint16_t defport) | |
661 | { | |
662 | if(auto addr=getRR<ARecordContent>(dr)) { | |
663 | return addr->getCA(defport); | |
664 | } | |
665 | else | |
666 | return getRR<AAAARecordContent>(dr)->getCA(defport); | |
667 | } | |
668 | ||
669 | /** | |
670 | * Check if the DNSNames that should be hostnames, are hostnames | |
671 | */ | |
672 | void checkHostnameCorrectness(const DNSResourceRecord& rr) | |
673 | { | |
674 | if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) { | |
675 | DNSName toCheck; | |
676 | if (rr.qtype.getCode() == QType::SRV) { | |
677 | vector<string> parts; | |
678 | stringtok(parts, rr.getZoneRepresentation()); | |
679 | if (parts.size() == 4) toCheck = DNSName(parts[3]); | |
680 | } else if (rr.qtype.getCode() == QType::MX) { | |
681 | vector<string> parts; | |
682 | stringtok(parts, rr.getZoneRepresentation()); | |
683 | if (parts.size() == 2) toCheck = DNSName(parts[1]); | |
684 | } else { | |
685 | toCheck = DNSName(rr.content); | |
686 | } | |
687 | ||
688 | if (toCheck.empty()) { | |
689 | throw std::runtime_error("unable to extract hostname from content"); | |
690 | } | |
691 | else if ((rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) && toCheck == g_rootdnsname) { | |
692 | // allow null MX/SRV | |
693 | } else if(!toCheck.isHostname()) { | |
694 | throw std::runtime_error(boost::str(boost::format("non-hostname content %s") % toCheck.toString())); | |
695 | } | |
696 | } | |
697 | } | |
698 | ||
699 | #if 0 | |
700 | static struct Reporter | |
701 | { | |
702 | Reporter() | |
703 | { | |
704 | reportAllTypes(); | |
705 | } | |
706 | } reporter __attribute__((init_priority(65535))); | |
707 | #endif |