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 &param) {
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