Coverage Report

Created: 2023-03-26 07:17

/src/pdns/pdns/doh.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
24
#include <unordered_map>
25
26
#include "iputils.hh"
27
#include "libssl.hh"
28
#include "noinitvector.hh"
29
#include "stat_t.hh"
30
31
struct DOHServerConfig;
32
33
class DOHResponseMapEntry
34
{
35
public:
36
  DOHResponseMapEntry(const std::string& regex, uint16_t status, const PacketBuffer& content, const boost::optional<std::unordered_map<std::string, std::string>>& headers): d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status)
37
0
  {
38
0
    if (status >= 400 && !d_content.empty() && d_content.at(d_content.size() -1) != 0) {
39
0
      // we need to make sure it's null-terminated
40
0
      d_content.push_back(0);
41
0
    }
42
0
  }
43
44
  bool matches(const std::string& path) const
45
0
  {
46
0
    return d_regex.match(path);
47
0
  }
48
49
  uint16_t getStatusCode() const
50
0
  {
51
0
    return d_status;
52
0
  }
53
54
  const PacketBuffer& getContent() const
55
0
  {
56
0
    return d_content;
57
0
  }
58
59
  const boost::optional<std::unordered_map<std::string, std::string>>& getHeaders() const
60
0
  {
61
0
    return d_customHeaders;
62
0
  }
63
64
private:
65
  Regex d_regex;
66
  boost::optional<std::unordered_map<std::string, std::string>> d_customHeaders;
67
  PacketBuffer d_content;
68
  uint16_t d_status;
69
};
70
71
struct DOHFrontend
72
{
73
  DOHFrontend()
74
0
  {
75
0
  }
76
77
  std::shared_ptr<DOHServerConfig> d_dsc{nullptr};
78
  std::shared_ptr<std::vector<std::shared_ptr<DOHResponseMapEntry>>> d_responsesMap;
79
  TLSConfig d_tlsConfig;
80
  TLSErrorCounters d_tlsCounters;
81
  std::string d_serverTokens{"h2o/dnsdist"};
82
  std::unordered_map<std::string, std::string> d_customResponseHeaders;
83
  ComboAddress d_local;
84
85
  uint32_t d_idleTimeout{30};             // HTTP idle timeout in seconds
86
  std::vector<std::string> d_urls;
87
88
  pdns::stat_t d_httpconnects{0};   // number of TCP/IP connections established
89
  pdns::stat_t d_getqueries{0};     // valid DNS queries received via GET
90
  pdns::stat_t d_postqueries{0};    // valid DNS queries received via POST
91
  pdns::stat_t d_badrequests{0};     // request could not be converted to dns query
92
  pdns::stat_t d_errorresponses{0}; // dnsdist set 'error' on response
93
  pdns::stat_t d_redirectresponses{0}; // dnsdist set 'redirect' on response
94
  pdns::stat_t d_validresponses{0}; // valid responses sent out
95
96
  struct HTTPVersionStats
97
  {
98
    pdns::stat_t d_nbQueries{0}; // valid DNS queries received
99
    pdns::stat_t d_nb200Responses{0};
100
    pdns::stat_t d_nb400Responses{0};
101
    pdns::stat_t d_nb403Responses{0};
102
    pdns::stat_t d_nb500Responses{0};
103
    pdns::stat_t d_nb502Responses{0};
104
    pdns::stat_t d_nbOtherResponses{0};
105
  };
106
107
  HTTPVersionStats d_http1Stats;
108
  HTTPVersionStats d_http2Stats;
109
#ifdef __linux__
110
  // On Linux this gives us 128k pending queries (default is 8192 queries),
111
  // which should be enough to deal with huge spikes
112
  uint32_t d_internalPipeBufferSize{1024*1024};
113
#else
114
  uint32_t d_internalPipeBufferSize{0};
115
#endif
116
  bool d_sendCacheControlHeaders{true};
117
  bool d_trustForwardedForHeader{false};
118
  /* whether we require tue query path to exactly match one of configured ones,
119
     or accept everything below these paths. */
120
  bool d_exactPathMatching{true};
121
  bool d_keepIncomingHeaders{false};
122
123
  time_t getTicketsKeyRotationDelay() const
124
0
  {
125
0
    return d_tlsConfig.d_ticketsKeyRotationDelay;
126
0
  }
127
128
  bool isHTTPS() const
129
0
  {
130
0
    return !d_tlsConfig.d_certKeyPairs.empty();
131
0
  }
132
133
#ifndef HAVE_DNS_OVER_HTTPS
134
  void setup()
135
0
  {
136
0
  }
137
138
  void reloadCertificates()
139
0
  {
140
0
  }
141
142
  void rotateTicketsKey(time_t /* now */)
143
0
  {
144
0
  }
145
146
  void loadTicketsKeys(const std::string& /* keyFile */)
147
0
  {
148
0
  }
149
150
  void handleTicketsKeyRotation()
151
0
  {
152
0
  }
153
154
  time_t getNextTicketsKeyRotation() const
155
0
  {
156
0
    return 0;
157
0
  }
158
159
  size_t getTicketsKeysCount() const
160
0
  {
161
0
    size_t res = 0;
162
0
    return res;
163
0
  }
164
165
#else
166
  void setup();
167
  void reloadCertificates();
168
169
  void rotateTicketsKey(time_t now);
170
  void loadTicketsKeys(const std::string& keyFile);
171
  void handleTicketsKeyRotation();
172
  time_t getNextTicketsKeyRotation() const;
173
  size_t getTicketsKeysCount() const;
174
#endif /* HAVE_DNS_OVER_HTTPS */
175
};
176
177
#ifndef HAVE_DNS_OVER_HTTPS
178
struct DOHUnit
179
{
180
  static void release(DOHUnit*)
181
0
  {
182
0
  }
183
184
  void get()
185
0
  {
186
0
  }
187
188
  void release()
189
0
  {
190
0
  }
191
192
  size_t proxyProtocolPayloadSize{0};
193
  uint16_t status_code{200};
194
};
195
196
#else /* HAVE_DNS_OVER_HTTPS */
197
#include <unordered_map>
198
199
#include "dnsdist-idstate.hh"
200
201
struct st_h2o_req_t;
202
struct DownstreamState;
203
204
struct DOHUnit
205
{
206
  DOHUnit(PacketBuffer&& q, std::string&& p, std::string&& h): path(std::move(p)), host(std::move(h)), query(std::move(q))
207
  {
208
    ids.ednsAdded = false;
209
  }
210
211
  DOHUnit(const DOHUnit&) = delete;
212
  DOHUnit& operator=(const DOHUnit&) = delete;
213
214
  void get()
215
  {
216
    ++d_refcnt;
217
  }
218
219
  void release()
220
  {
221
    if (--d_refcnt == 0) {
222
      if (self) {
223
        *self = nullptr;
224
      }
225
226
      delete this;
227
    }
228
  }
229
230
  static void release(DOHUnit* ptr)
231
  {
232
    if (ptr) {
233
      ptr->release();
234
    }
235
  }
236
237
  InternalQueryState ids;
238
  std::string sni;
239
  std::string path;
240
  std::string scheme;
241
  std::string host;
242
  std::string contentType;
243
  PacketBuffer query;
244
  PacketBuffer response;
245
  std::shared_ptr<DownstreamState> downstream{nullptr};
246
  std::unique_ptr<std::unordered_map<std::string, std::string>> headers;
247
  st_h2o_req_t* req{nullptr};
248
  DOHUnit** self{nullptr};
249
  DOHServerConfig* dsc{nullptr};
250
  std::atomic<uint64_t> d_refcnt{1};
251
  size_t query_at{0};
252
  size_t proxyProtocolPayloadSize{0};
253
  int rsock{-1};
254
  /* the status_code is set from
255
     processDOHQuery() (which is executed in
256
     the DOH client thread) so that the correct
257
     response can be sent in on_dnsdist(),
258
     after the DOHUnit has been passed back to
259
     the main DoH thread.
260
  */
261
  uint16_t status_code{200};
262
  /* whether the query was re-sent to the backend over
263
     TCP after receiving a truncated answer over UDP */
264
  bool tcp{false};
265
  bool truncated{false};
266
267
  std::string getHTTPPath() const;
268
  std::string getHTTPHost() const;
269
  std::string getHTTPScheme() const;
270
  std::string getHTTPQueryString() const;
271
  std::unordered_map<std::string, std::string> getHTTPHeaders() const;
272
  void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType="");
273
};
274
275
void handleUDPResponseForDoH(std::unique_ptr<DOHUnit, void(*)(DOHUnit*)>&&, PacketBuffer&& response, InternalQueryState&& state);
276
277
struct CrossProtocolQuery;
278
struct DNSQuestion;
279
280
std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse);
281
282
#endif /* HAVE_DNS_OVER_HTTPS  */
283
284
using DOHUnitUniquePtr = std::unique_ptr<DOHUnit, void(*)(DOHUnit*)>;
285
286
void handleDOHTimeout(DOHUnitUniquePtr&& oldDU);