]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsrecords.cc
auth: switch circleci mssql image
[thirdparty/pdns.git] / pdns / dnsrecords.cc
CommitLineData
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
30void 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 47string 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
80bool 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 90boilerplate_conv(A, QType::A, conv.xfrIP(d_ip));
8c1c9170 91
5a1f298f 92ARecordContent::ARecordContent(uint32_t ip)
efb265e3
BH
93{
94 d_ip = ip;
95}
96
5a1f298f 97ARecordContent::ARecordContent(const ComboAddress& ca)
447e0cff 98{
99 d_ip = ca.sin4.sin_addr.s_addr;
100}
101
5a1f298f 102AAAARecordContent::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 109ComboAddress 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
118ComboAddress 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
130void 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 136boilerplate_conv(AAAA, QType::AAAA, conv.xfrIP6(d_ip6); );
9d9c52ef 137
ad8fa726
PD
138boilerplate_conv(NS, QType::NS, conv.xfrName(d_content, true));
139boilerplate_conv(PTR, QType::PTR, conv.xfrName(d_content, true));
140boilerplate_conv(CNAME, QType::CNAME, conv.xfrName(d_content, true));
85c6d90e 141boilerplate_conv(ALIAS, QType::ALIAS, conv.xfrName(d_content, false));
ad8fa726 142boilerplate_conv(DNAME, QType::DNAME, conv.xfrName(d_content));
fa552262
CHB
143boilerplate_conv(MB, QType::MB, conv.xfrName(d_madname, true));
144boilerplate_conv(MG, QType::MG, conv.xfrName(d_mgmname, true));
ad8fa726
PD
145boilerplate_conv(MR, QType::MR, conv.xfrName(d_alias, true));
146boilerplate_conv(MINFO, QType::MINFO, conv.xfrName(d_rmailbx, true); conv.xfrName(d_emailbx, true));
3bb50daa 147boilerplate_conv(TXT, QType::TXT, conv.xfrText(d_text, true));
8900e2e3 148#ifdef HAVE_LUA_RECORDS
5dbd408c 149boilerplate_conv(LUA, QType::LUA, conv.xfrType(d_type); conv.xfrText(d_code, true));
8900e2e3 150#endif
acedb99e 151boilerplate_conv(ENT, 0, );
ef6a78d5 152boilerplate_conv(SPF, 99, conv.xfrText(d_text, true));
3bb50daa 153boilerplate_conv(HINFO, QType::HINFO, conv.xfrText(d_cpu); conv.xfrText(d_host));
ff6a1e7b 154
3bb50daa 155boilerplate_conv(RP, QType::RP,
ad8fa726
PD
156 conv.xfrName(d_mbox);
157 conv.xfrName(d_info)
232f0877 158 );
ff6a1e7b 159
ff6a1e7b 160
3bb50daa 161boilerplate_conv(OPT, QType::OPT,
232f0877
CH
162 conv.xfrBlob(d_data)
163 );
878435ce 164
8900e2e3 165#ifdef HAVE_LUA_RECORDS
98fa3598 166string 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
180void 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 198boilerplate_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 212MXRecordContent::MXRecordContent(uint16_t preference, const DNSName& mxname): d_preference(preference), d_mxname(mxname)
2770fad0
BH
213{
214}
ff6a1e7b 215
3bb50daa 216boilerplate_conv(MX, QType::MX,
232f0877 217 conv.xfr16BitInt(d_preference);
ad8fa726 218 conv.xfrName(d_mxname, true);
232f0877 219 )
ff6a1e7b 220
3bb50daa 221boilerplate_conv(KX, QType::KX,
232f0877 222 conv.xfr16BitInt(d_preference);
ad8fa726 223 conv.xfrName(d_exchanger, false);
232f0877 224 )
9fd71f2e 225
3bb50daa 226boilerplate_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
260boilerplate_conv(DHCID, 49,
232f0877
CH
261 conv.xfrBlob(d_content);
262 )
9fd71f2e
BH
263
264
3bb50daa 265boilerplate_conv(AFSDB, QType::AFSDB,
232f0877 266 conv.xfr16BitInt(d_subtype);
ad8fa726 267 conv.xfrName(d_hostname);
232f0877 268 )
37f47031 269
ff6a1e7b 270
3bb50daa 271boilerplate_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 278SRVRecordContent::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 282boilerplate_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 287SOARecordContent::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 292boilerplate_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 302boilerplate_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 309boilerplate_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 318boilerplate_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 325boilerplate_conv(OPENPGPKEY, 61,
e7917c06 326 conv.xfrBlob(d_keyring);
68066337
JC
327 )
328
291935bb
PL
329boilerplate_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 336DSRecordContent::DSRecordContent() {}
8c1c9170 337boilerplate_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 344CDSRecordContent::CDSRecordContent() {}
882de365
PL
345boilerplate_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 352DLVRecordContent::DLVRecordContent() {}
0b55f2f5 353boilerplate_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 361boilerplate_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 367boilerplate_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 379RRSIGRecordContent::RRSIGRecordContent() {}
1c4d88c5 380
8c1c9170 381boilerplate_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 387DNSKEYRecordContent::DNSKEYRecordContent() {}
1c4d88c5 388
882de365
PL
389boilerplate_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 395CDNSKEYRecordContent::CDNSKEYRecordContent() {}
882de365 396
3150a49c 397boilerplate_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 403RKEYRecordContent::RKEYRecordContent() {}
66a07c55 404
3150a49c 405/* EUI48 start */
66a07c55
AT
406void EUI48RecordContent::report(void)
407{
3bb50daa 408 regist(1, QType::EUI48, &make, &make, "EUI48");
66a07c55 409}
32122aab 410std::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 419std::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}
431void EUI48RecordContent::toPacket(DNSPacketWriter& pw)
432{
433 string blob(d_eui48, d_eui48+6);
434 pw.xfrBlob(blob);
435}
f21fc0aa 436string 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
449void EUI64RecordContent::report(void)
450{
3bb50daa 451 regist(1, QType::EUI64, &make, &make, "EUI64");
66a07c55 452}
32122aab 453std::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 462std::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}
475void EUI64RecordContent::toPacket(DNSPacketWriter& pw)
476{
477 string blob(d_eui64, d_eui64+8);
478 pw.xfrBlob(blob);
479}
f21fc0aa 480string 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 492boilerplate_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 503TKEYRecordContent::TKEYRecordContent() { d_othersize = 0; } // fix CID#1288932
66a07c55 504
20966479 505boilerplate_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
511boilerplate_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 517static 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 531uint16_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
537uint16_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
546bool 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 573DNSRecord 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 592void 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
612void 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
654void reportAllTypes()
655{
656 reportBasicTypes();
657 reportOtherTypes();
658}
659
f1ae49f7 660ComboAddress 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 */
672void 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
700static struct Reporter
701{
702 Reporter()
703 {
704 reportAllTypes();
ff6a1e7b
BH
705 }
706} reporter __attribute__((init_priority(65535)));
250d1fd8 707#endif