Coverage Report

Created: 2023-09-25 07:00

/src/pdns/pdns/dnsdistdist/dns.hh
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 { Query=0, IQuery=1, Status=2, Notify=4, Update=5 };
52
  static std::string to_s(uint8_t opcode);
53
};
54
55
//! This class represents a resource record
56
class DNSResourceRecord
57
{
58
public:
59
4.93k
  DNSResourceRecord() : last_modified(0), ttl(0), signttl(0), domain_id(-1), qclass(1), scopeMask(0), auth(1), disabled(0) {};
60
  static DNSResourceRecord fromWire(const DNSRecord& d);
61
62
  enum Place : uint8_t {QUESTION=0, ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; //!< Type describing the positioning within, say, a DNSPacket
63
64
  void setContent(const string& content);
65
  string getZoneRepresentation(bool noDot=false) const;
66
67
  // data
68
  DNSName qname; //!< the name of this record, for example: www.powerdns.com
69
  DNSName ordername;
70
  DNSName wildcardname;
71
  string content; //!< what this record points to. Example: 10.1.2.3
72
73
  // Aligned on 8-byte boundaries on systems where time_t is 8 bytes and int
74
  // is 4 bytes, aka modern linux on x86_64
75
  time_t last_modified; //!< For autocalculating SOA serial numbers - the backend needs to fill this in
76
77
  uint32_t ttl; //!< Time To Live of this record
78
  uint32_t signttl; //!< If non-zero, use this TTL as original TTL in the RRSIG
79
80
  int domain_id; //!< If a backend implements this, the domain_id of the zone this record is in
81
  QType qtype; //!< qtype of this record, ie A, CNAME, MX etc
82
  uint16_t qclass; //!< class of this record
83
84
  uint8_t scopeMask;
85
  bool auth;
86
  bool disabled;
87
88
  bool operator==(const DNSResourceRecord& rhs);
89
90
  bool operator<(const DNSResourceRecord &b) const
91
0
  {
92
0
    if(qname < b.qname)
93
0
      return true;
94
0
    if(qname == b.qname)
95
0
      return(content < b.content);
96
0
    return false;
97
0
  }
98
};
99
100
#define GCCPACKATTRIBUTE __attribute__((packed))
101
102
struct dnsrecordheader
103
{
104
  uint16_t d_type;
105
  uint16_t d_class;
106
  uint32_t d_ttl;
107
  uint16_t d_clen;
108
} GCCPACKATTRIBUTE;
109
110
struct EDNS0Record
111
{
112
  uint8_t extRCode, version;
113
  uint16_t extFlags;
114
} GCCPACKATTRIBUTE;
115
116
static_assert(sizeof(EDNS0Record) == 4, "EDNS0Record size must be 4");
117
118
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
119
#include <machine/endian.h>
120
#elif __linux__ || __GNU__
121
# include <endian.h>
122
123
#else  // with thanks to <arpa/nameser.h> 
124
125
# define LITTLE_ENDIAN   1234    /* least-significant byte first (vax, pc) */
126
# define BIG_ENDIAN      4321    /* most-significant byte first (IBM, net) */
127
# define PDP_ENDIAN      3412    /* LSB first in word, MSW first in long (pdp) */
128
129
#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
130
        defined(__i386) || defined(__ia64) || defined(__amd64) || \
131
        defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
132
        defined(__alpha__) || defined(__alpha) || \
133
        (defined(__Lynx__) && defined(__x86__))
134
# define BYTE_ORDER      LITTLE_ENDIAN
135
#endif
136
137
#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
138
    defined(__sparc) || \
139
    defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
140
    defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
141
    defined(apollo) || defined(__convex__) || defined(_CRAY) || \
142
    defined(__hppa) || defined(__hp9000) || \
143
    defined(__hp9000s300) || defined(__hp9000s700) || \
144
    defined(__hp3000s900) || defined(MPE) || \
145
    defined(BIT_ZERO_ON_LEFT) || defined(m68k) || \
146
        (defined(__Lynx__) && \
147
        (defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))
148
# define BYTE_ORDER      BIG_ENDIAN
149
#endif
150
151
#endif
152
153
struct dnsheader {
154
        uint16_t        id;             /* query identification number */
155
#if BYTE_ORDER == BIG_ENDIAN
156
                        /* fields in third byte */
157
        unsigned        qr: 1;          /* response flag */
158
        unsigned        opcode: 4;      /* purpose of message */
159
        unsigned        aa: 1;          /* authoritative answer */
160
        unsigned        tc: 1;          /* truncated message */
161
        unsigned        rd: 1;          /* recursion desired */
162
                        /* fields in fourth byte */
163
        unsigned        ra: 1;          /* recursion available */
164
        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
165
        unsigned        ad: 1;          /* authentic data from named */
166
        unsigned        cd: 1;          /* checking disabled by resolver */
167
        unsigned        rcode :4;       /* response code */
168
#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
169
                        /* fields in third byte */
170
        unsigned        rd :1;          /* recursion desired */
171
        unsigned        tc :1;          /* truncated message */
172
        unsigned        aa :1;          /* authoritative answer */
173
        unsigned        opcode :4;      /* purpose of message */
174
        unsigned        qr :1;          /* response flag */
175
                        /* fields in fourth byte */
176
        unsigned        rcode :4;       /* response code */
177
        unsigned        cd: 1;          /* checking disabled by resolver */
178
        unsigned        ad: 1;          /* authentic data from named */
179
        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
180
        unsigned        ra :1;          /* recursion available */
181
#endif
182
                        /* remaining bytes */
183
        uint16_t        qdcount;        /* number of question entries */
184
        uint16_t        ancount;        /* number of answer entries */
185
        uint16_t        nscount;        /* number of authority entries */
186
        uint16_t        arcount;        /* number of resource entries */
187
};
188
189
static_assert(sizeof(dnsheader) == 12, "dnsheader size must be 12");
190
191
class dnsheader_aligned
192
{
193
public:
194
  dnsheader_aligned(const void* mem)
195
3.62k
  {
196
3.62k
    if (reinterpret_cast<uintptr_t>(mem) % sizeof(uint32_t) == 0) {  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
197
3.09k
      d_p = reinterpret_cast<const dnsheader*>(mem);  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
198
3.09k
    }
199
526
    else {
200
526
      memcpy(&d_h, mem, sizeof(dnsheader));
201
526
      d_p = &d_h;
202
526
    }
203
3.62k
  }
204
205
  [[nodiscard]] const dnsheader* get() const
206
3.62k
  {
207
3.62k
    return d_p;
208
3.62k
  }
209
210
private:
211
  dnsheader d_h{};
212
  const dnsheader *d_p{};
213
};
214
215
inline uint16_t * getFlagsFromDNSHeader(struct dnsheader * dh)
216
0
{
217
0
  return (uint16_t*) (((char *) dh) + sizeof(uint16_t));
218
0
}
219
220
2.29k
#define DNS_TYPE_SIZE (2)
221
2.29k
#define DNS_CLASS_SIZE (2)
222
1.08k
#define DNS_TTL_SIZE (4)
223
1.62k
#define DNS_RDLENGTH_SIZE (2)
224
0
#define EDNS_EXTENDED_RCODE_SIZE (1)
225
0
#define EDNS_VERSION_SIZE (1)
226
64.6k
#define EDNS_OPTION_CODE_SIZE (2)
227
64.6k
#define EDNS_OPTION_LENGTH_SIZE (2)
228
229
#if BYTE_ORDER == BIG_ENDIAN
230
#define FLAGS_RD_OFFSET (8)
231
#define FLAGS_CD_OFFSET (12)
232
#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
233
#define FLAGS_RD_OFFSET (0)
234
#define FLAGS_CD_OFFSET (12)
235
#endif
236
237
uint32_t hashQuestion(const uint8_t* packet, uint16_t len, uint32_t init, bool& ok);
238
239
struct TSIGTriplet
240
{
241
  DNSName name, algo;
242
  string secret;
243
};