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