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