Line | Count | Source (jump to first uncovered line) |
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 | | #include "qtype.hh" |
24 | | #include "dnsname.hh" |
25 | | #include <ctime> |
26 | | #include <sys/types.h> |
27 | | |
28 | | #undef BADSIG // signal.h SIG_ERR |
29 | | |
30 | | struct DNSRecord; |
31 | | |
32 | | class RCode |
33 | | { |
34 | | public: |
35 | | enum rcodes_ : uint8_t { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5, YXDomain=6, YXRRSet=7, NXRRSet=8, NotAuth=9, NotZone=10}; |
36 | | static std::string to_s(uint8_t rcode); |
37 | | static std::string to_short_s(uint8_t rcode); |
38 | | const static std::array<std::string, 24> rcodes_s; |
39 | | }; |
40 | | |
41 | | class ERCode |
42 | | { |
43 | | public: |
44 | | enum rcodes_ : uint16_t { BADVERS=16, BADSIG=16, BADKEY=17, BADTIME=18, BADMODE=19, BADNAME=20, BADALG=21, BADTRUNC=22, BADCOOKIE=23 }; |
45 | | static std::string to_s(uint16_t rcode); |
46 | | }; |
47 | | |
48 | | class Opcode |
49 | | { |
50 | | public: |
51 | | enum opcodes_ : uint8_t { Query=0, IQuery=1, Status=2, Notify=4, Update=5 }; |
52 | | static std::string to_s(uint8_t opcode); |
53 | | }; |
54 | | |
55 | | // This needs to be a signed type, so that serialization of UnknownDomainID |
56 | | // as text is "-1", for compatibility with the remote and pipe backends. |
57 | | // See static_assert there for details. |
58 | | using domainid_t = int32_t; |
59 | | |
60 | | constexpr domainid_t UnknownDomainID{-1}; |
61 | | |
62 | | //! This class represents a resource record |
63 | | class DNSResourceRecord |
64 | | { |
65 | | public: |
66 | | static DNSResourceRecord fromWire(const DNSRecord& wire); |
67 | | |
68 | | enum Place : uint8_t |
69 | | { |
70 | | QUESTION = 0, |
71 | | ANSWER = 1, |
72 | | AUTHORITY = 2, |
73 | | ADDITIONAL = 3 |
74 | | }; //!< Type describing the positioning within, say, a DNSPacket |
75 | | |
76 | | [[nodiscard]] static std::string placeString(uint8_t place); |
77 | | void setContent(const string& content); |
78 | | [[nodiscard]] string getZoneRepresentation(bool noDot = false) const; |
79 | | |
80 | | // data |
81 | | DNSName qname; //!< the name of this record, for example: www.powerdns.com |
82 | | DNSName ordername; |
83 | | DNSName wildcardname; |
84 | | string content; //!< what this record points to. Example: 10.1.2.3 |
85 | | |
86 | | // Aligned on 8-byte boundaries on systems where time_t is 8 bytes and int |
87 | | // is 4 bytes, aka modern linux on x86_64 |
88 | | time_t last_modified{}; //!< For autocalculating SOA serial numbers - the backend needs to fill this in |
89 | | |
90 | | uint32_t ttl{}; //!< Time To Live of this record |
91 | | uint32_t signttl{}; //!< If non-zero, use this TTL as original TTL in the RRSIG |
92 | | |
93 | | domainid_t domain_id{UnknownDomainID}; //!< If a backend implements this, the domain_id of the zone this record is in |
94 | | QType qtype; //!< qtype of this record, ie A, CNAME, MX etc |
95 | | uint16_t qclass{1}; //!< class of this record |
96 | | |
97 | | uint8_t scopeMask{}; |
98 | | bool auth{true}; |
99 | | bool disabled{}; |
100 | | |
101 | | bool operator==(const DNSResourceRecord& rhs); |
102 | | |
103 | | bool operator<(const DNSResourceRecord& other) const |
104 | 0 | { |
105 | 0 | if (qname < other.qname) { |
106 | 0 | return true; |
107 | 0 | } |
108 | 0 | if (qname == other.qname) { |
109 | 0 | return (content < other.content); |
110 | 0 | } |
111 | 0 | return false; |
112 | 0 | } |
113 | | }; |
114 | | |
115 | | #define GCCPACKATTRIBUTE __attribute__((packed)) |
116 | | |
117 | | struct dnsrecordheader |
118 | | { |
119 | | uint16_t d_type; |
120 | | uint16_t d_class; |
121 | | uint32_t d_ttl; |
122 | | uint16_t d_clen; |
123 | | } GCCPACKATTRIBUTE; |
124 | | |
125 | | struct EDNS0Record |
126 | | { |
127 | | uint8_t extRCode, version; |
128 | | uint16_t extFlags; |
129 | | } GCCPACKATTRIBUTE; |
130 | | |
131 | | static_assert(sizeof(EDNS0Record) == 4, "EDNS0Record size must be 4"); |
132 | | |
133 | | #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) |
134 | | #include <machine/endian.h> |
135 | | #elif __linux__ || __GNU__ |
136 | | # include <endian.h> |
137 | | |
138 | | #else // with thanks to <arpa/nameser.h> |
139 | | |
140 | | # define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ |
141 | | # define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ |
142 | | # define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ |
143 | | |
144 | | #if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ |
145 | | defined(__i386) || defined(__ia64) || defined(__amd64) || \ |
146 | | defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ |
147 | | defined(__alpha__) || defined(__alpha) || \ |
148 | | (defined(__Lynx__) && defined(__x86__)) |
149 | | # define BYTE_ORDER LITTLE_ENDIAN |
150 | | #endif |
151 | | |
152 | | #if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ |
153 | | defined(__sparc) || \ |
154 | | defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ |
155 | | defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ |
156 | | defined(apollo) || defined(__convex__) || defined(_CRAY) || \ |
157 | | defined(__hppa) || defined(__hp9000) || \ |
158 | | defined(__hp9000s300) || defined(__hp9000s700) || \ |
159 | | defined(__hp3000s900) || defined(MPE) || \ |
160 | | defined(BIT_ZERO_ON_LEFT) || defined(m68k) || \ |
161 | | (defined(__Lynx__) && \ |
162 | | (defined(__68k__) || defined(__sparc__) || defined(__powerpc__))) |
163 | | # define BYTE_ORDER BIG_ENDIAN |
164 | | #endif |
165 | | |
166 | | #endif |
167 | | |
168 | | struct dnsheader { |
169 | | uint16_t id; /* query identification number */ |
170 | | #if BYTE_ORDER == BIG_ENDIAN |
171 | | /* fields in third byte */ |
172 | | unsigned qr: 1; /* response flag */ |
173 | | unsigned opcode: 4; /* purpose of message */ |
174 | | unsigned aa: 1; /* authoritative answer */ |
175 | | unsigned tc: 1; /* truncated message */ |
176 | | unsigned rd: 1; /* recursion desired */ |
177 | | /* fields in fourth byte */ |
178 | | unsigned ra: 1; /* recursion available */ |
179 | | unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ |
180 | | unsigned ad: 1; /* authentic data from named */ |
181 | | unsigned cd: 1; /* checking disabled by resolver */ |
182 | | unsigned rcode :4; /* response code */ |
183 | | #elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN |
184 | | /* fields in third byte */ |
185 | | unsigned rd :1; /* recursion desired */ |
186 | | unsigned tc :1; /* truncated message */ |
187 | | unsigned aa :1; /* authoritative answer */ |
188 | | unsigned opcode :4; /* purpose of message */ |
189 | | unsigned qr :1; /* response flag */ |
190 | | /* fields in fourth byte */ |
191 | | unsigned rcode :4; /* response code */ |
192 | | unsigned cd: 1; /* checking disabled by resolver */ |
193 | | unsigned ad: 1; /* authentic data from named */ |
194 | | unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ |
195 | | unsigned ra :1; /* recursion available */ |
196 | | #endif |
197 | | /* remaining bytes */ |
198 | | uint16_t qdcount; /* number of question entries */ |
199 | | uint16_t ancount; /* number of answer entries */ |
200 | | uint16_t nscount; /* number of authority entries */ |
201 | | uint16_t arcount; /* number of resource entries */ |
202 | | }; |
203 | | |
204 | | static_assert(sizeof(dnsheader) == 12, "dnsheader size must be 12"); |
205 | | |
206 | | class dnsheader_aligned |
207 | | { |
208 | | public: |
209 | | static bool isMemoryAligned(const void* mem) |
210 | 5.05k | { |
211 | 5.05k | return reinterpret_cast<uintptr_t>(mem) % sizeof(uint32_t) == 0; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) |
212 | 5.05k | } |
213 | | |
214 | | dnsheader_aligned(const void* mem) |
215 | 5.05k | { |
216 | 5.05k | if (isMemoryAligned(mem)) { |
217 | 4.56k | d_p = reinterpret_cast<const dnsheader*>(mem); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) |
218 | 4.56k | } |
219 | 496 | else { |
220 | 496 | memcpy(&d_h, mem, sizeof(dnsheader)); |
221 | 496 | d_p = &d_h; |
222 | 496 | } |
223 | 5.05k | } |
224 | | |
225 | | [[nodiscard]] const dnsheader* get() const |
226 | 3.97k | { |
227 | 3.97k | return d_p; |
228 | 3.97k | } |
229 | | |
230 | | [[nodiscard]] const dnsheader& operator*() const |
231 | 0 | { |
232 | 0 | return *d_p; |
233 | 0 | } |
234 | | |
235 | | [[nodiscard]] const dnsheader* operator->() const |
236 | 3.99k | { |
237 | 3.99k | return d_p; |
238 | 3.99k | } |
239 | | |
240 | | private: |
241 | | dnsheader d_h{}; |
242 | | const dnsheader* d_p{}; |
243 | | }; |
244 | | |
245 | | inline uint16_t* getFlagsFromDNSHeader(dnsheader* dh) |
246 | 0 | { |
247 | 0 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) |
248 | 0 | return reinterpret_cast<uint16_t*>(reinterpret_cast<char*>(dh) + sizeof(uint16_t)); |
249 | 0 | } |
250 | | |
251 | | inline const uint16_t * getFlagsFromDNSHeader(const dnsheader* dh) |
252 | 0 | { |
253 | 0 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) |
254 | 0 | return reinterpret_cast<const uint16_t*>(reinterpret_cast<const char*>(dh) + sizeof(uint16_t)); |
255 | 0 | } |
256 | | |
257 | 0 | #define DNS_TYPE_SIZE (2) |
258 | 0 | #define DNS_CLASS_SIZE (2) |
259 | 0 | #define DNS_TTL_SIZE (4) |
260 | 1.17k | #define DNS_RDLENGTH_SIZE (2) |
261 | | #define EDNS_EXTENDED_RCODE_SIZE (1) |
262 | | #define EDNS_VERSION_SIZE (1) |
263 | 80.4k | #define EDNS_OPTION_CODE_SIZE (2) |
264 | 80.4k | #define EDNS_OPTION_LENGTH_SIZE (2) |
265 | | |
266 | | #if BYTE_ORDER == BIG_ENDIAN |
267 | | #define FLAGS_RD_OFFSET (8) |
268 | | #define FLAGS_CD_OFFSET (12) |
269 | | #elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN |
270 | | #define FLAGS_RD_OFFSET (0) |
271 | | #define FLAGS_CD_OFFSET (12) |
272 | | #endif |
273 | | |
274 | | uint32_t hashQuestion(const uint8_t* packet, uint16_t len, uint32_t init, bool& ok); |
275 | | |
276 | | struct TSIGTriplet |
277 | | { |
278 | | DNSName name, algo; |
279 | | string secret; |
280 | | }; |