From 2f230033794fafdf10822568e763d4db68cf6c6b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 23:14:49 +0200 Subject: Merging upstream version 1.9.3. Signed-off-by: Daniel Baumann --- dnsdist-doh-common.hh | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 dnsdist-doh-common.hh (limited to 'dnsdist-doh-common.hh') diff --git a/dnsdist-doh-common.hh b/dnsdist-doh-common.hh new file mode 100644 index 0000000..0dc714d --- /dev/null +++ b/dnsdist-doh-common.hh @@ -0,0 +1,248 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once + +#include +#include +#include +#include + +#include "config.h" +#include "iputils.hh" +#include "libssl.hh" +#include "noinitvector.hh" +#include "stat_t.hh" +#include "tcpiohandler.hh" + +namespace dnsdist::doh +{ +std::optional getPayloadFromPath(const std::string_view& path); +} + +struct DOHServerConfig; + +class DOHResponseMapEntry +{ +public: + DOHResponseMapEntry(const std::string& regex, uint16_t status, const PacketBuffer& content, const boost::optional>& headers) : + d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status) + { + if (status >= 400 && !d_content.empty() && d_content.at(d_content.size() - 1) != 0) { + // we need to make sure it's null-terminated + d_content.push_back(0); + } + } + + bool matches(const std::string& path) const + { + return d_regex.match(path); + } + + uint16_t getStatusCode() const + { + return d_status; + } + + const PacketBuffer& getContent() const + { + return d_content; + } + + const boost::optional>& getHeaders() const + { + return d_customHeaders; + } + +private: + Regex d_regex; + boost::optional> d_customHeaders; + PacketBuffer d_content; + uint16_t d_status; +}; + +struct DOHFrontend +{ + DOHFrontend() + { + } + DOHFrontend(std::shared_ptr tlsCtx) : + d_tlsContext(std::move(tlsCtx)) + { + } + + virtual ~DOHFrontend() + { + } + + std::shared_ptr d_dsc{nullptr}; + std::shared_ptr>> d_responsesMap; + TLSFrontend d_tlsContext{TLSFrontend::ALPN::DoH}; + std::string d_serverTokens{"h2o/dnsdist"}; + std::unordered_map d_customResponseHeaders; + std::string d_library; + + uint32_t d_idleTimeout{30}; // HTTP idle timeout in seconds + std::set> d_urls; + + pdns::stat_t d_httpconnects{0}; // number of TCP/IP connections established + pdns::stat_t d_getqueries{0}; // valid DNS queries received via GET + pdns::stat_t d_postqueries{0}; // valid DNS queries received via POST + pdns::stat_t d_badrequests{0}; // request could not be converted to dns query + pdns::stat_t d_errorresponses{0}; // dnsdist set 'error' on response + pdns::stat_t d_redirectresponses{0}; // dnsdist set 'redirect' on response + pdns::stat_t d_validresponses{0}; // valid responses sent out + + struct HTTPVersionStats + { + pdns::stat_t d_nbQueries{0}; // valid DNS queries received + pdns::stat_t d_nb200Responses{0}; + pdns::stat_t d_nb400Responses{0}; + pdns::stat_t d_nb403Responses{0}; + pdns::stat_t d_nb500Responses{0}; + pdns::stat_t d_nb502Responses{0}; + pdns::stat_t d_nbOtherResponses{0}; + }; + + HTTPVersionStats d_http1Stats; + HTTPVersionStats d_http2Stats; +#ifdef __linux__ + // On Linux this gives us 128k pending queries (default is 8192 queries), + // which should be enough to deal with huge spikes + uint32_t d_internalPipeBufferSize{1024 * 1024}; +#else + uint32_t d_internalPipeBufferSize{0}; +#endif + bool d_sendCacheControlHeaders{true}; + bool d_trustForwardedForHeader{false}; + bool d_earlyACLDrop{true}; + /* whether we require tue query path to exactly match one of configured ones, + or accept everything below these paths. */ + bool d_exactPathMatching{true}; + bool d_keepIncomingHeaders{false}; + + time_t getTicketsKeyRotationDelay() const + { + return d_tlsContext.d_tlsConfig.d_ticketsKeyRotationDelay; + } + + bool isHTTPS() const + { + return !d_tlsContext.d_tlsConfig.d_certKeyPairs.empty(); + } + +#ifndef HAVE_DNS_OVER_HTTPS + virtual void setup() + { + } + + virtual void reloadCertificates() + { + } + + virtual void rotateTicketsKey(time_t /* now */) + { + } + + virtual void loadTicketsKeys(const std::string& /* keyFile */) + { + } + + virtual void handleTicketsKeyRotation() + { + } + + virtual std::string getNextTicketsKeyRotation() + { + return std::string(); + } + + virtual size_t getTicketsKeysCount() const + { + size_t res = 0; + return res; + } + +#else + virtual void setup(); + virtual void reloadCertificates(); + + virtual void rotateTicketsKey(time_t now); + virtual void loadTicketsKeys(const std::string& keyFile); + virtual void handleTicketsKeyRotation(); + virtual std::string getNextTicketsKeyRotation() const; + virtual size_t getTicketsKeysCount(); +#endif /* HAVE_DNS_OVER_HTTPS */ +}; + +#include "dnsdist-idstate.hh" + +struct DownstreamState; + +#ifndef HAVE_DNS_OVER_HTTPS +struct DOHUnitInterface +{ + virtual ~DOHUnitInterface() + { + } + static void handleTimeout(std::unique_ptr) + { + } + + static void handleUDPResponse(std::unique_ptr, PacketBuffer&&, InternalQueryState&&, const std::shared_ptr&) + { + } +}; +#else /* HAVE_DNS_OVER_HTTPS */ +struct DOHUnitInterface +{ + virtual ~DOHUnitInterface() + { + } + + virtual std::string getHTTPPath() const = 0; + virtual std::string getHTTPQueryString() const = 0; + virtual const std::string& getHTTPHost() const = 0; + virtual const std::string& getHTTPScheme() const = 0; + virtual const std::unordered_map& getHTTPHeaders() const = 0; + virtual void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType = "") = 0; + virtual void handleTimeout() = 0; + virtual void handleUDPResponse(PacketBuffer&& response, InternalQueryState&& state, const std::shared_ptr&) = 0; + + static void handleTimeout(std::unique_ptr unit) + { + if (unit) { + unit->handleTimeout(); + unit.release(); + } + } + + static void handleUDPResponse(std::unique_ptr unit, PacketBuffer&& response, InternalQueryState&& state, const std::shared_ptr& ds) + { + if (unit) { + unit->handleUDPResponse(std::move(response), std::move(state), ds); + unit.release(); + } + } + + std::shared_ptr downstream{nullptr}; +}; +#endif /* HAVE_DNS_OVER_HTTPS */ -- cgit v1.2.3