diff -ru dnsdist-2.0.2.orig/dnsdist-doh-common.hh dnsdist-2.0.2/dnsdist-doh-common.hh --- dnsdist-2.0.2.orig/dnsdist-doh-common.hh 2025-11-27 14:25:28.000000000 +0100 +++ dnsdist-2.0.2/dnsdist-doh-common.hh 2026-02-23 15:06:00.549271733 +0100 @@ -36,6 +36,7 @@ namespace dnsdist::doh { static constexpr uint32_t MAX_INCOMING_CONCURRENT_STREAMS{100U}; +static constexpr size_t MAX_INCOMING_HTTP_HEADERS{256U}; std::optional getPayloadFromPath(const std::string_view& path); } diff -ru dnsdist-2.0.2.orig/dnsdist-nghttp2-in.cc dnsdist-2.0.2/dnsdist-nghttp2-in.cc --- dnsdist-2.0.2.orig/dnsdist-nghttp2-in.cc 2025-11-27 14:25:28.000000000 +0100 +++ dnsdist-2.0.2/dnsdist-nghttp2-in.cc 2026-02-23 15:06:00.549711969 +0100 @@ -1136,6 +1136,11 @@ if (!query.d_headers) { query.d_headers = std::make_unique(); } + if (query.d_headers->size() >= dnsdist::doh::MAX_INCOMING_HTTP_HEADERS) { + /* be nice but not too nice */ + vinfolog("Too many incoming DoH headers"); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): nghttp2 API query.d_headers->insert({std::string(reinterpret_cast(name), nameLen), std::string(valueView)}); } Only in dnsdist-2.0.2: dnsdist-nghttp2-in.cc.orig diff -ru dnsdist-2.0.2.orig/doh3.cc dnsdist-2.0.2/doh3.cc --- dnsdist-2.0.2.orig/doh3.cc 2025-11-27 14:25:28.000000000 +0100 +++ dnsdist-2.0.2/doh3.cc 2026-02-23 15:07:40.792417033 +0100 @@ -732,6 +732,10 @@ std::string_view content(reinterpret_cast(value), value_len); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API auto* headersptr = reinterpret_cast(argp); + if (headersptr->size() >= dnsdist::doh::MAX_INCOMING_HTTP_HEADERS) { + /* be nice but not too nice */ + return 1; + } headersptr->emplace(key, content); return 0; }, @@ -818,6 +822,13 @@ break; } + if (len > std::numeric_limits::max() || (std::numeric_limits::max() - streamBuffer.size()) < static_cast(len)) { + vinfolog("DOH3 data frame of size %d is too large for a DNS query (we already have %d)", len, streamBuffer.size()); + conn.d_streamBuffers.erase(streamID); + handleImmediateError("DoH3 non-compliant query"); + return; + } + buffer.resize(static_cast(len)); streamBuffer.insert(streamBuffer.end(), buffer.begin(), buffer.end()); } @@ -850,11 +861,13 @@ if (streamID < 0) { break; } + std::unique_ptr eventPtr(event, quiche_h3_event_free); + event = nullptr; conn.d_headersBuffers.try_emplace(streamID, dnsdist::doh3::h3_headers_t{}); - switch (quiche_h3_event_type(event)) { + switch (quiche_h3_event_type(eventPtr.get())) { case QUICHE_H3_EVENT_HEADERS: { - processH3HeaderEvent(clientState, frontend, conn, client, serverConnID, streamID, event); + processH3HeaderEvent(clientState, frontend, conn, client, serverConnID, streamID, eventPtr.get()); break; } case QUICHE_H3_EVENT_DATA: { @@ -867,8 +880,6 @@ case QUICHE_H3_EVENT_GOAWAY: break; } - - quiche_h3_event_free(event); } } Only in dnsdist-2.0.2: doh3.cc.orig diff -ru dnsdist-2.0.2.orig/doh.cc dnsdist-2.0.2/doh.cc --- dnsdist-2.0.2.orig/doh.cc 2025-11-27 14:25:28.000000000 +0100 +++ dnsdist-2.0.2/doh.cc 2026-02-23 15:06:00.550339303 +0100 @@ -964,6 +964,12 @@ if (dsc->dohFrontend->d_keepIncomingHeaders) { dohUnit->headers = std::make_unique>(); + if (req->headers.size >= dnsdist::doh::MAX_INCOMING_HTTP_HEADERS) { + /* be nice but not too nice */ + vinfolog("Too many incoming DoH headers"); + h2o_send_error_400(req, "Bad Request", "The DNS query had too many HTTP headers", 0); + return; + } dohUnit->headers->reserve(req->headers.size); for (size_t i = 0; i < req->headers.size; ++i) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API Only in dnsdist-2.0.2: doh.cc.orig diff -ru dnsdist-2.0.2.orig/doq.cc dnsdist-2.0.2/doq.cc --- dnsdist-2.0.2.orig/doq.cc 2025-11-27 14:25:28.000000000 +0100 +++ dnsdist-2.0.2/doq.cc 2026-02-23 15:06:00.551842080 +0100 @@ -640,6 +640,15 @@ return; } + if (received > std::numeric_limits::max() || (std::numeric_limits::max() - streamBuffer.size()) < static_cast(received)) { + vinfolog("DoQ data frame of size %d is too large for a DNS query (we already have %d)", received, streamBuffer.size()); + conn.d_streamBuffers.erase(streamID); + ++dnsdist::metrics::g_stats.nonCompliantQueries; + ++clientState.nonCompliantQueries; + quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast(DOQ_Error_Codes::DOQ_PROTOCOL_ERROR)); + return; + } + streamBuffer.resize(existingLength + received); if (fin) { break; Only in dnsdist-2.0.2: doq.cc.orig