23
[ghsmtp.git] / DNS-rrs.hpp
blobe6e2a628f52264b63619e6c1f2433b252a1531bc
1 #ifndef DNS_RRS_DOT_HPP
2 #define DNS_RRS_DOT_HPP
4 #include <cstddef>
5 #include <cstring>
6 #include <optional>
7 #include <span>
8 #include <string>
9 #include <variant>
10 #include <vector>
12 #include <netinet/in.h>
14 #include "iobuffer.hpp"
16 namespace DNS {
18 enum class RR_type : uint16_t {
19 // RFC 1035 section 3.2.2 “TYPE values”
20 NONE,
22 NS,
23 MD,
24 MF,
25 CNAME,
26 SOA,
27 MB,
28 MG,
29 MR,
30 RR_NULL,
31 WKS,
32 PTR,
33 HINFO,
34 MINFO,
35 MX,
36 TXT,
37 RP, // RFC 1183 Responsible Person
38 AFSDB, // RFC 1183 AFS database record
40 // RFC 2535
41 SIG = 24, // RFC 2535 Signature
42 KEY = 25, // RFC 2535 and RFC 2930 Key record
44 // RFC 3596 section 2.1 “AAAA record type”
45 AAAA = 28,
47 // RFC 2782 Service locator
48 SRV = 33,
50 // RFC 4398 Certificate record
51 CERT = 37,
53 // RFC 6891 EDNS(0) OPT pseudo-RR
54 OPT = 41,
56 // RFC 4255 SSH Public Key Fingerprint
57 SSHFP = 44,
59 // RFC 4034
60 RRSIG = 46, // DNSSEC signature
61 NSEC = 47, // Next Secure record
62 DNSKEY = 48, // DNS Key record
64 // RFC 6698 section 7.1 “TLSA RRtype”
65 TLSA = 52,
68 constexpr char const* RR_type_c_str(RR_type type)
70 switch (type) { // clang-format off
71 case RR_type::NONE: return "NONE";
72 case RR_type::A: return "A";
73 case RR_type::NS: return "NS";
74 case RR_type::MD: return "MD";
75 case RR_type::MF: return "MF";
76 case RR_type::CNAME: return "CNAME";
77 case RR_type::SOA: return "SOA";
78 case RR_type::MB: return "MB";
79 case RR_type::MG: return "MG";
80 case RR_type::MR: return "MR";
81 case RR_type::RR_NULL:return "RR_NULL";
82 case RR_type::WKS: return "WKS";
83 case RR_type::PTR: return "PTR";
84 case RR_type::HINFO: return "HINFO";
85 case RR_type::MINFO: return "MINFO";
86 case RR_type::MX: return "MX";
87 case RR_type::TXT: return "TXT";
88 case RR_type::RP: return "RP";
89 case RR_type::AFSDB: return "AFSDB";
90 case RR_type::SIG: return "SIG";
91 case RR_type::KEY: return "KEY";
92 case RR_type::AAAA: return "AAAA";
93 case RR_type::SRV: return "SRV";
94 case RR_type::CERT: return "CERT";
95 case RR_type::OPT: return "OPT";
96 case RR_type::SSHFP: return "SSHFP";
97 case RR_type::RRSIG: return "RRSIG";
98 case RR_type::NSEC: return "NSEC";
99 case RR_type::DNSKEY: return "DNSKEY";
100 case RR_type::TLSA: return "TLSA";
101 } // clang-format on
102 return "*** unknown RR_type ***";
105 constexpr char const* RR_type_c_str(uint16_t rcode)
107 return RR_type_c_str(static_cast<RR_type>(rcode));
110 constexpr char const* rcode_c_str(uint16_t rcode)
112 // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
113 switch (rcode) { // clang-format off
114 case 0: return "no error"; // [RFC1035]
115 case 1: return "format error"; // [RFC1035]
116 case 2: return "server failure"; // [RFC1035]
117 case 3: return "non-existent domain"; // [RFC1035]
118 case 4: return "not implemented"; // [RFC1035]
119 case 5: return "query Refused"; // [RFC1035]
120 case 6: return "name exists when it should not"; // [RFC2136][RFC6672]
121 case 7: return "RR set exists when it should not"; // [RFC2136]
122 case 8: return "RR set that should exist does not"; // [RFC2136]
123 case 9: return "server not authoritative for zone or not authorized"; // [RFC2136 & RFC2845]
124 case 10: return "name not contained in zone"; // [RFC2136]
125 case 11: return "unassigned-11";
126 case 12: return "unassigned-12";
127 case 13: return "unassigned-13";
128 case 14: return "unassigned-14";
129 case 15: return "unassigned-15";
130 case 16: return "bad OPT version or TSIG signature failure"; // [RFC6891 & RFC2845]
131 case 17: return "key not recognized"; // [RFC2845]
132 case 18: return "signature out of time window"; // [RFC2845]
133 case 19: return "bad TKEY mode"; // [RFC2930]
134 case 20: return "duplicate key name"; // [RFC2930]
135 case 21: return "algorithm not supported"; // [RFC2930]
136 case 22: return "bad truncation"; // [RFC4635]
137 case 23: return "bad/missing server cookie"; // [RFC7873]
138 } // clang-format on
139 if ((24 <= rcode) && (rcode <= 3840)) {
140 return "unassigned-24-3840";
142 if ((3841 <= rcode) && (rcode <= 4095)) {
143 return "reserved for private use"; // [RFC6895]
145 if ((4096 <= rcode) && (rcode <= 65534)) {
146 return "unassigned-4096-65534";
148 if (rcode == 65535) {
149 return "reserved-65535"; // [RFC6895]
151 return "*** rcode out of range ***";
154 class RR_A {
155 public:
156 RR_A(uint8_t const* rd, size_t sz);
158 std::optional<std::string> as_str() const { return std::string{str_}; }
160 sockaddr_in const& addr() const { return addr_; }
161 char const* c_str() const { return str_; }
162 constexpr static RR_type rr_type() { return RR_type::A; }
164 bool operator==(RR_A const& rhs) const { return strcmp(str_, rhs.str_) == 0; }
165 bool operator<(RR_A const& rhs) const { return strcmp(str_, rhs.str_) < 0; }
167 private:
168 sockaddr_in addr_;
169 char str_[INET_ADDRSTRLEN];
172 class RR_CNAME {
173 public:
174 explicit RR_CNAME(std::string cname)
175 : cname_(cname)
179 std::optional<std::string> as_str() const { return str(); }
181 std::string const& str() const { return cname_; }
182 char const* c_str() const { return str().c_str(); }
183 constexpr static RR_type rr_type() { return RR_type::CNAME; }
185 bool operator==(RR_CNAME const& rhs) const { return str() == rhs.str(); }
186 bool operator<(RR_CNAME const& rhs) const { return str() < rhs.str(); }
188 private:
189 std::string cname_;
192 // RFC 2181 section 10.2 PTR records
193 class RR_PTR {
194 public:
195 explicit RR_PTR(std::string ptrdname)
196 : ptrdname_(ptrdname)
200 std::optional<std::string> as_str() const { return str(); }
202 std::string const& str() const { return ptrdname_; }
203 char const* c_str() const { return str().c_str(); }
204 constexpr static RR_type rr_type() { return RR_type::PTR; }
206 bool operator==(RR_PTR const& rhs) const { return str() == rhs.str(); }
207 bool operator<(RR_PTR const& rhs) const { return str() < rhs.str(); }
209 private:
210 std::string ptrdname_;
213 class RR_MX {
214 public:
215 RR_MX(std::string exchange, uint16_t preference)
216 : exchange_(exchange)
217 , preference_(preference)
221 std::optional<std::string> as_str() const { return exchange(); }
223 std::string const& exchange() const { return exchange_; }
224 uint16_t preference() const { return preference_; }
226 constexpr static RR_type rr_type() { return RR_type::MX; }
228 bool operator==(RR_MX const& rhs) const
230 return (preference() == rhs.preference()) && (exchange() == rhs.exchange());
232 bool operator<(RR_MX const& rhs) const
234 if (preference() == rhs.preference())
235 return exchange() < rhs.exchange();
236 return preference() < rhs.preference();
239 private:
240 std::string exchange_;
241 uint16_t preference_;
244 class RR_TXT {
245 public:
246 explicit RR_TXT(std::string txt_data)
247 : txt_data_(txt_data)
251 std::optional<std::string> as_str() const { return str(); }
253 char const* c_str() const { return str().c_str(); }
254 std::string const& str() const { return txt_data_; }
255 constexpr static RR_type rr_type() { return RR_type::TXT; }
257 bool operator==(RR_TXT const& rhs) const { return str() == rhs.str(); }
258 bool operator<(RR_TXT const& rhs) const { return str() < rhs.str(); }
260 private:
261 std::string txt_data_;
264 class RR_AAAA {
265 public:
266 RR_AAAA(uint8_t const* rd, size_t sz);
268 std::optional<std::string> as_str() const { return std::string{c_str()}; }
270 sockaddr_in6 const& addr() const { return addr_; }
271 char const* c_str() const { return str_; }
272 constexpr static RR_type rr_type() { return RR_type::AAAA; }
274 bool operator==(RR_AAAA const& rhs) const
276 return strcmp(c_str(), rhs.c_str()) == 0;
278 bool operator<(RR_AAAA const& rhs) const
280 return strcmp(c_str(), rhs.c_str()) < 0;
283 private:
284 sockaddr_in6 addr_;
285 char str_[INET6_ADDRSTRLEN];
288 class RR_TLSA {
289 public:
290 using octet = unsigned char;
291 using container_t = iobuffer<octet>;
293 RR_TLSA(uint8_t cert_usage,
294 uint8_t selector,
295 uint8_t matching_type,
296 std::span<octet const> data);
297 unsigned cert_usage() const { return cert_usage_; }
298 unsigned selector() const { return selector_; }
299 unsigned matching_type() const { return matching_type_; }
301 // container_t const& assoc_data() const { return assoc_data_; }
303 // doesn't have a string representation
304 std::optional<std::string> as_str() const { return {}; }
306 constexpr static RR_type rr_type() { return RR_type::TLSA; }
308 std::span<octet const> assoc_data() const
310 return {assoc_data_.data(), assoc_data_.size()};
313 bool operator==(RR_TLSA const& rhs) const
315 return (cert_usage() == rhs.cert_usage()) &&
316 (selector() == rhs.selector()) &&
317 (matching_type() == rhs.matching_type()) &&
318 (assoc_data_ == rhs.assoc_data_);
320 bool operator<(RR_TLSA const& rhs) const
322 if (!(*this == rhs))
323 return assoc_data_ < rhs.assoc_data_;
324 return false;
327 private:
328 container_t assoc_data_;
329 uint8_t cert_usage_;
330 uint8_t selector_;
331 uint8_t matching_type_;
334 using RR =
335 std::variant<RR_A, RR_CNAME, RR_PTR, RR_MX, RR_TXT, RR_AAAA, RR_TLSA>;
337 using RR_collection = std::vector<RR>;
339 } // namespace DNS
341 #endif // DNS_RRS_DOT_HPP