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