/src/pdns/pdns/dnsrecords.cc
Line | Count | Source (jump to first uncovered line) |
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 | | |
26 | | #include <boost/format.hpp> |
27 | | |
28 | | #include "utility.hh" |
29 | | #include "dnsrecords.hh" |
30 | | #include "iputils.hh" |
31 | | |
32 | 0 | void DNSResourceRecord::setContent(const string &cont) { |
33 | 0 | content = cont; |
34 | 0 | switch(qtype.getCode()) { |
35 | 0 | case QType::SRV: |
36 | 0 | case QType::MX: |
37 | 0 | if (content.size() >= 2 && *(content.rbegin()+1) == ' ') |
38 | 0 | return; |
39 | | /* Falls through. */ |
40 | 0 | case QType::CNAME: |
41 | 0 | case QType::DNAME: |
42 | 0 | case QType::NS: |
43 | 0 | case QType::PTR: |
44 | 0 | if (content.size() >= 2 && *(content.rbegin()) == '.') |
45 | 0 | boost::erase_tail(content, 1); |
46 | 0 | } |
47 | 0 | } |
48 | | |
49 | 0 | string DNSResourceRecord::getZoneRepresentation(bool noDot) const { |
50 | 0 | ostringstream ret; |
51 | 0 | vector<string> parts; |
52 | 0 | string last; |
53 | |
|
54 | 0 | switch(qtype.getCode()) { |
55 | 0 | case QType::SRV: |
56 | 0 | case QType::MX: |
57 | 0 | stringtok(parts, content); |
58 | 0 | if (parts.empty()) |
59 | 0 | return ""; |
60 | 0 | last = *parts.rbegin(); |
61 | 0 | ret << content; |
62 | 0 | if (last == ".") |
63 | 0 | break; |
64 | 0 | if (*(last.rbegin()) != '.' && !noDot) |
65 | 0 | ret << "."; |
66 | 0 | break; |
67 | 0 | case QType::CNAME: |
68 | 0 | case QType::DNAME: |
69 | 0 | case QType::NS: |
70 | 0 | case QType::PTR: |
71 | 0 | ret<<content; |
72 | 0 | if (*(content.rbegin()) != '.' && !noDot) |
73 | 0 | ret<<"."; |
74 | 0 | break; |
75 | 0 | default: |
76 | 0 | ret<<content; |
77 | 0 | break; |
78 | 0 | } |
79 | 0 | return ret.str(); |
80 | 0 | } |
81 | | |
82 | | bool DNSResourceRecord::operator==(const DNSResourceRecord& rhs) |
83 | 0 | { |
84 | 0 | string lcontent=toLower(content); |
85 | 0 | string rcontent=toLower(rhs.content); |
86 | |
|
87 | 0 | return |
88 | 0 | std::tie(qname, qtype, lcontent, ttl) == |
89 | 0 | std::tie(rhs.qname, rhs.qtype, rcontent, rhs.ttl); |
90 | 0 | } |
91 | | |
92 | | boilerplate_conv(A, conv.xfrIP(d_ip)); |
93 | | |
94 | | ARecordContent::ARecordContent(uint32_t ip) |
95 | 0 | { |
96 | 0 | d_ip = ip; |
97 | 0 | } |
98 | | |
99 | | ARecordContent::ARecordContent(const ComboAddress& ca) |
100 | 0 | { |
101 | 0 | d_ip = ca.sin4.sin_addr.s_addr; |
102 | 0 | } |
103 | | |
104 | | AAAARecordContent::AAAARecordContent(const ComboAddress& ca) |
105 | 0 | { |
106 | 0 | d_ip6.assign((const char*)ca.sin6.sin6_addr.s6_addr, 16); |
107 | 0 | } |
108 | | |
109 | | |
110 | | |
111 | | ComboAddress ARecordContent::getCA(int port) const |
112 | 0 | { |
113 | 0 | ComboAddress ret; |
114 | 0 | ret.sin4.sin_family=AF_INET; |
115 | 0 | ret.sin4.sin_port=htons(port); |
116 | 0 | memcpy(&ret.sin4.sin_addr.s_addr, &d_ip, sizeof(ret.sin4.sin_addr.s_addr)); |
117 | 0 | return ret; |
118 | 0 | } |
119 | | |
120 | | ComboAddress AAAARecordContent::getCA(int port) const |
121 | 0 | { |
122 | 0 | ComboAddress ret; |
123 | 0 | ret.reset(); |
124 | |
|
125 | 0 | ret.sin4.sin_family=AF_INET6; |
126 | 0 | ret.sin6.sin6_port = htons(port); |
127 | 0 | memcpy(&ret.sin6.sin6_addr.s6_addr, d_ip6.c_str(), sizeof(ret.sin6.sin6_addr.s6_addr)); |
128 | 0 | return ret; |
129 | 0 | } |
130 | | |
131 | | |
132 | | void ARecordContent::doRecordCheck(const DNSRecord& dr) |
133 | 694 | { |
134 | 694 | if(dr.d_clen!=4) |
135 | 23 | throw MOADNSException("Wrong size for A record ("+std::to_string(dr.d_clen)+")"); |
136 | 694 | } |
137 | | |
138 | | boilerplate_conv(AAAA, conv.xfrIP6(d_ip6); ); |
139 | | |
140 | | boilerplate_conv(NS, conv.xfrName(d_content, true)); |
141 | | boilerplate_conv(PTR, conv.xfrName(d_content, true)); |
142 | | boilerplate_conv(CNAME, conv.xfrName(d_content, true)); |
143 | | #if !defined(RECURSOR) |
144 | | boilerplate_conv(ALIAS, conv.xfrName(d_content, false)); |
145 | | #endif |
146 | | boilerplate_conv(DNAME, conv.xfrName(d_content)); |
147 | | boilerplate_conv(MB, conv.xfrName(d_madname, true)); |
148 | | boilerplate_conv(MG, conv.xfrName(d_mgmname, true)); |
149 | | boilerplate_conv(MR, conv.xfrName(d_alias, true)); |
150 | | boilerplate_conv(MINFO, conv.xfrName(d_rmailbx, true); conv.xfrName(d_emailbx, true)); |
151 | | boilerplate_conv(TXT, conv.xfrText(d_text, true)); |
152 | | #ifdef HAVE_LUA_RECORDS |
153 | | boilerplate_conv(LUA, conv.xfrType(d_type); conv.xfrText(d_code, true)); |
154 | | #endif |
155 | | boilerplate_conv(ENT, ); |
156 | | boilerplate_conv(SPF, conv.xfrText(d_text, true)); |
157 | | boilerplate_conv(HINFO, conv.xfrText(d_cpu); conv.xfrText(d_host)); |
158 | | |
159 | | boilerplate_conv(RP, |
160 | | conv.xfrName(d_mbox); |
161 | | conv.xfrName(d_info) |
162 | | ); |
163 | | |
164 | | |
165 | | boilerplate_conv(OPT, |
166 | | conv.xfrBlob(d_data) |
167 | | ); |
168 | | |
169 | | #ifdef HAVE_LUA_RECORDS |
170 | | string LUARecordContent::getCode() const |
171 | | { |
172 | | // in d_code, series of "part1" "part2" |
173 | | vector<string> parts; |
174 | | stringtok(parts, d_code, "\""); |
175 | | string ret; |
176 | | for(const auto& p : parts) { |
177 | | ret += p; |
178 | | ret.append(1, ' '); |
179 | | } |
180 | | return ret; |
181 | | } |
182 | | #endif |
183 | | |
184 | | void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options) const |
185 | 0 | { |
186 | 0 | string::size_type pos=0; |
187 | 0 | uint16_t code, len; |
188 | 0 | while(d_data.size() >= 4 + pos) { |
189 | 0 | code = 256 * (unsigned char)d_data.at(pos) + (unsigned char)d_data.at(pos+1); |
190 | 0 | len = 256 * (unsigned char)d_data.at(pos+2) + (unsigned char)d_data.at(pos+3); |
191 | 0 | pos+=4; |
192 | |
|
193 | 0 | if(pos + len > d_data.size()) |
194 | 0 | break; |
195 | | |
196 | 0 | string field(d_data.c_str() + pos, len); |
197 | 0 | pos+=len; |
198 | 0 | options.emplace_back(code, std::move(field)); |
199 | 0 | } |
200 | 0 | } |
201 | | |
202 | | boilerplate_conv(TSIG, |
203 | | conv.xfrName(d_algoName); |
204 | | conv.xfr48BitInt(d_time); |
205 | | conv.xfr16BitInt(d_fudge); |
206 | | uint16_t size=d_mac.size(); |
207 | | conv.xfr16BitInt(size); |
208 | | if (size>0) conv.xfrBlobNoSpaces(d_mac, size); |
209 | | conv.xfr16BitInt(d_origID); |
210 | | conv.xfr16BitInt(d_eRcode); |
211 | | size=d_otherData.size(); |
212 | | conv.xfr16BitInt(size); |
213 | | if (size>0) conv.xfrBlobNoSpaces(d_otherData, size); |
214 | | ); |
215 | | |
216 | | MXRecordContent::MXRecordContent(uint16_t preference, DNSName mxname): d_preference(preference), d_mxname(std::move(mxname)) |
217 | 0 | { |
218 | 0 | } |
219 | | |
220 | | boilerplate_conv(MX, |
221 | | conv.xfr16BitInt(d_preference); |
222 | | conv.xfrName(d_mxname, true); |
223 | | ) |
224 | | |
225 | | boilerplate_conv(KX, |
226 | | conv.xfr16BitInt(d_preference); |
227 | | conv.xfrName(d_exchanger, false); |
228 | | ) |
229 | | |
230 | | boilerplate_conv(IPSECKEY, |
231 | | conv.xfr8BitInt(d_preference); |
232 | | conv.xfr8BitInt(d_gatewaytype); |
233 | | conv.xfr8BitInt(d_algorithm); |
234 | | |
235 | | // now we need to determine values |
236 | | switch(d_gatewaytype) { |
237 | | case 0: // NO KEY |
238 | | break; |
239 | | case 1: // IPv4 GW |
240 | | conv.xfrIP(d_ip4); |
241 | | break; |
242 | | case 2: // IPv6 GW |
243 | | conv.xfrIP6(d_ip6); |
244 | | break; |
245 | | case 3: // DNS label |
246 | | conv.xfrName(d_gateway, false); |
247 | | break; |
248 | | default: |
249 | | throw MOADNSException("Parsing record content: invalid gateway type"); |
250 | | }; |
251 | | |
252 | | switch(d_algorithm) { |
253 | | case 0: |
254 | | break; |
255 | | case 1: |
256 | | case 2: |
257 | | conv.xfrBlob(d_publickey); |
258 | | break; |
259 | | default: |
260 | | throw MOADNSException("Parsing record content: invalid algorithm type"); |
261 | | } |
262 | | ) |
263 | | |
264 | | boilerplate_conv(DHCID, |
265 | | conv.xfrBlob(d_content); |
266 | | ) |
267 | | |
268 | | |
269 | | boilerplate_conv(AFSDB, |
270 | | conv.xfr16BitInt(d_subtype); |
271 | | conv.xfrName(d_hostname); |
272 | | ) |
273 | | |
274 | | |
275 | | boilerplate_conv(NAPTR, |
276 | | conv.xfr16BitInt(d_order); conv.xfr16BitInt(d_preference); |
277 | | conv.xfrText(d_flags); conv.xfrText(d_services); conv.xfrText(d_regexp); |
278 | | conv.xfrName(d_replacement); |
279 | | ) |
280 | | |
281 | | |
282 | | SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, DNSName target) |
283 | | : d_weight(weight), d_port(port), d_target(std::move(target)), d_preference(preference) |
284 | 0 | {} |
285 | | |
286 | | boilerplate_conv(SRV, |
287 | | conv.xfr16BitInt(d_preference); conv.xfr16BitInt(d_weight); conv.xfr16BitInt(d_port); |
288 | | conv.xfrName(d_target); |
289 | | ) |
290 | | |
291 | | SOARecordContent::SOARecordContent(DNSName mname, DNSName rname, const struct soatimes& st) |
292 | | : d_mname(std::move(mname)), d_rname(std::move(rname)), d_st(st) |
293 | 0 | { |
294 | 0 | } |
295 | | |
296 | | boilerplate_conv(SOA, |
297 | | conv.xfrName(d_mname, true); |
298 | | conv.xfrName(d_rname, true); |
299 | | conv.xfr32BitInt(d_st.serial); |
300 | | conv.xfr32BitInt(d_st.refresh); |
301 | | conv.xfr32BitInt(d_st.retry); |
302 | | conv.xfr32BitInt(d_st.expire); |
303 | | conv.xfr32BitInt(d_st.minimum); |
304 | | ); |
305 | | #undef KEY |
306 | | boilerplate_conv(KEY, |
307 | | conv.xfr16BitInt(d_flags); |
308 | | conv.xfr8BitInt(d_protocol); |
309 | | conv.xfr8BitInt(d_algorithm); |
310 | | conv.xfrBlob(d_certificate); |
311 | | ); |
312 | | |
313 | | boilerplate_conv(ZONEMD, |
314 | | conv.xfr32BitInt(d_serial); |
315 | | conv.xfr8BitInt(d_scheme); |
316 | | conv.xfr8BitInt(d_hashalgo); |
317 | | conv.xfrHexBlob(d_digest, true); // keep reading across spaces |
318 | | ); |
319 | | |
320 | | boilerplate_conv(CERT, |
321 | | conv.xfr16BitInt(d_type); |
322 | | if (d_type == 0) throw MOADNSException("CERT type 0 is reserved"); |
323 | | |
324 | | conv.xfr16BitInt(d_tag); |
325 | | conv.xfr8BitInt(d_algorithm); |
326 | | conv.xfrBlob(d_certificate); |
327 | | ) |
328 | | |
329 | | boilerplate_conv(TLSA, |
330 | | conv.xfr8BitInt(d_certusage); |
331 | | conv.xfr8BitInt(d_selector); |
332 | | conv.xfr8BitInt(d_matchtype); |
333 | | conv.xfrHexBlob(d_cert, true); |
334 | | ) |
335 | | |
336 | | boilerplate_conv(OPENPGPKEY, |
337 | | conv.xfrBlob(d_keyring); |
338 | | ) |
339 | | |
340 | | boilerplate_conv(SVCB, |
341 | | conv.xfr16BitInt(d_priority); |
342 | | conv.xfrName(d_target, false, true); |
343 | | if (d_priority != 0) { |
344 | | conv.xfrSvcParamKeyVals(d_params); |
345 | | } |
346 | | ) |
347 | | |
348 | | boilerplate_conv(HTTPS, |
349 | | conv.xfr16BitInt(d_priority); |
350 | | conv.xfrName(d_target, false, true); |
351 | | if (d_priority != 0) { |
352 | | conv.xfrSvcParamKeyVals(d_params); |
353 | | } |
354 | | ) |
355 | | |
356 | | boilerplate_conv(SMIMEA, |
357 | | conv.xfr8BitInt(d_certusage); |
358 | | conv.xfr8BitInt(d_selector); |
359 | | conv.xfr8BitInt(d_matchtype); |
360 | | conv.xfrHexBlob(d_cert, true); |
361 | | ) |
362 | | |
363 | 0 | DSRecordContent::DSRecordContent() {} |
364 | | boilerplate_conv(DS, |
365 | | conv.xfr16BitInt(d_tag); |
366 | | conv.xfr8BitInt(d_algorithm); |
367 | | conv.xfr8BitInt(d_digesttype); |
368 | | conv.xfrHexBlob(d_digest, true); // keep reading across spaces |
369 | | ) |
370 | | |
371 | 0 | CDSRecordContent::CDSRecordContent() {} |
372 | | boilerplate_conv(CDS, |
373 | | conv.xfr16BitInt(d_tag); |
374 | | conv.xfr8BitInt(d_algorithm); |
375 | | conv.xfr8BitInt(d_digesttype); |
376 | | conv.xfrHexBlob(d_digest, true); // keep reading across spaces |
377 | | ) |
378 | | |
379 | 0 | DLVRecordContent::DLVRecordContent() {} |
380 | | boilerplate_conv(DLV, |
381 | | conv.xfr16BitInt(d_tag); |
382 | | conv.xfr8BitInt(d_algorithm); |
383 | | conv.xfr8BitInt(d_digesttype); |
384 | | conv.xfrHexBlob(d_digest, true); // keep reading across spaces |
385 | | ) |
386 | | |
387 | | |
388 | | boilerplate_conv(SSHFP, |
389 | | conv.xfr8BitInt(d_algorithm); |
390 | | conv.xfr8BitInt(d_fptype); |
391 | | conv.xfrHexBlob(d_fingerprint, true); |
392 | | ) |
393 | | |
394 | | boilerplate_conv(RRSIG, |
395 | | conv.xfrType(d_type); |
396 | | conv.xfr8BitInt(d_algorithm); |
397 | | conv.xfr8BitInt(d_labels); |
398 | | conv.xfr32BitInt(d_originalttl); |
399 | | conv.xfrTime(d_sigexpire); |
400 | | conv.xfrTime(d_siginception); |
401 | | conv.xfr16BitInt(d_tag); |
402 | | conv.xfrName(d_signer); |
403 | | conv.xfrBlob(d_signature); |
404 | | ) |
405 | | |
406 | 0 | RRSIGRecordContent::RRSIGRecordContent() {} |
407 | | |
408 | | boilerplate_conv(DNSKEY, |
409 | | conv.xfr16BitInt(d_flags); |
410 | | conv.xfr8BitInt(d_protocol); |
411 | | conv.xfr8BitInt(d_algorithm); |
412 | | conv.xfrBlob(d_key); |
413 | | ) |
414 | 0 | DNSKEYRecordContent::DNSKEYRecordContent() {} |
415 | | |
416 | | boilerplate_conv(CDNSKEY, |
417 | | conv.xfr16BitInt(d_flags); |
418 | | conv.xfr8BitInt(d_protocol); |
419 | | conv.xfr8BitInt(d_algorithm); |
420 | | conv.xfrBlob(d_key); |
421 | | ) |
422 | 0 | CDNSKEYRecordContent::CDNSKEYRecordContent() {} |
423 | | |
424 | | boilerplate_conv(RKEY, |
425 | | conv.xfr16BitInt(d_flags); |
426 | | conv.xfr8BitInt(d_protocol); |
427 | | conv.xfr8BitInt(d_algorithm); |
428 | | conv.xfrBlob(d_key); |
429 | | ) |
430 | 0 | RKEYRecordContent::RKEYRecordContent() {} |
431 | | |
432 | | boilerplate_conv(NID, |
433 | | conv.xfr16BitInt(d_preference); |
434 | | conv.xfrNodeOrLocatorID(d_node_id);) |
435 | | |
436 | | boilerplate_conv(L32, |
437 | | conv.xfr16BitInt(d_preference); |
438 | | conv.xfrIP(d_locator);) |
439 | | |
440 | | boilerplate_conv(L64, |
441 | | conv.xfr16BitInt(d_preference); |
442 | | conv.xfrNodeOrLocatorID(d_locator);) |
443 | | |
444 | | boilerplate_conv(LP, |
445 | | conv.xfr16BitInt(d_preference); |
446 | | conv.xfrName(d_fqdn, false);) |
447 | | |
448 | | /* EUI48 start */ |
449 | | void EUI48RecordContent::report() |
450 | 2 | { |
451 | 2 | regist(1, QType::EUI48, &make, &make, "EUI48"); |
452 | 2 | } |
453 | | std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr) |
454 | 762 | { |
455 | 762 | if(dr.d_clen!=6) |
456 | 23 | throw MOADNSException("Wrong size for EUI48 record"); |
457 | | |
458 | 739 | auto ret=std::make_shared<EUI48RecordContent>(); |
459 | 739 | pr.copyRecord((uint8_t*) &ret->d_eui48, 6); |
460 | 739 | return ret; |
461 | 762 | } |
462 | | std::shared_ptr<DNSRecordContent> EUI48RecordContent::make(const string& zone) |
463 | 0 | { |
464 | | // try to parse |
465 | 0 | auto ret=std::make_shared<EUI48RecordContent>(); |
466 | | // format is 6 hex bytes and dashes |
467 | 0 | if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx", |
468 | 0 | ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2, |
469 | 0 | ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) { |
470 | 0 | throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse"); |
471 | 0 | } |
472 | 0 | return ret; |
473 | 0 | } |
474 | | void EUI48RecordContent::toPacket(DNSPacketWriter& pw) const |
475 | 0 | { |
476 | 0 | string blob(d_eui48, d_eui48+6); |
477 | 0 | pw.xfrBlob(blob); |
478 | 0 | } |
479 | | |
480 | | string EUI48RecordContent::getZoneRepresentation(bool /* noDot */) const |
481 | 0 | { |
482 | 0 | char tmp[18]; |
483 | 0 | snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x", |
484 | 0 | d_eui48[0], d_eui48[1], d_eui48[2], |
485 | 0 | d_eui48[3], d_eui48[4], d_eui48[5]); |
486 | 0 | return tmp; |
487 | 0 | } |
488 | | |
489 | | /* EUI48 end */ |
490 | | |
491 | | /* EUI64 start */ |
492 | | |
493 | | void EUI64RecordContent::report() |
494 | 2 | { |
495 | 2 | regist(1, QType::EUI64, &make, &make, "EUI64"); |
496 | 2 | } |
497 | | std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr) |
498 | 1.01k | { |
499 | 1.01k | if(dr.d_clen!=8) |
500 | 16 | throw MOADNSException("Wrong size for EUI64 record"); |
501 | | |
502 | 1.00k | auto ret=std::make_shared<EUI64RecordContent>(); |
503 | 1.00k | pr.copyRecord((uint8_t*) &ret->d_eui64, 8); |
504 | 1.00k | return ret; |
505 | 1.01k | } |
506 | | std::shared_ptr<DNSRecordContent> EUI64RecordContent::make(const string& zone) |
507 | 0 | { |
508 | | // try to parse |
509 | 0 | auto ret=std::make_shared<EUI64RecordContent>(); |
510 | | // format is 8 hex bytes and dashes |
511 | 0 | if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx", |
512 | 0 | ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2, |
513 | 0 | ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5, |
514 | 0 | ret->d_eui64+6, ret->d_eui64+7) != 8) { |
515 | 0 | throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse"); |
516 | 0 | } |
517 | 0 | return ret; |
518 | 0 | } |
519 | | void EUI64RecordContent::toPacket(DNSPacketWriter& pw) const |
520 | 0 | { |
521 | 0 | string blob(d_eui64, d_eui64+8); |
522 | 0 | pw.xfrBlob(blob); |
523 | 0 | } |
524 | | |
525 | | string EUI64RecordContent::getZoneRepresentation(bool /* noDot */) const |
526 | 0 | { |
527 | 0 | char tmp[24]; |
528 | 0 | snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", |
529 | 0 | d_eui64[0], d_eui64[1], d_eui64[2], |
530 | 0 | d_eui64[3], d_eui64[4], d_eui64[5], |
531 | 0 | d_eui64[6], d_eui64[7]); |
532 | 0 | return tmp; |
533 | 0 | } |
534 | | |
535 | | /* EUI64 end */ |
536 | | |
537 | | /* APL start */ |
538 | | /* https://tools.ietf.org/html/rfc3123 */ |
539 | | void APLRecordContent::report() |
540 | 2 | { |
541 | 2 | regist(1, QType::APL, &make, &make, "APL"); |
542 | 2 | } |
543 | | |
544 | | // Parse incoming packets (e.g. nsupdate) |
545 | 844 | std::shared_ptr<DNSRecordContent> APLRecordContent::make(const DNSRecord &dr, PacketReader& pr) { |
546 | 844 | uint8_t temp; |
547 | 844 | APLRDataElement ard; |
548 | 844 | size_t processed = 0; |
549 | | |
550 | 844 | auto ret=std::make_shared<APLRecordContent>(); |
551 | | |
552 | 19.4k | while (processed<dr.d_clen) { |
553 | 18.7k | pr.xfr16BitInt(ard.d_family); |
554 | 18.7k | pr.xfr8BitInt(ard.d_prefix); |
555 | 18.7k | pr.xfr8BitInt(temp); |
556 | 18.7k | ard.d_n = (temp & 128) >> 7; |
557 | 18.7k | ard.d_afdlength = temp & 127; |
558 | | |
559 | 18.7k | if (ard.d_family == APL_FAMILY_IPV4) { |
560 | 17.3k | if (ard.d_afdlength > 4) { |
561 | 5 | throw MOADNSException("Invalid IP length for IPv4 APL"); |
562 | 5 | } |
563 | 17.3k | memset(ard.d_ip.d_ip4, 0, sizeof(ard.d_ip.d_ip4)); |
564 | 17.8k | for (u_int i=0; i < ard.d_afdlength; i++) |
565 | 498 | pr.xfr8BitInt(ard.d_ip.d_ip4[i]); |
566 | 17.3k | } else if (ard.d_family == APL_FAMILY_IPV6) { |
567 | 1.34k | if (ard.d_afdlength > 16) { |
568 | 4 | throw MOADNSException("Invalid IP length for IPv6 APL"); |
569 | 4 | } |
570 | 1.34k | memset(ard.d_ip.d_ip6, 0, sizeof(ard.d_ip.d_ip6)); |
571 | 2.13k | for (u_int i=0; i < ard.d_afdlength; i++) |
572 | 793 | pr.xfr8BitInt(ard.d_ip.d_ip6[i]); |
573 | 1.34k | } else |
574 | 105 | throw MOADNSException("Unknown family for APL record"); |
575 | | |
576 | 18.6k | processed += 4 + ard.d_afdlength; |
577 | | |
578 | 18.6k | ret->aplrdata.push_back(ard); |
579 | 18.6k | } |
580 | | |
581 | 730 | return ret; |
582 | 844 | } |
583 | | |
584 | | // Parse a single APL <apitem> |
585 | 0 | APLRDataElement APLRecordContent::parseAPLElement(const string& element) { |
586 | 0 | string record; |
587 | 0 | Netmask nm; |
588 | 0 | unsigned int bytes; |
589 | 0 | bool done_trimming; |
590 | 0 | APLRDataElement ard; |
591 | | |
592 | | // Parse the optional leading ! (negate) |
593 | 0 | if (element.at(0) == '!') { |
594 | 0 | ard.d_n = true; |
595 | 0 | record = element.substr(1, element.length()-1); |
596 | 0 | } else { |
597 | 0 | ard.d_n = false; |
598 | 0 | record = element; |
599 | 0 | } |
600 | |
|
601 | 0 | if (record.find('/') == string::npos) { // Required by RFC section 5 |
602 | 0 | throw MOADNSException("Asked to decode '"+element+"' as an APL record, but missing subnet mask"); |
603 | 0 | } |
604 | | |
605 | | |
606 | 0 | if (record.find("1:", 0) == 0) { // IPv4 |
607 | 0 | uint32_t v4ip; |
608 | |
|
609 | 0 | ard.d_family = APL_FAMILY_IPV4; |
610 | | |
611 | | // Ensure that a mask is provided |
612 | | |
613 | | // Read IPv4 string into a Netmask object |
614 | 0 | nm = Netmask(record.substr(2, record.length() - 2)); |
615 | 0 | ard.d_prefix = nm.getBits(); |
616 | |
|
617 | 0 | if (nm.getNetwork().isIPv4() == 0) |
618 | 0 | throw MOADNSException("Asked to decode '"+element+"' as an APL v4 record"); |
619 | | |
620 | | // Section 4.1 of RFC 3123 (don't send trailing "0" bytes) |
621 | | // Copy data; using array of bytes since we might end up truncating them in the packet |
622 | 0 | v4ip = ntohl(nm.getNetwork().sin4.sin_addr.s_addr); |
623 | 0 | memset(ard.d_ip.d_ip4, 0, sizeof(ard.d_ip.d_ip4)); |
624 | 0 | bytes = 4; // Start by assuming we'll send 4 bytes |
625 | 0 | done_trimming = false; |
626 | 0 | for (int i=0; i<4; i++) { |
627 | 0 | ard.d_ip.d_ip4[3-i] = (v4ip & 255); |
628 | | // Remove trailing "0" bytes from packet and update length |
629 | 0 | if ((v4ip & 255) == 0 and !done_trimming) { |
630 | 0 | bytes--; |
631 | 0 | } else { |
632 | 0 | done_trimming = true; |
633 | 0 | } |
634 | 0 | v4ip = v4ip >> 8; |
635 | 0 | } |
636 | 0 | ard.d_afdlength = bytes; |
637 | |
|
638 | 0 | } else if (record.find("2:", 0) == 0) { // IPv6 |
639 | 0 | ard.d_family = APL_FAMILY_IPV6; |
640 | | |
641 | | // Parse IPv6 string into a Netmask object |
642 | 0 | nm = Netmask(record.substr(2, record.length() - 2)); |
643 | 0 | ard.d_prefix = nm.getBits(); |
644 | |
|
645 | 0 | if (nm.getNetwork().isIPv6() == 0) |
646 | 0 | throw MOADNSException("Asked to decode '"+element+"' as an APL v6 record"); |
647 | | |
648 | | // Section 4.2 of RFC 3123 (don't send trailing "0" bytes) |
649 | | // Remove trailing "0" bytes from packet and reduce length |
650 | 0 | memset(ard.d_ip.d_ip6, 0, sizeof(ard.d_ip.d_ip6)); |
651 | 0 | bytes = 16; // Start by assuming we'll send 16 bytes |
652 | 0 | done_trimming = false; |
653 | 0 | for (int i=0; i<16; i++) { |
654 | 0 | ard.d_ip.d_ip6[15-i] = nm.getNetwork().sin6.sin6_addr.s6_addr[15-i]; |
655 | 0 | if (nm.getNetwork().sin6.sin6_addr.s6_addr[15-i] == 0 and !done_trimming) { |
656 | | // trailing 0 byte, update length |
657 | 0 | bytes--; |
658 | 0 | } else { |
659 | 0 | done_trimming = true; |
660 | 0 | } |
661 | 0 | } |
662 | 0 | ard.d_afdlength = bytes; |
663 | |
|
664 | 0 | } else { |
665 | 0 | throw MOADNSException("Asked to encode '"+element+"' as an IPv6 APL record but got unknown Address Family"); |
666 | 0 | } |
667 | 0 | return ard; |
668 | |
|
669 | 0 | } |
670 | | |
671 | | // Parse backend record (0, 1 or more <apitem>) |
672 | 0 | std::shared_ptr<DNSRecordContent> APLRecordContent::make(const string& zone) { |
673 | 0 | APLRDataElement ard; |
674 | 0 | vector<string> elements; |
675 | |
|
676 | 0 | auto ret=std::make_shared<APLRecordContent>(); |
677 | |
|
678 | 0 | boost::split(elements, zone, boost::is_any_of(" ")); |
679 | 0 | for (auto & element : elements) { |
680 | 0 | if (!element.empty()) { |
681 | 0 | ard = ret->parseAPLElement(element); |
682 | 0 | ret->aplrdata.push_back(ard); |
683 | 0 | } |
684 | 0 | } |
685 | 0 | return ret; |
686 | 0 | } |
687 | | |
688 | | |
689 | | // DNSRecord to Packet conversion |
690 | 0 | void APLRecordContent::toPacket(DNSPacketWriter& pw) const { |
691 | 0 | for (auto & ard : aplrdata) { |
692 | 0 | pw.xfr16BitInt(ard.d_family); |
693 | 0 | pw.xfr8BitInt(ard.d_prefix); |
694 | 0 | pw.xfr8BitInt((ard.d_n << 7) + ard.d_afdlength); |
695 | 0 | if (ard.d_family == APL_FAMILY_IPV4) { |
696 | 0 | for (int i=0; i<ard.d_afdlength; i++) { |
697 | 0 | pw.xfr8BitInt(ard.d_ip.d_ip4[i]); |
698 | 0 | } |
699 | 0 | } else if (ard.d_family == APL_FAMILY_IPV6) { |
700 | 0 | for (int i=0; i<ard.d_afdlength; i++) { |
701 | 0 | pw.xfr8BitInt(ard.d_ip.d_ip6[i]); |
702 | 0 | } |
703 | 0 | } |
704 | 0 | } |
705 | 0 | } |
706 | | |
707 | | // Decode record into string |
708 | 0 | string APLRecordContent::getZoneRepresentation(bool /* noDot */) const { |
709 | 0 | string s_n, s_family, output; |
710 | 0 | ComboAddress ca; |
711 | 0 | Netmask nm; |
712 | |
|
713 | 0 | output = ""; |
714 | |
|
715 | 0 | for (std::vector<APLRDataElement>::const_iterator ard = aplrdata.begin() ; ard != aplrdata.end(); ++ard) { |
716 | | |
717 | | // Negation flag |
718 | 0 | if (ard->d_n) { |
719 | 0 | s_n = "!"; |
720 | 0 | } else { |
721 | 0 | s_n = ""; |
722 | 0 | } |
723 | |
|
724 | 0 | if (ard->d_family == APL_FAMILY_IPV4) { // IPv4 |
725 | 0 | s_family = std::to_string(APL_FAMILY_IPV4); |
726 | 0 | ca = ComboAddress(); |
727 | 0 | memcpy(&ca.sin4.sin_addr.s_addr, ard->d_ip.d_ip4, sizeof(ca.sin4.sin_addr.s_addr)); |
728 | 0 | } else if (ard->d_family == APL_FAMILY_IPV6) { // IPv6 |
729 | 0 | s_family = std::to_string(APL_FAMILY_IPV6); |
730 | 0 | ca = ComboAddress(); |
731 | 0 | ca.sin4.sin_family = AF_INET6; |
732 | 0 | memset(&ca.sin6.sin6_addr.s6_addr, 0, sizeof(ca.sin6.sin6_addr.s6_addr)); |
733 | 0 | memcpy(&ca.sin6.sin6_addr.s6_addr, ard->d_ip.d_ip6, ard->d_afdlength); |
734 | 0 | } else { |
735 | 0 | throw MOADNSException("Asked to decode APL record but got unknown Address Family"); |
736 | 0 | } |
737 | | |
738 | 0 | nm = Netmask(ca, ard->d_prefix); |
739 | |
|
740 | 0 | output += s_n + s_family + ":" + nm.toString(); |
741 | 0 | if (std::next(ard) != aplrdata.end()) |
742 | 0 | output += " "; |
743 | 0 | } |
744 | 0 | return output; |
745 | 0 | } |
746 | | |
747 | | /* APL end */ |
748 | | |
749 | | /* SVCB start */ |
750 | 0 | bool SVCBBaseRecordContent::autoHint(const SvcParam::SvcParamKey &key) const { |
751 | 0 | auto p = getParamIt(key); |
752 | 0 | if (p == d_params.end()) { |
753 | 0 | return false; |
754 | 0 | } |
755 | 0 | return p->getAutoHint(); |
756 | 0 | } |
757 | | |
758 | 0 | void SVCBBaseRecordContent::setHints(const SvcParam::SvcParamKey &key, const std::vector<ComboAddress> &addresses) { |
759 | 0 | auto p = getParamIt(key); |
760 | 0 | if (p == d_params.end()) { |
761 | 0 | return; |
762 | 0 | } |
763 | | |
764 | 0 | std::vector<ComboAddress> h; |
765 | 0 | h.reserve(h.size() + addresses.size()); |
766 | 0 | h.insert(h.end(), addresses.begin(), addresses.end()); |
767 | |
|
768 | 0 | try { |
769 | 0 | auto newParam = SvcParam(key, std::move(h)); |
770 | 0 | d_params.erase(p); |
771 | 0 | d_params.insert(newParam); |
772 | 0 | } catch (...) { |
773 | | // XXX maybe we should SERVFAIL instead? |
774 | 0 | return; |
775 | 0 | } |
776 | 0 | } |
777 | | |
778 | 0 | void SVCBBaseRecordContent::removeParam(const SvcParam::SvcParamKey &key) { |
779 | 0 | auto p = getParamIt(key); |
780 | 0 | if (p == d_params.end()) { |
781 | 0 | return; |
782 | 0 | } |
783 | 0 | d_params.erase(p); |
784 | 0 | } |
785 | | |
786 | 0 | bool SVCBBaseRecordContent::hasParams() const { |
787 | 0 | return !d_params.empty(); |
788 | 0 | } |
789 | | |
790 | 0 | bool SVCBBaseRecordContent::hasParam(const SvcParam::SvcParamKey &key) const { |
791 | 0 | return getParamIt(key) != d_params.end(); |
792 | 0 | } |
793 | | |
794 | 0 | SvcParam SVCBBaseRecordContent::getParam(const SvcParam::SvcParamKey &key) const { |
795 | 0 | auto p = getParamIt(key); |
796 | 0 | if (p == d_params.end()) { |
797 | 0 | throw std::out_of_range("No param with key " + SvcParam::keyToString(key)); |
798 | 0 | } |
799 | 0 | return *p; |
800 | 0 | } |
801 | | |
802 | 0 | set<SvcParam>::const_iterator SVCBBaseRecordContent::getParamIt(const SvcParam::SvcParamKey &key) const { |
803 | 0 | auto p = std::find_if(d_params.begin(), d_params.end(), |
804 | 0 | [&key](const SvcParam ¶m) { |
805 | 0 | return param.getKey() == key; |
806 | 0 | }); |
807 | 0 | return p; |
808 | 0 | } |
809 | | |
810 | | std::shared_ptr<SVCBBaseRecordContent> SVCBRecordContent::clone() const |
811 | 0 | { |
812 | 0 | return std::shared_ptr<SVCBBaseRecordContent>(std::make_shared<SVCBRecordContent>(*this)); |
813 | 0 | } |
814 | | |
815 | | std::shared_ptr<SVCBBaseRecordContent> HTTPSRecordContent::clone() const |
816 | 0 | { |
817 | 0 | return std::shared_ptr<SVCBBaseRecordContent>(std::make_shared<HTTPSRecordContent>(*this)); |
818 | 0 | } |
819 | | |
820 | | /* SVCB end */ |
821 | | |
822 | | boilerplate_conv(TKEY, |
823 | | conv.xfrName(d_algo); |
824 | | conv.xfr32BitInt(d_inception); |
825 | | conv.xfr32BitInt(d_expiration); |
826 | | conv.xfr16BitInt(d_mode); |
827 | | conv.xfr16BitInt(d_error); |
828 | | conv.xfr16BitInt(d_keysize); |
829 | | if (d_keysize>0) conv.xfrBlobNoSpaces(d_key, d_keysize); |
830 | | conv.xfr16BitInt(d_othersize); |
831 | | if (d_othersize>0) conv.xfrBlobNoSpaces(d_other, d_othersize); |
832 | | ) |
833 | 0 | TKEYRecordContent::TKEYRecordContent() { d_othersize = 0; } // fix CID#1288932 |
834 | | |
835 | | boilerplate_conv(URI, |
836 | | conv.xfr16BitInt(d_priority); |
837 | | conv.xfr16BitInt(d_weight); |
838 | | conv.xfrText(d_target, true, false); |
839 | | ) |
840 | | |
841 | | boilerplate_conv(CAA, |
842 | | conv.xfr8BitInt(d_flags); |
843 | | conv.xfrUnquotedText(d_tag, true); |
844 | | conv.xfrText(d_value, true, false); /* no lenField */ |
845 | | ) |
846 | | |
847 | | static uint16_t makeTag(const std::string& data) |
848 | 0 | { |
849 | 0 | const unsigned char* key=(const unsigned char*)data.c_str(); |
850 | 0 | unsigned int keysize=data.length(); |
851 | |
|
852 | 0 | unsigned long ac; /* assumed to be 32 bits or larger */ |
853 | 0 | unsigned int i; /* loop index */ |
854 | |
|
855 | 0 | for ( ac = 0, i = 0; i < keysize; ++i ) |
856 | 0 | ac += (i & 1) ? key[i] : key[i] << 8; |
857 | 0 | ac += (ac >> 16) & 0xFFFF; |
858 | 0 | return ac & 0xFFFF; |
859 | 0 | } |
860 | | |
861 | | uint16_t DNSKEYRecordContent::getTag() const |
862 | 0 | { |
863 | 0 | return makeTag(this->serialize(DNSName())); |
864 | 0 | } |
865 | | |
866 | | |
867 | | /* |
868 | | * Fills `eo` by parsing the EDNS(0) OPT RR (RFC 6891) |
869 | | */ |
870 | | bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo) |
871 | 0 | { |
872 | 0 | eo->d_extFlags=0; |
873 | 0 | if(mdp.d_header.arcount && !mdp.d_answers.empty()) { |
874 | 0 | for(const MOADNSParser::answers_t::value_type& val : mdp.d_answers) { |
875 | 0 | if(val.first.d_place == DNSResourceRecord::ADDITIONAL && val.first.d_type == QType::OPT) { |
876 | 0 | eo->d_packetsize=val.first.d_class; |
877 | |
|
878 | 0 | EDNS0Record stuff; |
879 | 0 | uint32_t ttl=ntohl(val.first.d_ttl); |
880 | 0 | static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)"); |
881 | 0 | memcpy(&stuff, &ttl, sizeof(stuff)); |
882 | |
|
883 | 0 | eo->d_extRCode=stuff.extRCode; |
884 | 0 | eo->d_version=stuff.version; |
885 | 0 | eo->d_extFlags = ntohs(stuff.extFlags); |
886 | 0 | auto orc = getRR<OPTRecordContent>(val.first); |
887 | 0 | if(orc == nullptr) |
888 | 0 | return false; |
889 | 0 | orc->getData(eo->d_options); |
890 | 0 | return true; |
891 | 0 | } |
892 | 0 | } |
893 | 0 | } |
894 | 0 | return false; |
895 | 0 | } |
896 | | |
897 | | void reportBasicTypes() |
898 | 2 | { |
899 | 2 | ARecordContent::report(); |
900 | 2 | AAAARecordContent::report(); |
901 | 2 | NSRecordContent::report(); |
902 | 2 | CNAMERecordContent::report(); |
903 | 2 | MXRecordContent::report(); |
904 | 2 | SOARecordContent::report(); |
905 | 2 | SRVRecordContent::report(); |
906 | 2 | PTRRecordContent::report(); |
907 | 2 | DNSRecordContent::regist(QClass::CHAOS, QType::TXT, &TXTRecordContent::make, &TXTRecordContent::make, "TXT"); |
908 | 2 | TXTRecordContent::report(); |
909 | | #ifdef HAVE_LUA_RECORDS |
910 | | LUARecordContent::report(); |
911 | | #endif |
912 | 2 | DNSRecordContent::regist(QClass::IN, QType::ANY, nullptr, nullptr, "ANY"); |
913 | 2 | DNSRecordContent::regist(QClass::IN, QType::AXFR, nullptr, nullptr, "AXFR"); |
914 | 2 | DNSRecordContent::regist(QClass::IN, QType::IXFR, nullptr, nullptr, "IXFR"); |
915 | 2 | } |
916 | | |
917 | | void reportOtherTypes() |
918 | 2 | { |
919 | 2 | MBRecordContent::report(); |
920 | 2 | MGRecordContent::report(); |
921 | 2 | MRRecordContent::report(); |
922 | 2 | AFSDBRecordContent::report(); |
923 | 2 | DNAMERecordContent::report(); |
924 | 2 | #if !defined(RECURSOR) |
925 | 2 | ALIASRecordContent::report(); |
926 | 2 | #endif |
927 | 2 | SPFRecordContent::report(); |
928 | 2 | NAPTRRecordContent::report(); |
929 | 2 | KXRecordContent::report(); |
930 | 2 | LOCRecordContent::report(); |
931 | 2 | ENTRecordContent::report(); |
932 | 2 | HINFORecordContent::report(); |
933 | 2 | RPRecordContent::report(); |
934 | 2 | KEYRecordContent::report(); |
935 | 2 | DNSKEYRecordContent::report(); |
936 | 2 | DHCIDRecordContent::report(); |
937 | 2 | CDNSKEYRecordContent::report(); |
938 | 2 | RKEYRecordContent::report(); |
939 | 2 | RRSIGRecordContent::report(); |
940 | 2 | DSRecordContent::report(); |
941 | 2 | CDSRecordContent::report(); |
942 | 2 | SSHFPRecordContent::report(); |
943 | 2 | CERTRecordContent::report(); |
944 | 2 | NSECRecordContent::report(); |
945 | 2 | NSEC3RecordContent::report(); |
946 | 2 | NSEC3PARAMRecordContent::report(); |
947 | 2 | TLSARecordContent::report(); |
948 | 2 | SMIMEARecordContent::report(); |
949 | 2 | OPENPGPKEYRecordContent::report(); |
950 | 2 | SVCBRecordContent::report(); |
951 | 2 | HTTPSRecordContent::report(); |
952 | 2 | DLVRecordContent::report(); |
953 | 2 | DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG"); |
954 | 2 | DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY"); |
955 | | //TSIGRecordContent::report(); |
956 | 2 | OPTRecordContent::report(); |
957 | 2 | EUI48RecordContent::report(); |
958 | 2 | EUI64RecordContent::report(); |
959 | 2 | MINFORecordContent::report(); |
960 | 2 | URIRecordContent::report(); |
961 | 2 | CAARecordContent::report(); |
962 | 2 | APLRecordContent::report(); |
963 | 2 | IPSECKEYRecordContent::report(); |
964 | 2 | CSYNCRecordContent::report(); |
965 | 2 | NIDRecordContent::report(); |
966 | 2 | L32RecordContent::report(); |
967 | 2 | L64RecordContent::report(); |
968 | 2 | LPRecordContent::report(); |
969 | 2 | ZONEMDRecordContent::report(); |
970 | 2 | } |
971 | | |
972 | | void reportAllTypes() |
973 | 2 | { |
974 | 2 | reportBasicTypes(); |
975 | 2 | reportOtherTypes(); |
976 | 2 | } |
977 | | |
978 | | ComboAddress getAddr(const DNSRecord& dr, uint16_t defport) |
979 | 0 | { |
980 | 0 | if (auto a = getRR<ARecordContent>(dr)) { |
981 | 0 | return a->getCA(defport); |
982 | 0 | } |
983 | 0 | else if (auto aaaa = getRR<AAAARecordContent>(dr)) { |
984 | 0 | return aaaa->getCA(defport); |
985 | 0 | } |
986 | 0 | throw std::invalid_argument("not an A or AAAA record"); |
987 | 0 | } |
988 | | |
989 | | /** |
990 | | * Check if the DNSNames that should be hostnames, are hostnames |
991 | | */ |
992 | | void checkHostnameCorrectness(const DNSResourceRecord& rr) |
993 | 0 | { |
994 | 0 | if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) { |
995 | 0 | DNSName toCheck; |
996 | 0 | if (rr.qtype.getCode() == QType::SRV) { |
997 | 0 | vector<string> parts; |
998 | 0 | stringtok(parts, rr.getZoneRepresentation()); |
999 | 0 | if (parts.size() == 4) toCheck = DNSName(parts[3]); |
1000 | 0 | } else if (rr.qtype.getCode() == QType::MX) { |
1001 | 0 | vector<string> parts; |
1002 | 0 | stringtok(parts, rr.getZoneRepresentation()); |
1003 | 0 | if (parts.size() == 2) toCheck = DNSName(parts[1]); |
1004 | 0 | } else { |
1005 | 0 | toCheck = DNSName(rr.content); |
1006 | 0 | } |
1007 | |
|
1008 | 0 | if (toCheck.empty()) { |
1009 | 0 | throw std::runtime_error("unable to extract hostname from content"); |
1010 | 0 | } |
1011 | 0 | else if ((rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) && toCheck == g_rootdnsname) { |
1012 | | // allow null MX/SRV |
1013 | 0 | } else if(!toCheck.isHostname()) { |
1014 | 0 | throw std::runtime_error(boost::str(boost::format("non-hostname content %s") % toCheck.toString())); |
1015 | 0 | } |
1016 | 0 | } |
1017 | 0 | } |
1018 | | |
1019 | | #if 0 |
1020 | | static struct Reporter |
1021 | | { |
1022 | | Reporter() |
1023 | | { |
1024 | | reportAllTypes(); |
1025 | | } |
1026 | | } reporter __attribute__((init_priority(65535))); |
1027 | | #endif |