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