don't try to write data after error
[ghsmtp.git] / DNS-rrs.hpp
blob64c96cbb58d16f191af9d8eb3c7aa62287461d02
1 #ifndef DNS_RRS_DOT_HPP
2 #define DNS_RRS_DOT_HPP
4 #include <cstddef>
5 #include <cstring>
6 #include <optional>
7 #include <string>
8 #include <variant>
9 #include <vector>
11 #include <netinet/in.h>
13 #include "iobuffer.hpp"
15 namespace DNS {
17 enum class RR_type : uint16_t {
18 // RFC 1035 section 3.2.2 “TYPE values”
19 NONE,
21 NS,
22 MD,
23 MF,
24 CNAME,
25 SOA,
26 MB,
27 MG,
28 MR,
29 RR_NULL,
30 WKS,
31 PTR,
32 HINFO,
33 MINFO,
34 MX,
35 TXT,
36 RP, // RFC 1183 Responsible Person
37 AFSDB, // RFC 1183 AFS database record
39 // RFC 2535
40 SIG = 24, // RFC 2535 Signature
41 KEY = 25, // RFC 2535 and RFC 2930 Key record
43 // RFC 3596 section 2.1 “AAAA record type”
44 AAAA = 28,
46 // RFC 2782 Service locator
47 SRV = 33,
49 // RFC 4398 Certificate record
50 CERT = 37,
52 // RFC 6891 EDNS(0) OPT pseudo-RR
53 OPT = 41,
55 // RFC 4255 SSH Public Key Fingerprint
56 SSHFP = 44,
58 // RFC 4034
59 RRSIG = 46, // DNSSEC signature
60 NSEC = 47, // Next Secure record
61 DNSKEY = 48, // DNS Key record
63 // RFC 6698 section 7.1 “TLSA RRtype”
64 TLSA = 52,
67 constexpr char const* RR_type_c_str(RR_type type)
69 switch (type) { // clang-format off
70 case RR_type::NONE: return "NONE";
71 case RR_type::A: return "A";
72 case RR_type::NS: return "NS";
73 case RR_type::MD: return "MD";
74 case RR_type::MF: return "MF";
75 case RR_type::CNAME: return "CNAME";
76 case RR_type::SOA: return "SOA";
77 case RR_type::MB: return "MB";
78 case RR_type::MG: return "MG";
79 case RR_type::MR: return "MR";
80 case RR_type::RR_NULL:return "RR_NULL";
81 case RR_type::WKS: return "WKS";
82 case RR_type::PTR: return "PTR";
83 case RR_type::HINFO: return "HINFO";
84 case RR_type::MINFO: return "MINFO";
85 case RR_type::MX: return "MX";
86 case RR_type::TXT: return "TXT";
87 case RR_type::RP: return "RP";
88 case RR_type::AFSDB: return "AFSDB";
89 case RR_type::SIG: return "SIG";
90 case RR_type::KEY: return "KEY";
91 case RR_type::AAAA: return "AAAA";
92 case RR_type::SRV: return "SRV";
93 case RR_type::CERT: return "CERT";
94 case RR_type::OPT: return "OPT";
95 case RR_type::SSHFP: return "SSHFP";
96 case RR_type::RRSIG: return "RRSIG";
97 case RR_type::NSEC: return "NSEC";
98 case RR_type::DNSKEY: return "DNSKEY";
99 case RR_type::TLSA: return "TLSA";
100 } // clang-format on
101 return "*** unknown RR_type ***";
104 constexpr char const* RR_type_c_str(uint16_t rcode)
106 return RR_type_c_str(static_cast<RR_type>(rcode));
109 constexpr char const* rcode_c_str(uint16_t rcode)
111 // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
112 switch (rcode) { // clang-format off
113 case 0: return "no error"; // [RFC1035]
114 case 1: return "format error"; // [RFC1035]
115 case 2: return "server failure"; // [RFC1035]
116 case 3: return "non-existent domain"; // [RFC1035]
117 case 4: return "not implemented"; // [RFC1035]
118 case 5: return "query Refused"; // [RFC1035]
119 case 6: return "name exists when it should not"; // [RFC2136][RFC6672]
120 case 7: return "RR set exists when it should not"; // [RFC2136]
121 case 8: return "RR set that should exist does not"; // [RFC2136]
122 case 9: return "server not authoritative for zone or not authorized"; // [RFC2136 & RFC2845]
123 case 10: return "name not contained in zone"; // [RFC2136]
124 case 11: return "unassigned-11";
125 case 12: return "unassigned-12";
126 case 13: return "unassigned-13";
127 case 14: return "unassigned-14";
128 case 15: return "unassigned-15";
129 case 16: return "bad OPT version or TSIG signature failure"; // [RFC6891 & RFC2845]
130 case 17: return "key not recognized"; // [RFC2845]
131 case 18: return "signature out of time window"; // [RFC2845]
132 case 19: return "bad TKEY mode"; // [RFC2930]
133 case 20: return "duplicate key name"; // [RFC2930]
134 case 21: return "algorithm not supported"; // [RFC2930]
135 case 22: return "bad truncation"; // [RFC4635]
136 case 23: return "bad/missing server cookie"; // [RFC7873]
137 } // clang-format on
138 if ((24 <= rcode) && (rcode <= 3840)) {
139 return "unassigned-24-3840";
141 if ((3841 <= rcode) && (rcode <= 4095)) {
142 return "reserved for private use"; // [RFC6895]
144 if ((4096 <= rcode) && (rcode <= 65534)) {
145 return "unassigned-4096-65534";
147 if (rcode == 65535) {
148 return "reserved-65535"; // [RFC6895]
150 return "*** rcode out of range ***";
153 class RR_A {
154 public:
155 RR_A(uint8_t const* rd, size_t sz);
157 std::optional<std::string> as_str() const { return std::string{str_}; }
159 sockaddr_in const& addr() const { return addr_; }
160 char const* c_str() const { return str_; }
161 static RR_type rr_type() { return RR_type::A; }
163 bool operator==(RR_A const& rhs) const { return strcmp(str_, rhs.str_) == 0; }
164 bool operator<(RR_A const& rhs) const { return strcmp(str_, rhs.str_) < 0; }
166 private:
167 sockaddr_in addr_;
168 char str_[INET_ADDRSTRLEN];
171 class RR_CNAME {
172 public:
173 explicit RR_CNAME(std::string cname)
174 : cname_(cname)
178 std::optional<std::string> as_str() const { return str(); }
180 std::string const& str() const { return cname_; }
181 char const* c_str() const { return str().c_str(); }
182 static RR_type rr_type() { return RR_type::CNAME; }
184 bool operator==(RR_CNAME const& rhs) const { return str() == rhs.str(); }
185 bool operator<(RR_CNAME const& rhs) const { return str() < rhs.str(); }
187 private:
188 std::string cname_;
191 // RFC 2181 section 10.2 PTR records
192 class RR_PTR {
193 public:
194 explicit RR_PTR(std::string ptrdname)
195 : ptrdname_(ptrdname)
199 std::optional<std::string> as_str() const { return str(); }
201 std::string const& str() const { return ptrdname_; }
202 char const* c_str() const { return str().c_str(); }
203 constexpr static RR_type rr_type() { return RR_type::PTR; }
205 bool operator==(RR_PTR const& rhs) const { return str() == rhs.str(); }
206 bool operator<(RR_PTR const& rhs) const { return str() < rhs.str(); }
208 private:
209 std::string ptrdname_;
212 class RR_MX {
213 public:
214 RR_MX(std::string exchange, uint16_t preference)
215 : exchange_(exchange)
216 , preference_(preference)
220 std::optional<std::string> as_str() const { return exchange(); }
222 std::string const& exchange() const { return exchange_; }
223 uint16_t preference() const { return preference_; }
225 static RR_type rr_type() { return RR_type::MX; }
227 bool operator==(RR_MX const& rhs) const
229 return (preference() == rhs.preference()) && (exchange() == rhs.exchange());
231 bool operator<(RR_MX const& rhs) const
233 if (preference() < rhs.preference())
234 return true;
235 if (preference() == rhs.preference())
236 return exchange() < rhs.exchange();
237 return false;
240 private:
241 std::string exchange_;
242 uint16_t preference_;
245 class RR_TXT {
246 public:
247 explicit RR_TXT(std::string txt_data)
248 : txt_data_(txt_data)
252 std::optional<std::string> as_str() const { return str(); }
254 char const* c_str() const { return str().c_str(); }
255 std::string const& str() const { return txt_data_; }
256 static RR_type rr_type() { return RR_type::TXT; }
258 bool operator==(RR_TXT const& rhs) const { return str() == rhs.str(); }
259 bool operator<(RR_TXT const& rhs) const { return str() < rhs.str(); }
261 private:
262 std::string txt_data_;
265 class RR_AAAA {
266 public:
267 RR_AAAA(uint8_t const* rd, size_t sz);
269 std::optional<std::string> as_str() const { return std::string{c_str()}; }
271 sockaddr_in6 const& addr() const { return addr_; }
272 char const* c_str() const { return str_; }
273 static RR_type rr_type() { return RR_type::AAAA; }
275 bool operator==(RR_AAAA const& rhs) const
277 return strcmp(c_str(), rhs.c_str()) == 0;
279 bool operator<(RR_AAAA const& rhs) const
281 return strcmp(c_str(), rhs.c_str()) < 0;
284 private:
285 sockaddr_in6 addr_;
286 char str_[INET6_ADDRSTRLEN];
289 class RR_TLSA {
290 public:
291 using octet = unsigned char;
293 using container_t = iobuffer<octet>;
295 RR_TLSA(uint8_t cert_usage,
296 uint8_t selector,
297 uint8_t matching_type,
298 uint8_t const* assoc_data,
299 size_t assoc_data_sz);
300 unsigned cert_usage() const { return cert_usage_; }
301 unsigned selector() const { return selector_; }
302 unsigned matching_type() const { return matching_type_; }
304 container_t const& assoc_data() const { return assoc_data_; }
306 // doesn't have a string representation
307 std::optional<std::string> as_str() const { return {}; }
309 static RR_type rr_type() { return RR_type::TLSA; }
311 bool operator==(RR_TLSA const& rhs) const
313 return (cert_usage() == rhs.cert_usage()) && (selector() == rhs.selector())
314 && (matching_type() == rhs.matching_type())
315 && (assoc_data() == rhs.assoc_data());
317 bool operator<(RR_TLSA const& rhs) const
319 return assoc_data() < rhs.assoc_data();
322 private:
323 container_t assoc_data_;
324 uint8_t cert_usage_;
325 uint8_t selector_;
326 uint8_t matching_type_;
329 using RR
330 = std::variant<RR_A, RR_CNAME, RR_PTR, RR_MX, RR_TXT, RR_AAAA, RR_TLSA>;
332 using RR_collection = std::vector<RR>;
334 } // namespace DNS
336 #endif // DNS_RRS_DOT_HPP