• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 19741624072

27 Nov 2025 03:45PM UTC coverage: 73.086% (+0.02%) from 73.065%
19741624072

Pull #16570

github

web-flow
Merge 08a2cdb1d into f94a3f63f
Pull Request #16570: rec: rewrite all unwrap calls in web.rs

38523 of 63408 branches covered (60.75%)

Branch coverage included in aggregate %.

128044 of 164496 relevant lines covered (77.84%)

6531485.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.57
/pdns/dnsdistdist/dnsdist-doh-common.hh
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 <optional>
25
#include <unordered_map>
26
#include <set>
27
#include <string_view>
28

29
#include "config.h"
30
#include "iputils.hh"
31
#include "libssl.hh"
32
#include "noinitvector.hh"
33
#include "stat_t.hh"
34
#include "tcpiohandler.hh"
35

36
namespace dnsdist::doh
37
{
38
static constexpr uint32_t MAX_INCOMING_CONCURRENT_STREAMS{100U};
39

40
std::optional<PacketBuffer> getPayloadFromPath(const std::string_view& path);
41
}
42

43
struct DOHServerConfig;
44

45
class DOHResponseMapEntry
46
{
47
public:
48
  DOHResponseMapEntry(const std::string& regex, uint16_t status, const PacketBuffer& content, const boost::optional<std::unordered_map<std::string, std::string>>& headers) :
49
    d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status)
8✔
50
  {
8✔
51
    if (status >= 400 && !d_content.empty() && d_content.at(d_content.size() - 1) != 0) {
8!
52
      // we need to make sure it's null-terminated
53
      d_content.push_back(0);
8✔
54
    }
8✔
55
  }
8✔
56

57
  bool matches(const std::string& path) const
58
  {
85✔
59
    return d_regex.match(path);
85✔
60
  }
85✔
61

62
  uint16_t getStatusCode() const
63
  {
10✔
64
    return d_status;
10✔
65
  }
10✔
66

67
  const PacketBuffer& getContent() const
68
  {
6✔
69
    return d_content;
6✔
70
  }
6✔
71

72
  const boost::optional<std::unordered_map<std::string, std::string>>& getHeaders() const
73
  {
6✔
74
    return d_customHeaders;
6✔
75
  }
6✔
76

77
private:
78
  Regex d_regex;
79
  boost::optional<std::unordered_map<std::string, std::string>> d_customHeaders;
80
  PacketBuffer d_content;
81
  uint16_t d_status;
82
};
83

84
struct DOHFrontend
85
{
86
  DOHFrontend() :
87
    d_tlsContext(std::make_shared<TLSFrontend>(TLSFrontend::ALPN::DoH))
168✔
88
  {
168✔
89
  }
168✔
90
  DOHFrontend(std::shared_ptr<TLSCtx> tlsCtx) :
91
    d_tlsContext(std::make_shared<TLSFrontend>(std::move(tlsCtx)))
6✔
92
  {
6✔
93
  }
6✔
94

95
  virtual ~DOHFrontend()
96
  {
52✔
97
  }
52✔
98

99
  std::shared_ptr<DOHServerConfig> d_dsc{nullptr};
100
  std::shared_ptr<std::vector<std::shared_ptr<DOHResponseMapEntry>>> d_responsesMap;
101
  std::shared_ptr<TLSFrontend> d_tlsContext;
102
  std::string d_serverTokens{"h2o/dnsdist"};
103
  std::unordered_map<std::string, std::string> d_customResponseHeaders;
104
  std::string d_library;
105

106
  uint32_t d_idleTimeout{30}; // HTTP idle timeout in seconds
107
  std::set<std::string, std::less<>> d_urls;
108

109
  pdns::stat_t d_httpconnects{0}; // number of TCP/IP connections established
110
  pdns::stat_t d_getqueries{0}; // valid DNS queries received via GET
111
  pdns::stat_t d_postqueries{0}; // valid DNS queries received via POST
112
  pdns::stat_t d_badrequests{0}; // request could not be converted to dns query
113
  pdns::stat_t d_errorresponses{0}; // dnsdist set 'error' on response
114
  pdns::stat_t d_redirectresponses{0}; // dnsdist set 'redirect' on response
115
  pdns::stat_t d_validresponses{0}; // valid responses sent out
116

117
  struct HTTPVersionStats
118
  {
119
    pdns::stat_t d_nbQueries{0}; // valid DNS queries received
120
    pdns::stat_t d_nb200Responses{0};
121
    pdns::stat_t d_nb400Responses{0};
122
    pdns::stat_t d_nb403Responses{0};
123
    pdns::stat_t d_nb500Responses{0};
124
    pdns::stat_t d_nb502Responses{0};
125
    pdns::stat_t d_nbOtherResponses{0};
126
  };
127

128
  HTTPVersionStats d_http1Stats;
129
  HTTPVersionStats d_http2Stats;
130
#ifdef __linux__
131
  // On Linux this gives us 128k pending queries (default is 8192 queries),
132
  // which should be enough to deal with huge spikes
133
  uint32_t d_internalPipeBufferSize{1024 * 1024};
134
#else
135
  uint32_t d_internalPipeBufferSize{0};
136
#endif
137
  bool d_sendCacheControlHeaders{true};
138
  bool d_trustForwardedForHeader{false};
139
  bool d_earlyACLDrop{true};
140
  /* whether we require tue query path to exactly match one of configured ones,
141
     or accept everything below these paths. */
142
  bool d_exactPathMatching{true};
143
  bool d_keepIncomingHeaders{false};
144

145
  time_t getTicketsKeyRotationDelay() const
146
  {
12✔
147
    return d_tlsContext->d_tlsConfig.d_ticketsKeyRotationDelay;
12✔
148
  }
12✔
149

150
  bool isHTTPS() const
151
  {
797✔
152
    return !d_tlsContext->d_tlsConfig.d_certKeyPairs.empty();
797✔
153
  }
797✔
154

155
#ifndef HAVE_DNS_OVER_HTTPS
156
  virtual void setup()
157
  {
158
  }
159

160
  virtual void reloadCertificates()
161
  {
162
  }
163

164
  virtual void rotateTicketsKey(time_t /* now */)
165
  {
166
  }
167

168
  virtual void loadTicketsKeys(const std::string& /* keyFile */)
169
  {
170
  }
171

172
  virtual void loadTicketsKey(const std::string& /* key */)
173
  {
174
  }
175

176
  virtual void handleTicketsKeyRotation()
177
  {
178
  }
179

180
  virtual std::string getNextTicketsKeyRotation()
181
  {
182
    return std::string();
183
  }
184

185
  virtual size_t getTicketsKeysCount() const
186
  {
187
    size_t res = 0;
188
    return res;
189
  }
190

191
#else
192
  virtual void setup();
193
  virtual void reloadCertificates();
194

195
  virtual void rotateTicketsKey(time_t now);
196
  virtual void loadTicketsKeys(const std::string& keyFile);
197
  virtual void loadTicketsKey(const std::string& key);
198
  virtual void handleTicketsKeyRotation();
199
  virtual std::string getNextTicketsKeyRotation() const;
200
  virtual size_t getTicketsKeysCount();
201
#endif /* HAVE_DNS_OVER_HTTPS */
202
};
203

204
#include "dnsdist-idstate.hh"
205

206
struct DownstreamState;
207

208
class TCPQuerySender;
209

210
#ifndef HAVE_DNS_OVER_HTTPS
211
struct DOHUnitInterface
212
{
213
  virtual ~DOHUnitInterface()
214
  {
215
  }
216

217
  virtual std::shared_ptr<TCPQuerySender> getQuerySender() const
218
  {
219
    return nullptr;
220
  }
221

222
  static void handleTimeout(std::unique_ptr<DOHUnitInterface>)
223
  {
224
  }
225

226
  static void handleUDPResponse(std::unique_ptr<DOHUnitInterface>, PacketBuffer&&, InternalQueryState&&, const std::shared_ptr<DownstreamState>&)
227
  {
228
  }
229
};
230
#else /* HAVE_DNS_OVER_HTTPS */
231
struct DOHUnitInterface
232
{
233
  virtual ~DOHUnitInterface()
234
  {
320✔
235
  }
320✔
236

237
  virtual std::string getHTTPPath() const = 0;
238
  virtual std::string getHTTPQueryString() const = 0;
239
  virtual const std::string& getHTTPHost() const = 0;
240
  virtual const std::string& getHTTPScheme() const = 0;
241
  virtual const std::unordered_map<std::string, std::string>& getHTTPHeaders() const = 0;
242
  virtual std::shared_ptr<TCPQuerySender> getQuerySender() const = 0;
243
  virtual void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType = "") = 0;
244
  virtual void handleTimeout() = 0;
245
  virtual void handleUDPResponse(PacketBuffer&& response, InternalQueryState&& state, const std::shared_ptr<DownstreamState>&) = 0;
246

247
  static void handleTimeout(std::unique_ptr<DOHUnitInterface> unit)
248
  {
5✔
249
    if (unit) {
5!
250
      auto* ptr = unit.release();
251
      ptr->handleTimeout();
252
    }
253
  }
5✔
254

255
  static void handleUDPResponse(std::unique_ptr<DOHUnitInterface> unit, PacketBuffer&& response, InternalQueryState&& state, const std::shared_ptr<DownstreamState>& ds)
256
  {
122✔
257
    if (unit) {
122!
258
      auto* ptr = unit.release();
122✔
259
      ptr->handleUDPResponse(std::move(response), std::move(state), ds);
122✔
260
    }
122✔
261
  }
122✔
262

263
  std::shared_ptr<DownstreamState> downstream{nullptr};
264
};
265
#endif /* HAVE_DNS_OVER_HTTPS  */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc