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 #pragma once
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "dnsparser.hh"
28 #include "dnswriter.hh"
29 #include "rcpgenerator.hh"
30 #include <set>
31 #include <bitset>
32 #include "namespaces.hh"
33 #include "iputils.hh"
34 #include "svc-records.hh"
35 
36 #define includeboilerplate(RNAME)   RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \
37   RNAME##RecordContent(const string& zoneData);                                                  \
38   static void report(void);                                                                      \
39   static void unreport(void);                                                                    \
40   static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);          \
41   static std::shared_ptr<DNSRecordContent> make(const string& zonedata);                         \
42   string getZoneRepresentation(bool noDot=false) const override;                                 \
43   void toPacket(DNSPacketWriter& pw) override;                                                   \
44   uint16_t getType() const override { return QType::RNAME; }                                   \
45   template<class Convertor> void xfrPacket(Convertor& conv, bool noDot=false);
46 
47 class NAPTRRecordContent : public DNSRecordContent
48 {
49 public:
50   NAPTRRecordContent(uint16_t order, uint16_t preference, string flags, string services, string regexp, DNSName replacement);
51 
52   includeboilerplate(NAPTR)
53   template<class Convertor> void xfrRecordContent(Convertor& conv);
54 private:
55   uint16_t d_order, d_preference;
56   string d_flags, d_services, d_regexp;
57   DNSName d_replacement;
58 };
59 
60 
61 class ARecordContent : public DNSRecordContent
62 {
63 public:
64   explicit ARecordContent(const ComboAddress& ca);
65   explicit ARecordContent(uint32_t ip);
66   includeboilerplate(A)
67   void doRecordCheck(const DNSRecord& dr);
68   ComboAddress getCA(int port=0) const;
operator ==(const DNSRecordContent & rhs) const69   bool operator==(const DNSRecordContent& rhs) const override
70   {
71     if(typeid(*this) != typeid(rhs))
72       return false;
73     return d_ip == dynamic_cast<const ARecordContent&>(rhs).d_ip;
74   }
75 private:
76   uint32_t d_ip;
77 };
78 
79 class AAAARecordContent : public DNSRecordContent
80 {
81 public:
82   AAAARecordContent(std::string &val);
83   explicit AAAARecordContent(const ComboAddress& ca);
84   includeboilerplate(AAAA)
85   ComboAddress getCA(int port=0) const;
operator ==(const DNSRecordContent & rhs) const86   bool operator==(const DNSRecordContent& rhs) const override
87   {
88     if(typeid(*this) != typeid(rhs))
89       return false;
90     return d_ip6 == dynamic_cast<const decltype(this)>(&rhs)->d_ip6;
91   }
92 private:
93   string d_ip6; // why??
94 };
95 
96 class MXRecordContent : public DNSRecordContent
97 {
98 public:
99   MXRecordContent(uint16_t preference, DNSName  mxname);
100 
101   includeboilerplate(MX)
102 
103   uint16_t d_preference;
104   DNSName d_mxname;
105 
operator ==(const DNSRecordContent & rhs) const106   bool operator==(const DNSRecordContent& rhs) const override
107   {
108     if(typeid(*this) != typeid(rhs))
109       return false;
110     auto rrhs =dynamic_cast<const decltype(this)>(&rhs);
111     return std::tie(d_preference, d_mxname) == std::tie(rrhs->d_preference, rrhs->d_mxname);
112   }
113 
114 };
115 
116 class KXRecordContent : public DNSRecordContent
117 {
118 public:
119   KXRecordContent(uint16_t preference, const DNSName& exchanger);
120 
121   includeboilerplate(KX)
122 
123 private:
124   uint16_t d_preference;
125   DNSName d_exchanger;
126 };
127 
128 class IPSECKEYRecordContent : public DNSRecordContent
129 {
130 public:
131   IPSECKEYRecordContent(uint16_t preference, uint8_t gatewaytype, uint8_t algo, const DNSName& gateway, const string& publickey);
132 
133   includeboilerplate(IPSECKEY)
134 
135 private:
136   uint32_t d_ip4;
137   DNSName d_gateway;
138   string d_publickey;
139   string d_ip6;
140   uint8_t d_preference, d_gatewaytype, d_algorithm;
141 };
142 
143 class DHCIDRecordContent : public DNSRecordContent
144 {
145 public:
146   includeboilerplate(DHCID)
147 
148 private:
149   string d_content;
150 };
151 
152 
153 class SRVRecordContent : public DNSRecordContent
154 {
155 public:
156   SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, DNSName  target);
157 
158   includeboilerplate(SRV)
159 
160   uint16_t d_weight, d_port;
161   DNSName d_target;
162   uint16_t d_preference;
163 };
164 
165 class TSIGRecordContent : public DNSRecordContent
166 {
167 public:
168   includeboilerplate(TSIG)
TSIGRecordContent()169   TSIGRecordContent() {}
170 
171   uint16_t d_origID{0};
172   uint16_t d_fudge{0};
173 
174   DNSName d_algoName;
175   string d_mac;
176   string d_otherData;
177   uint64_t d_time{0};
178   //  uint16_t d_macSize;
179   uint16_t d_eRcode{0};
180   // uint16_t d_otherLen
181 };
182 
183 
184 class TXTRecordContent : public DNSRecordContent
185 {
186 public:
187   includeboilerplate(TXT)
188 
189   string d_text;
190 };
191 
192 #ifdef HAVE_LUA_RECORDS
193 class LUARecordContent : public DNSRecordContent
194 {
195 public:
196   includeboilerplate(LUA)
197   string getCode() const;
198   uint16_t d_type;
199   string d_code;
200 };
201 #endif
202 
203 class ENTRecordContent : public DNSRecordContent
204 {
205 public:
206   includeboilerplate(ENT)
207 };
208 
209 class SPFRecordContent : public DNSRecordContent
210 {
211 public:
includeboilerplate(SPF) const212   includeboilerplate(SPF)
213   const std::string& getText() const
214   {
215     return d_text;
216   }
217 
218 private:
219   string d_text;
220 };
221 
222 
223 class NSRecordContent : public DNSRecordContent
224 {
225 public:
226   includeboilerplate(NS)
NSRecordContent(const DNSName & content)227   explicit NSRecordContent(const DNSName& content) : d_content(content){}
getNS() const228   const DNSName& getNS() const { return d_content; }
operator ==(const DNSRecordContent & rhs) const229   bool operator==(const DNSRecordContent& rhs) const override
230   {
231     if(typeid(*this) != typeid(rhs))
232       return false;
233     auto rrhs =dynamic_cast<const decltype(this)>(&rhs);
234     return d_content == rrhs->d_content;
235   }
236 
237 private:
238   DNSName d_content;
239 };
240 
241 class PTRRecordContent : public DNSRecordContent
242 {
243 public:
244   includeboilerplate(PTR)
PTRRecordContent(const DNSName & content)245   explicit PTRRecordContent(const DNSName& content) : d_content(content){}
getContent() const246   const DNSName& getContent() const { return d_content; }
247 private:
248   DNSName d_content;
249 };
250 
251 class CNAMERecordContent : public DNSRecordContent
252 {
253 public:
254   includeboilerplate(CNAME)
CNAMERecordContent(const DNSName & content)255   CNAMERecordContent(const DNSName& content) : d_content(content){}
getTarget() const256   DNSName getTarget() const { return d_content; }
257 private:
258   DNSName d_content;
259 };
260 
261 class ALIASRecordContent : public DNSRecordContent
262 {
263 public:
264   includeboilerplate(ALIAS)
265 
266   DNSName d_content;
267 };
268 
269 
270 class DNAMERecordContent : public DNSRecordContent
271 {
272 public:
273   includeboilerplate(DNAME)
DNAMERecordContent(const DNSName & content)274   DNAMERecordContent(const DNSName& content) : d_content(content){}
getTarget() const275   const DNSName& getTarget() const { return d_content; }
276 private:
277   DNSName d_content;
278 };
279 
280 
281 class MBRecordContent : public DNSRecordContent
282 {
283 public:
284   includeboilerplate(MB)
285 
286 private:
287   DNSName d_madname;
288 };
289 
290 class MGRecordContent : public DNSRecordContent
291 {
292 public:
293   includeboilerplate(MG)
294 
295 private:
296   DNSName d_mgmname;
297 };
298 
299 class MRRecordContent : public DNSRecordContent
300 {
301 public:
302   includeboilerplate(MR)
303 
304 private:
305   DNSName d_alias;
306 };
307 
308 class MINFORecordContent : public DNSRecordContent
309 {
310 public:
311   includeboilerplate(MINFO)
312 
313 private:
314   DNSName d_rmailbx;
315   DNSName d_emailbx;
316 };
317 
318 class OPTRecordContent : public DNSRecordContent
319 {
320 public:
OPTRecordContent()321   OPTRecordContent(){}
322   includeboilerplate(OPT)
323   void getData(vector<pair<uint16_t, string> > &opts);
324 private:
325   string d_data;
326 };
327 
328 
329 class HINFORecordContent : public DNSRecordContent
330 {
331 public:
332   includeboilerplate(HINFO)
333 
334 private:
335   string d_cpu, d_host;
336 };
337 
338 class RPRecordContent : public DNSRecordContent
339 {
340 public:
341   includeboilerplate(RP)
342 
343 private:
344   DNSName d_mbox, d_info;
345 };
346 
347 
348 class DNSKEYRecordContent : public DNSRecordContent
349 {
350 public:
351   DNSKEYRecordContent();
352   includeboilerplate(DNSKEY)
353   uint16_t getTag() const;
354   uint16_t getTag();
355 
356   uint16_t d_flags{0};
357   uint8_t d_protocol{0};
358   uint8_t d_algorithm{0};
359   string d_key;
operator <(const DNSKEYRecordContent & rhs) const360   bool operator<(const DNSKEYRecordContent& rhs) const
361   {
362     return tie(d_flags, d_protocol, d_algorithm, d_key) <
363       tie(rhs.d_flags, rhs.d_protocol, rhs.d_algorithm, rhs.d_key);
364   }
365 };
366 
367 class CDNSKEYRecordContent : public DNSRecordContent
368 {
369 public:
370   CDNSKEYRecordContent();
371   includeboilerplate(CDNSKEY)
372   uint16_t getTag();
373 
374   uint16_t d_flags{0};
375   uint8_t d_protocol{0};
376   uint8_t d_algorithm{0};
377   string d_key;
378 };
379 
380 class DSRecordContent : public DNSRecordContent
381 {
382 public:
383   DSRecordContent();
operator ==(const DNSRecordContent & rhs) const384   bool operator==(const DNSRecordContent& rhs) const override
385   {
386     if(typeid(*this) != typeid(rhs))
387       return false;
388     auto rrhs =dynamic_cast<const decltype(this)>(&rhs);
389     return tie(d_tag, d_algorithm, d_digesttype, d_digest) ==
390       tie(rrhs->d_tag, rrhs->d_algorithm, rrhs->d_digesttype, rrhs->d_digest);
391   }
operator <(const DSRecordContent & rhs) const392   bool operator<(const DSRecordContent& rhs) const
393   {
394     return tie(d_tag, d_algorithm, d_digesttype, d_digest) <
395       tie(rhs.d_tag, rhs.d_algorithm, rhs.d_digesttype, rhs.d_digest);
396   }
397 
includeboilerplate(DS)398   includeboilerplate(DS)
399 
400   uint16_t d_tag{0};
401   uint8_t d_algorithm{0}, d_digesttype{0};
402   string d_digest;
403 };
404 
405 class CDSRecordContent : public DNSRecordContent
406 {
407 public:
408   CDSRecordContent();
includeboilerplate(CDS)409   includeboilerplate(CDS)
410 
411   uint16_t d_tag{0};
412   uint8_t d_algorithm{0}, d_digesttype{0};
413   string d_digest;
414 };
415 
416 class DLVRecordContent : public DNSRecordContent
417 {
418 public:
419   DLVRecordContent();
includeboilerplate(DLV)420   includeboilerplate(DLV)
421 
422   uint16_t d_tag{0};
423   uint8_t d_algorithm{0}, d_digesttype{0};
424   string d_digest;
425 };
426 
427 
428 class SSHFPRecordContent : public DNSRecordContent
429 {
430 public:
431   includeboilerplate(SSHFP)
432 
433 private:
434   uint8_t d_algorithm, d_fptype;
435   string d_fingerprint;
436 };
437 
438 class KEYRecordContent : public DNSRecordContent
439 {
440 public:
441   includeboilerplate(KEY)
442 
443 private:
444   uint16_t d_flags;
445   uint8_t d_protocol, d_algorithm;
446   string d_certificate;
447 };
448 
449 class AFSDBRecordContent : public DNSRecordContent
450 {
451 public:
452   includeboilerplate(AFSDB)
453 
454 private:
455   uint16_t d_subtype;
456   DNSName d_hostname;
457 };
458 
459 
460 class CERTRecordContent : public DNSRecordContent
461 {
462 public:
463   includeboilerplate(CERT)
464 
465 private:
466   uint16_t d_type, d_tag;
467   string d_certificate;
468   uint8_t d_algorithm;
469 };
470 
471 class TLSARecordContent : public DNSRecordContent
472 {
473 public:
474   includeboilerplate(TLSA)
475 
476 private:
477   uint8_t d_certusage, d_selector, d_matchtype;
478   string d_cert;
479 };
480 
481 class SMIMEARecordContent : public DNSRecordContent
482 {
483 public:
484   includeboilerplate(SMIMEA)
485 
486 private:
487   uint8_t d_certusage, d_selector, d_matchtype;
488   string d_cert;
489 };
490 
491 class OPENPGPKEYRecordContent : public DNSRecordContent
492 {
493 public:
494   includeboilerplate(OPENPGPKEY)
495 
496 private:
497   string d_keyring;
498 };
499 
500 class SVCBBaseRecordContent : public DNSRecordContent
501 {
502   public:
getTarget() const503     const DNSName& getTarget() const {return d_target;}
getPriority() const504     uint16_t getPriority() const {return d_priority;}
505     // Returns true if a value for |key| was set to 'auto'
506     bool autoHint(const SvcParam::SvcParamKey &key) const;
507     // Sets the |addresses| to the existing hints for |key|
508     void setHints(const SvcParam::SvcParamKey &key, const std::vector<ComboAddress> &addresses);
509     // Removes the parameter for |key| from d_params
510     void removeParam(const SvcParam::SvcParamKey &key);
511     // Whether or not there are any parameter
512     bool hasParams() const;
513     // Whether or not the param of |key| exists
514     bool hasParam(const SvcParam::SvcParamKey &key) const;
515     // Get the parameter with |key|, will throw out_of_range if param isn't there
516     SvcParam getParam(const SvcParam::SvcParamKey &key) const;
517 
518   protected:
519     uint16_t d_priority;
520     DNSName d_target;
521     set<SvcParam> d_params;
522 
523     // Get the iterator to parameter with |key|, return value can be d_params::end
524     set<SvcParam>::const_iterator getParamIt(const SvcParam::SvcParamKey &key) const;
525 };
526 
527 class SVCBRecordContent : public SVCBBaseRecordContent
528 {
529 public:
530   includeboilerplate(SVCB)
531 };
532 
533 class HTTPSRecordContent : public SVCBBaseRecordContent
534 {
535 public:
536   includeboilerplate(HTTPS)
537 };
538 
539 class RRSIGRecordContent : public DNSRecordContent
540 {
541 public:
542   RRSIGRecordContent();
includeboilerplate(RRSIG)543   includeboilerplate(RRSIG)
544 
545   uint16_t d_type{0};
546   uint16_t d_tag{0};
547   DNSName d_signer;
548   string d_signature;
549   uint32_t d_originalttl{0}, d_sigexpire{0}, d_siginception{0};
550   uint8_t d_algorithm{0}, d_labels{0};
551 };
552 
553 //namespace {
554   struct soatimes
555   {
556     uint32_t serial;
557     uint32_t refresh;
558     uint32_t retry;
559     uint32_t expire;
560     uint32_t minimum;
561   };
562 //}
563 
564 class RKEYRecordContent : public DNSRecordContent
565 {
566 public:
567   RKEYRecordContent();
includeboilerplate(RKEY)568   includeboilerplate(RKEY)
569   uint16_t d_flags{0};
570   uint8_t d_protocol{0}, d_algorithm{0};
571   string d_key;
572 };
573 
574 class SOARecordContent : public DNSRecordContent
575 {
576 public:
577   includeboilerplate(SOA)
578   SOARecordContent(DNSName  mname, DNSName  rname, const struct soatimes& st);
579 
580   DNSName d_mname;
581   DNSName d_rname;
582   struct soatimes d_st;
583 };
584 
585 class NSECBitmap
586 {
587 public:
NSECBitmap()588   NSECBitmap(): d_bitset(nullptr)
589   {
590   }
NSECBitmap(const NSECBitmap & rhs)591   NSECBitmap(const NSECBitmap& rhs): d_set(rhs.d_set)
592   {
593     if (rhs.d_bitset) {
594       d_bitset = std::unique_ptr<std::bitset<nbTypes>>(new std::bitset<nbTypes>(*(rhs.d_bitset)));
595     }
596   }
operator =(const NSECBitmap & rhs)597   NSECBitmap& operator=(const NSECBitmap& rhs)
598   {
599     d_set = rhs.d_set;
600 
601     if (rhs.d_bitset) {
602       d_bitset = std::unique_ptr<std::bitset<nbTypes>>(new std::bitset<nbTypes>(*(rhs.d_bitset)));
603     }
604 
605     return *this;
606   }
NSECBitmap(NSECBitmap && rhs)607   NSECBitmap(NSECBitmap&& rhs): d_bitset(std::move(rhs.d_bitset)), d_set(std::move(rhs.d_set))
608   {
609   }
isSet(uint16_t type) const610   bool isSet(uint16_t type) const
611   {
612     if (d_bitset) {
613       return d_bitset->test(type);
614     }
615     return d_set.count(type);
616   }
set(uint16_t type)617   void set(uint16_t type)
618   {
619     if (!d_bitset) {
620       if (d_set.size() >= 200) {
621         migrateToBitSet();
622       }
623     }
624     if (d_bitset) {
625       d_bitset->set(type);
626     }
627     else {
628       d_set.insert(type);
629     }
630   }
count() const631   size_t count() const
632   {
633     if (d_bitset) {
634       return d_bitset->count();
635     }
636     else {
637       return d_set.size();
638     }
639   }
640 
641   void fromPacket(PacketReader& pr);
642   void toPacket(DNSPacketWriter& pw);
643   std::string getZoneRepresentation() const;
644 
645   static constexpr size_t const nbTypes = 65536;
646 
647 private:
648 
migrateToBitSet()649   void migrateToBitSet()
650   {
651     d_bitset = std::unique_ptr<std::bitset<nbTypes>>(new std::bitset<nbTypes>());
652     for (const auto& type : d_set) {
653       d_bitset->set(type);
654     }
655     d_set.clear();
656   }
657   /* using a dynamic set is very efficient for a small number of
658      types covered (~200), but uses a lot of memory (up to 3MB)
659      when there are a lot of them.
660      So we start with the set, but allocate and switch to a bitset
661      if the number of covered types increases a lot */
662   std::unique_ptr<std::bitset<nbTypes>> d_bitset;
663   std::set<uint16_t> d_set;
664 };
665 
666 class NSECRecordContent : public DNSRecordContent
667 {
668 public:
669   static void report(void);
NSECRecordContent()670   NSECRecordContent()
671   {}
672   NSECRecordContent(const string& content, const DNSName& zone=DNSName());
673 
674   static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
675   static std::shared_ptr<DNSRecordContent> make(const string& content);
676   string getZoneRepresentation(bool noDot=false) const override;
677   void toPacket(DNSPacketWriter& pw) override;
getType() const678   uint16_t getType() const override
679   {
680     return QType::NSEC;
681   }
isSet(uint16_t type) const682   bool isSet(uint16_t type) const
683   {
684     return d_bitmap.isSet(type);
685   }
set(uint16_t type)686   void set(uint16_t type)
687   {
688     d_bitmap.set(type);
689   }
set(const NSECBitmap & bitmap)690   void set(const NSECBitmap& bitmap)
691   {
692     d_bitmap = bitmap;
693   }
numberOfTypesSet() const694   size_t numberOfTypesSet() const
695   {
696     return d_bitmap.count();
697   }
698 
699   DNSName d_next;
700 private:
701   NSECBitmap d_bitmap;
702 };
703 
704 class NSEC3RecordContent : public DNSRecordContent
705 {
706 public:
707   static void report(void);
NSEC3RecordContent()708   NSEC3RecordContent()
709   {}
710   NSEC3RecordContent(const string& content, const DNSName& zone=DNSName());
711 
712   static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
713   static std::shared_ptr<DNSRecordContent> make(const string& content);
714   string getZoneRepresentation(bool noDot=false) const override;
715   void toPacket(DNSPacketWriter& pw) override;
716 
717   uint8_t d_algorithm{0}, d_flags{0};
718   uint16_t d_iterations{0};
719   string d_salt;
720   string d_nexthash;
721 
getType() const722   uint16_t getType() const override
723   {
724     return QType::NSEC3;
725   }
isSet(uint16_t type) const726   bool isSet(uint16_t type) const
727   {
728     return d_bitmap.isSet(type);
729   }
set(uint16_t type)730   void set(uint16_t type)
731   {
732     d_bitmap.set(type);
733   }
set(const NSECBitmap & bitmap)734   void set(const NSECBitmap& bitmap)
735   {
736     d_bitmap = bitmap;
737   }
numberOfTypesSet() const738   size_t numberOfTypesSet() const
739   {
740     return d_bitmap.count();
741   }
isOptOut() const742   bool isOptOut() const
743   {
744     return d_flags & 1;
745   }
746 
747 private:
748   NSECBitmap d_bitmap;
749 };
750 
751 class CSYNCRecordContent : public DNSRecordContent
752 {
753 public:
754   static void report(void);
CSYNCRecordContent()755   CSYNCRecordContent()
756   {}
757   CSYNCRecordContent(const string& content, const DNSName& zone=DNSName());
758 
759   static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
760   static std::shared_ptr<DNSRecordContent> make(const string& content);
761   string getZoneRepresentation(bool noDot=false) const override;
762   void toPacket(DNSPacketWriter& pw) override;
763 
getType() const764   uint16_t getType() const override
765   {
766     return QType::CSYNC;
767   }
768 
set(uint16_t type)769   void set(uint16_t type)
770   {
771     d_bitmap.set(type);
772   }
773 
774 private:
775   uint32_t d_serial{0};
776   uint16_t d_flags{0};
777   NSECBitmap d_bitmap;
778 };
779 
780 class NSEC3PARAMRecordContent : public DNSRecordContent
781 {
782 public:
783   static void report(void);
NSEC3PARAMRecordContent()784   NSEC3PARAMRecordContent()
785   {}
786   NSEC3PARAMRecordContent(const string& content, const DNSName& zone=DNSName());
787 
788   static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
789   static std::shared_ptr<DNSRecordContent> make(const string& content);
790   string getZoneRepresentation(bool noDot=false) const override;
791   void toPacket(DNSPacketWriter& pw) override;
792 
getType() const793   uint16_t getType() const override
794   {
795     return QType::NSEC3PARAM;
796   }
797 
798 
799   uint8_t d_algorithm{0}, d_flags{0};
800   uint16_t d_iterations{0};
801   string d_salt;
802 };
803 
804 
805 class LOCRecordContent : public DNSRecordContent
806 {
807 public:
808   static void report(void);
LOCRecordContent()809   LOCRecordContent()
810   {}
811   LOCRecordContent(const string& content, const string& zone="");
812 
813   static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
814   static std::shared_ptr<DNSRecordContent> make(const string& content);
815   string getZoneRepresentation(bool noDot=false) const override;
816   void toPacket(DNSPacketWriter& pw) override;
817 
818   uint8_t d_version{0}, d_size{0}, d_horizpre{0}, d_vertpre{0};
819   uint32_t d_latitude{0}, d_longitude{0}, d_altitude{0};
getType() const820   uint16_t getType() const override
821   {
822     return QType::LOC;
823   }
824 
825 private:
826 };
827 
828 
829 class NIDRecordContent : public DNSRecordContent
830 {
831 public:
832   includeboilerplate(NID);
833 
834 private:
835   uint16_t d_preference;
836   NodeOrLocatorID d_node_id;
837 };
838 
839 class L32RecordContent : public DNSRecordContent
840 {
841 public:
842   includeboilerplate(L32);
843 
844 private:
845   uint16_t d_preference;
846   uint32_t d_locator;
847 };
848 
849 class L64RecordContent : public DNSRecordContent
850 {
851 public:
852   includeboilerplate(L64);
853 
854 private:
855   uint16_t d_preference;
856   NodeOrLocatorID d_locator;
857 };
858 
859 class LPRecordContent : public DNSRecordContent
860 {
861 public:
862   includeboilerplate(LP);
863 
864 private:
865   uint16_t d_preference;
866   DNSName d_fqdn;
867 };
868 
869 class EUI48RecordContent : public DNSRecordContent
870 {
871 public:
EUI48RecordContent()872   EUI48RecordContent() {};
873   static void report(void);
874   static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
875   static std::shared_ptr<DNSRecordContent> make(const string& zone); // FIXME400: DNSName& zone?
876   string getZoneRepresentation(bool noDot=false) const override;
877   void toPacket(DNSPacketWriter& pw) override;
getType() const878   uint16_t getType() const override { return QType::EUI48; }
879 private:
880  // storage for the bytes
881  uint8_t d_eui48[6];
882 };
883 
884 class EUI64RecordContent : public DNSRecordContent
885 {
886 public:
EUI64RecordContent()887   EUI64RecordContent() {};
888   static void report(void);
889   static std::shared_ptr<DNSRecordContent> make(const DNSRecord &dr, PacketReader& pr);
890   static std::shared_ptr<DNSRecordContent> make(const string& zone); // FIXME400: DNSName& zone?
891   string getZoneRepresentation(bool noDot=false) const override;
892   void toPacket(DNSPacketWriter& pw) override;
getType() const893   uint16_t getType() const override { return QType::EUI64; }
894 private:
895  // storage for the bytes
896  uint8_t d_eui64[8];
897 };
898 
899 #define APL_FAMILY_IPV4 1
900 #define APL_FAMILY_IPV6 2
901 typedef struct s_APLRDataElement {
902   uint16_t d_family;
903   uint8_t d_prefix;
904   bool d_n : 1;
905   unsigned int d_afdlength : 7;
906   union u_d_ip {
907       uint8_t d_ip4[4];
908       uint8_t d_ip6[16];
909   } d_ip;
910 } APLRDataElement;
911 class APLRecordContent : public DNSRecordContent
912 {
913 public:
APLRecordContent()914   APLRecordContent() {};
915   includeboilerplate(APL)
916 private:
917   std::vector<APLRDataElement> aplrdata;
918   APLRDataElement parseAPLElement(const string &element);
919 };
920 
921 
922 class TKEYRecordContent : public DNSRecordContent
923 {
924 public:
925   TKEYRecordContent();
includeboilerplate(TKEY)926   includeboilerplate(TKEY)
927 
928   // storage for the bytes
929   uint16_t d_othersize{0};
930   uint16_t d_mode{0};
931   uint32_t d_inception{0};
932   uint32_t d_expiration{0};
933 
934   DNSName d_algo;
935   string d_key;
936   string d_other;
937 
938   uint16_t d_error{0};
939   uint16_t d_keysize{0};
940 private:
941 };
942 
943 class URIRecordContent : public DNSRecordContent {
944   public:
945     includeboilerplate(URI)
946   private:
947     uint16_t d_priority, d_weight;
948     string d_target;
949 };
950 
951 class CAARecordContent : public DNSRecordContent {
952   public:
953     includeboilerplate(CAA)
954   private:
955     uint8_t d_flags;
956     string d_tag, d_value;
957 };
958 
959 #define boilerplate(RNAME)                                                                         \
960 std::shared_ptr<RNAME##RecordContent::DNSRecordContent> RNAME##RecordContent::make(const DNSRecord& dr, PacketReader& pr) \
961 {                                                                                                  \
962   return std::make_shared<RNAME##RecordContent>(dr, pr);                                           \
963 }                                                                                                  \
964                                                                                                    \
965 RNAME##RecordContent::RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr)                  \
966 {                                                                                                  \
967   doRecordCheck(dr);                                                                               \
968   xfrPacket(pr);                                                                                   \
969 }                                                                                                  \
970                                                                                                    \
971 std::shared_ptr<RNAME##RecordContent::DNSRecordContent> RNAME##RecordContent::make(const string& zonedata)         \
972 {                                                                                                  \
973   return std::make_shared<RNAME##RecordContent>(zonedata);                                         \
974 }                                                                                                  \
975                                                                                                    \
976 void RNAME##RecordContent::toPacket(DNSPacketWriter& pw)                                           \
977 {                                                                                                  \
978   this->xfrPacket(pw);                                                                             \
979 }                                                                                                  \
980                                                                                                    \
981 void RNAME##RecordContent::report(void)                                                            \
982 {                                                                                                  \
983   regist(1, QType::RNAME, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME);              \
984   regist(254, QType::RNAME, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME);            \
985 }                                                                                                  \
986 void RNAME##RecordContent::unreport(void)                                                          \
987 {                                                                                                  \
988   unregist(1, QType::RNAME);                                                                              \
989   unregist(254, QType::RNAME);                                                                            \
990 }                                                                                                  \
991                                                                                                    \
992 RNAME##RecordContent::RNAME##RecordContent(const string& zoneData)                                 \
993 {                                                                                                  \
994   try {                                                                                            \
995     RecordTextReader rtr(zoneData);                                                                \
996     xfrPacket(rtr);                                                                                \
997   }                                                                                                \
998   catch(RecordTextException& rte) {                                                                \
999     throw MOADNSException("Parsing record content (try 'pdnsutil check-zone'): "+string(rte.what()));  \
1000   }                                                                                                \
1001 }                                                                                                  \
1002                                                                                                    \
1003 string RNAME##RecordContent::getZoneRepresentation(bool noDot) const                               \
1004 {                                                                                                  \
1005   string ret;                                                                                      \
1006   RecordTextWriter rtw(ret, noDot);                                                                       \
1007   const_cast<RNAME##RecordContent*>(this)->xfrPacket(rtw);                                         \
1008   return ret;                                                                                      \
1009 }
1010 
1011 
1012 #define boilerplate_conv(RNAME, CONV)                             \
1013 boilerplate(RNAME)                                                \
1014 template<class Convertor>                                         \
1015 void RNAME##RecordContent::xfrPacket(Convertor& conv, bool noDot) \
1016 {                                                                 \
1017   CONV;                                                           \
1018   if (conv.eof() == false) throw MOADNSException("When parsing " #RNAME " trailing data was not parsed: '" + conv.getRemaining() + "'"); \
1019 }                                                                 \
1020 
1021 struct EDNSOpts
1022 {
1023   enum zFlags { DNSSECOK=32768 };
1024   vector<pair<uint16_t, string> > d_options;
1025   uint16_t d_packetsize{0};
1026   uint16_t d_extFlags{0};
1027   uint8_t d_extRCode, d_version;
1028 };
1029 //! Convenience function that fills out EDNS0 options, and returns true if there are any
1030 
1031 class MOADNSParser;
1032 bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo);
1033 DNSRecord makeOpt(const uint16_t udpsize, const uint16_t extRCode, const uint16_t extFlags);
1034 void reportBasicTypes();
1035 void reportOtherTypes();
1036 void reportAllTypes();
1037 ComboAddress getAddr(const DNSRecord& dr, uint16_t defport=0);
1038 void checkHostnameCorrectness(const DNSResourceRecord& rr);
1039