From: Remi Gacogne Date: Tue, 13 Apr 2021 12:47:26 +0000 (+0200) Subject: dnsdist: Handle Proxy Protocol payloads with cross-protocol queries X-Git-Tag: dnsdist-1.7.0-alpha1~45^2~45 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=acf2a2211a1473eadae1fa0f3175fff6d0d6f33e;p=thirdparty%2Fpdns.git dnsdist: Handle Proxy Protocol payloads with cross-protocol queries --- diff --git a/pdns/dnsdist-tcp.cc b/pdns/dnsdist-tcp.cc index cea13fc631..022ae68783 100644 --- a/pdns/dnsdist-tcp.cc +++ b/pdns/dnsdist-tcp.cc @@ -379,14 +379,18 @@ static void handleResponseSent(std::shared_ptr& stat } } -static void prependSizeToTCPQuery(PacketBuffer& buffer) +static void prependSizeToTCPQuery(PacketBuffer& buffer, size_t proxyProtocolPayloadSize) { - uint16_t queryLen = buffer.size(); + if (buffer.size() <= proxyProtocolPayloadSize) { + throw std::runtime_error("The payload size is smaller or equal to the buffer size"); + } + + uint16_t queryLen = proxyProtocolPayloadSize > 0 ? (buffer.size() - proxyProtocolPayloadSize) : buffer.size(); const uint8_t sizeBytes[] = { static_cast(queryLen / 256), static_cast(queryLen % 256) }; /* prepend the size. Yes, this is not the most efficient way but it prevents mistakes that could occur if we had to deal with the size during the processing, especially alignment issues */ - buffer.insert(buffer.begin(), sizeBytes, sizeBytes + 2); + buffer.insert(buffer.begin() + proxyProtocolPayloadSize, sizeBytes, sizeBytes + 2); } bool IncomingTCPConnectionState::canAcceptNewQueries(const struct timeval& now) @@ -714,7 +718,7 @@ static void handleQuery(std::shared_ptr& state, cons setIDStateFromDNSQuestion(ids, dq, std::move(qname)); ids.origID = ntohs(dh->id); - prependSizeToTCPQuery(state->d_buffer); + prependSizeToTCPQuery(state->d_buffer, 0); auto downstreamConnection = state->getDownstreamConnection(ds, dq.proxyProtocolValues, now); @@ -1137,14 +1141,14 @@ static void handleCrossProtocolQuery(int pipefd, FDMultiplexer::funcparam_t& par auto query = std::move(tmp->query); auto downstreamServer = std::move(tmp->downstream); + auto proxyProtocolPayloadSize = tmp->proxyProtocolPayloadSize; std::shared_ptr tqs = tmp->getTCPQuerySender(); delete tmp; tmp = nullptr; auto downstream = DownstreamConnectionsManager::getConnectionToDownstream(threadData->mplexer, downstreamServer, now); -#warning FIXME: what if a proxy protocol payload was inserted? - prependSizeToTCPQuery(query.d_buffer); + prependSizeToTCPQuery(query.d_buffer, proxyProtocolPayloadSize); downstream->queueQuery(tqs, std::move(query)); } catch (...) { diff --git a/pdns/dnsdistdist/dnsdist-proxy-protocol.cc b/pdns/dnsdistdist/dnsdist-proxy-protocol.cc index 06a300d6a5..6a3e978977 100644 --- a/pdns/dnsdistdist/dnsdist-proxy-protocol.cc +++ b/pdns/dnsdistdist/dnsdist-proxy-protocol.cc @@ -41,9 +41,13 @@ bool addProxyProtocol(DNSQuestion& dq, const std::string& payload) return addProxyProtocol(dq.getMutableData(), payload); } -bool addProxyProtocol(DNSQuestion& dq) +bool addProxyProtocol(DNSQuestion& dq, size_t* payloadSize) { auto payload = getProxyProtocolPayload(dq); + if (payloadSize != nullptr) { + *payloadSize = payload.size(); + } + return addProxyProtocol(dq, payload); } diff --git a/pdns/dnsdistdist/dnsdist-proxy-protocol.hh b/pdns/dnsdistdist/dnsdist-proxy-protocol.hh index fac7dea618..de7674a2db 100644 --- a/pdns/dnsdistdist/dnsdist-proxy-protocol.hh +++ b/pdns/dnsdistdist/dnsdist-proxy-protocol.hh @@ -29,7 +29,7 @@ extern bool g_applyACLToProxiedClients; std::string getProxyProtocolPayload(const DNSQuestion& dq); -bool addProxyProtocol(DNSQuestion& dq); +bool addProxyProtocol(DNSQuestion& dq, size_t* proxyProtocolPayloadSize = nullptr); bool addProxyProtocol(DNSQuestion& dq, const std::string& payload); bool addProxyProtocol(PacketBuffer& buffer, const std::string& payload); bool addProxyProtocol(PacketBuffer& buffer, bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector& values); diff --git a/pdns/dnsdistdist/dnsdist-tcp.hh b/pdns/dnsdistdist/dnsdist-tcp.hh index b932e5d5a4..6a0058ca53 100644 --- a/pdns/dnsdistdist/dnsdist-tcp.hh +++ b/pdns/dnsdistdist/dnsdist-tcp.hh @@ -157,6 +157,8 @@ struct CrossProtocolQuery InternalQuery query; std::shared_ptr downstream{nullptr}; + size_t proxyProtocolPayloadSize{0}; + bool isXFR{false}; }; class TCPClientCollection { diff --git a/pdns/dnsdistdist/doh.cc b/pdns/dnsdistdist/doh.cc index 296c09e6db..fe237dcece 100644 --- a/pdns/dnsdistdist/doh.cc +++ b/pdns/dnsdistdist/doh.cc @@ -199,14 +199,6 @@ struct DOHServerConfig setNonBlocking(dohresponsepair[1]); - if (pipe(fd) < 0) { - close(dohquerypair[0]); - close(dohquerypair[1]); - close(dohresponsepair[0]); - close(dohresponsepair[1]); - unixDie("Creating a pipe for DNS over HTTPS"); - } - h2o_config_init(&h2o_config); h2o_config.http2.idle_timeout = idleTimeout * 1000; } @@ -563,7 +555,10 @@ static int processDOHQuery(DOHUnit* du) } if (du->downstream->useProxyProtocol) { - addProxyProtocol(dq); + size_t payloadSize = 0; + if (addProxyProtocol(dq)) { + du->proxyProtocolPayloadSize = payloadSize; + } } int fd = pickBackendSocketForSending(du->downstream); @@ -1196,6 +1191,7 @@ public: { query = InternalQuery(std::move(du->query), std::move(du->ids)); downstream = du->downstream; + proxyProtocolPayloadSize = du->proxyProtocolPayloadSize; } ~DoHCrossProtocolQuery() diff --git a/pdns/doh.hh b/pdns/doh.hh index 9a2d12bb4d..de8f67f42d 100644 --- a/pdns/doh.hh +++ b/pdns/doh.hh @@ -221,6 +221,7 @@ struct DOHUnit std::string contentType; std::atomic d_refcnt{1}; size_t query_at{0}; + size_t proxyProtocolPayloadSize{0}; int rsock{-1}; /* the status_code is set from processDOHQuery() (which is executed in