From: Remi Gacogne Date: Mon, 20 Nov 2023 15:21:21 +0000 (+0100) Subject: dnsdist: Allow enabling incoming PROXY protocol on a per-bind basis X-Git-Tag: dnsdist-1.9.0-alpha4~14^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d94e9c3ce8e2e5e24d68018348a30b28fdf673e6;p=thirdparty%2Fpdns.git dnsdist: Allow enabling incoming PROXY protocol on a per-bind basis The per-bind option defaults to `true` as to not break existing configuration, but setting `allowProxyProtocol=false` on a `add*Local()` directive disables proxy-protocol handling for this specific bind. --- diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index faca89bbae..44469c4b23 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -111,12 +111,13 @@ void resetLuaSideEffect() using localbind_t = LuaAssociativeTable, LuaArray, LuaAssociativeTable>>; -static void parseLocalBindVars(boost::optional& vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set& cpus, int& tcpListenQueueSize, uint64_t& maxInFlightQueriesPerConnection, uint64_t& tcpMaxConcurrentConnections) +static void parseLocalBindVars(boost::optional& vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set& cpus, int& tcpListenQueueSize, uint64_t& maxInFlightQueriesPerConnection, uint64_t& tcpMaxConcurrentConnections, bool& allowProxyProtocol) { if (vars) { LuaArray setCpus; getOptionalValue(vars, "reusePort", reusePort); + getOptionalValue(vars, "allowProxyProtocol", allowProxyProtocol); getOptionalValue(vars, "tcpFastOpenQueueSize", tcpFastOpenQueueSize); getOptionalValue(vars, "tcpListenQueueSize", tcpListenQueueSize); getOptionalValue(vars, "maxConcurrentTCPConnections", tcpMaxConcurrentConnections); @@ -723,8 +724,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) uint64_t tcpMaxConcurrentConnections = 0; std::string interface; std::set cpus; + bool allowProxyProtocol = true; - parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections); + parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, allowProxyProtocol); checkAllParametersConsumed("setLocal", vars); @@ -741,8 +743,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) } // only works pre-startup, so no sync necessary - g_frontends.push_back(std::make_unique(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)); - auto tcpCS = std::make_unique(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus); + g_frontends.push_back(std::make_unique(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol)); + auto tcpCS = std::make_unique(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol); if (tcpListenQueueSize > 0) { tcpCS->tcpListenQueueSize = tcpListenQueueSize; } @@ -775,15 +777,16 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) uint64_t tcpMaxConcurrentConnections = 0; std::string interface; std::set cpus; + bool allowProxyProtocol = true; - parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections); + parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, allowProxyProtocol); checkAllParametersConsumed("addLocal", vars); try { ComboAddress loc(addr, 53); // only works pre-startup, so no sync necessary - g_frontends.push_back(std::make_unique(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)); - auto tcpCS = std::make_unique(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus); + g_frontends.push_back(std::make_unique(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol)); + auto tcpCS = std::make_unique(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol); if (tcpListenQueueSize > 0) { tcpCS->tcpListenQueueSize = tcpListenQueueSize; } @@ -1614,8 +1617,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) std::string interface; std::set cpus; std::vector certKeys; + bool allowProxyProtocol = true; - parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections); + parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, allowProxyProtocol); checkAllParametersConsumed("addDNSCryptBind", vars); if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) { @@ -1647,13 +1651,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) auto ctx = std::make_shared(providerName, certKeys); /* UDP */ - auto cs = std::make_unique(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus); + auto cs = std::make_unique(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol); cs->dnscryptCtx = ctx; g_dnsCryptLocals.push_back(ctx); g_frontends.push_back(std::move(cs)); /* TCP */ - cs = std::make_unique(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus); + cs = std::make_unique(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol); cs->dnscryptCtx = std::move(ctx); if (tcpListenQueueSize > 0) { cs->tcpListenQueueSize = tcpListenQueueSize; @@ -2497,9 +2501,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) std::string interface; std::set cpus; std::vector> additionalAddresses; + bool allowProxyProtocol = true; if (vars) { - parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections); + parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, allowProxyProtocol); getOptionalValue(vars, "idleTimeout", frontend->d_idleTimeout); getOptionalValue(vars, "serverTokens", frontend->d_serverTokens); getOptionalValue(vars, "provider", frontend->d_tlsContext.d_provider); @@ -2569,7 +2574,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) } g_dohlocals.push_back(frontend); - auto cs = std::make_unique(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus); + auto cs = std::make_unique(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol); cs->dohFrontend = std::move(frontend); cs->d_additionalAddresses = std::move(additionalAddresses); @@ -2610,9 +2615,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) std::string interface; std::set cpus; std::vector> additionalAddresses; + bool allowProxyProtocol = true; if (vars) { - parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections); + parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, allowProxyProtocol); if (maxInFlightQueriesPerConn > 0) { frontend->d_maxInFlight = maxInFlightQueriesPerConn; } @@ -2649,7 +2655,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) checkAllParametersConsumed("addDOQLocal", vars); } g_doqlocals.push_back(frontend); - auto cs = std::make_unique(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus); + auto cs = std::make_unique(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol); cs->doqFrontend = std::move(frontend); cs->d_additionalAddresses = std::move(additionalAddresses); @@ -2834,9 +2840,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) std::string interface; std::set cpus; std::vector> additionalAddresses; + bool allowProxyProtocol = true; if (vars) { - parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConns); + parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConns, allowProxyProtocol); getOptionalValue(vars, "provider", frontend->d_provider); boost::algorithm::to_lower(frontend->d_provider); @@ -2889,7 +2896,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) vinfolog("Loading default TLS provider '%s'", provider); } // only works pre-startup, so no sync necessary - auto cs = std::make_unique(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus); + auto cs = std::make_unique(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol); cs->tlsFrontend = frontend; cs->d_additionalAddresses = std::move(additionalAddresses); if (tcpListenQueueSize > 0) { diff --git a/pdns/dnsdist-tcp.cc b/pdns/dnsdist-tcp.cc index 53cf163976..f5147ce087 100644 --- a/pdns/dnsdist-tcp.cc +++ b/pdns/dnsdist-tcp.cc @@ -916,7 +916,7 @@ IOState IncomingTCPConnectionState::handleHandshake(const struct timeval& now) DEBUGLOG("handshake done"); handleHandshakeDone(now); - if (!isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) { + if (d_ci.cs != nullptr && d_ci.cs->d_allowProxyProtocol && !isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) { d_state = State::readingProxyProtocolHeader; d_buffer.resize(s_proxyProtocolMinimumHeaderSize); d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize; @@ -955,7 +955,7 @@ void IncomingTCPConnectionState::handleIO() try { if (d_state == State::starting) { - if (isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) { + if (d_ci.cs != nullptr && d_ci.cs->d_allowProxyProtocol && isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) { d_state = State::readingProxyProtocolHeader; d_buffer.resize(s_proxyProtocolMinimumHeaderSize); d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize; diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 77c7f8d3a9..6c5272b89b 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -614,11 +614,11 @@ bool processResponse(PacketBuffer& response, const std::vector dss) setThreadName("dnsdist/respond"); auto localRespRuleActions = g_respruleactions.getLocal(); auto localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal(); - const size_t initialBufferSize = getInitialUDPPacketBufferSize(); + const size_t initialBufferSize = getInitialUDPPacketBufferSize(false); /* allocate one more byte so we can detect truncation */ PacketBuffer response(initialBufferSize + 1); uint16_t queryId = 0; @@ -1223,7 +1223,7 @@ static bool isUDPQueryAcceptable(ClientState& cs, LocalHolders& holders, const s return false; } - expectProxyProtocol = expectProxyProtocolFrom(remote); + expectProxyProtocol = cs.d_allowProxyProtocol && expectProxyProtocolFrom(remote); if (!holders.acl->match(remote) && !expectProxyProtocol) { vinfolog("Query from %s dropped because of ACL", remote.toStringWithPort()); ++dnsdist::metrics::g_stats.aclDrops; @@ -1848,7 +1848,7 @@ static void MultipleMessagesUDPClientThread(ClientState* cs, LocalHolders& holde - we use it for self-generated responses (from rule or cache) but we only accept incoming payloads up to that size */ - const size_t initialBufferSize = getInitialUDPPacketBufferSize(); + const size_t initialBufferSize = getInitialUDPPacketBufferSize(cs->d_allowProxyProtocol); const size_t maxIncomingPacketSize = getMaximumIncomingPacketSize(*cs); /* initialize the structures needed to receive our messages */ @@ -1938,7 +1938,7 @@ static void udpClientThread(std::vector states) size_t maxIncomingPacketSize{0}; int socket{-1}; }; - const size_t initialBufferSize = getInitialUDPPacketBufferSize(); + const size_t initialBufferSize = getInitialUDPPacketBufferSize(true); PacketBuffer packet(initialBufferSize); struct msghdr msgh; @@ -2840,17 +2840,17 @@ static void initFrontends() for (const auto& loc : g_cmdLine.locals) { /* UDP */ - g_frontends.emplace_back(std::make_unique(ComboAddress(loc, 53), false, false, 0, "", std::set{})); + g_frontends.emplace_back(std::make_unique(ComboAddress(loc, 53), false, false, 0, "", std::set{}, true)); /* TCP */ - g_frontends.emplace_back(std::make_unique(ComboAddress(loc, 53), true, false, 0, "", std::set{})); + g_frontends.emplace_back(std::make_unique(ComboAddress(loc, 53), true, false, 0, "", std::set{}, true)); } } if (g_frontends.empty()) { /* UDP */ - g_frontends.emplace_back(std::make_unique(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set{})); + g_frontends.emplace_back(std::make_unique(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set{}, true)); /* TCP */ - g_frontends.emplace_back(std::make_unique(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set{})); + g_frontends.emplace_back(std::make_unique(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set{}, true)); } } diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index aa64c3f0c3..3122776560 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -465,7 +465,7 @@ extern QueryCount g_qcount; struct ClientState { - ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set& cpus_): cpus(cpus_), interface(itfName), local(local_), fastOpenQueueSize(fastOpenQueue), tcp(isTCP_), reuseport(doReusePort) + ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set& cpus_, bool allowProxyProtocol): cpus(cpus_), interface(itfName), local(local_), fastOpenQueueSize(fastOpenQueue), tcp(isTCP_), reuseport(doReusePort), d_allowProxyProtocol(allowProxyProtocol) { } @@ -511,6 +511,7 @@ struct ClientState bool muted{false}; bool tcp; bool reuseport; + bool d_allowProxyProtocol{true}; // the global proxy protocol ACL still applies bool ready{false}; int getSocket() const diff --git a/pdns/dnsdistdist/dnsdist-nghttp2-in.cc b/pdns/dnsdistdist/dnsdist-nghttp2-in.cc index cacf367374..e23eb8b976 100644 --- a/pdns/dnsdistdist/dnsdist-nghttp2-in.cc +++ b/pdns/dnsdistdist/dnsdist-nghttp2-in.cc @@ -307,7 +307,7 @@ IOState IncomingHTTP2Connection::handleHandshake(const struct timeval& now) } } - if (!isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) { + if (d_ci.cs != nullptr && d_ci.cs->d_allowProxyProtocol && !isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) { d_state = State::readingProxyProtocolHeader; d_buffer.resize(s_proxyProtocolMinimumHeaderSize); d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize; @@ -337,7 +337,7 @@ void IncomingHTTP2Connection::handleIO() } if (d_state == State::starting) { - if (isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) { + if (d_ci.cs != nullptr && d_ci.cs->d_allowProxyProtocol && isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) { d_state = State::readingProxyProtocolHeader; d_buffer.resize(s_proxyProtocolMinimumHeaderSize); d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize; diff --git a/pdns/dnsdistdist/docs/reference/config.rst b/pdns/dnsdistdist/docs/reference/config.rst index a88ef4fa56..191bca50b4 100644 --- a/pdns/dnsdistdist/docs/reference/config.rst +++ b/pdns/dnsdistdist/docs/reference/config.rst @@ -83,6 +83,9 @@ Listen Sockets .. versionchanged:: 1.6.0 Added ``maxInFlight`` and ``maxConcurrentTCPConnections`` parameters. + .. versionchanged:: 1.9.0 + Added ``allowProxyProtocol`` parameter, which was always ``true`` before 1.9.0. + Add to the list of listen addresses. Note that for IPv6 link-local addresses, it might be necessary to specify the interface to use: ``fe80::1%eth0``. On recent Linux versions specifying the interface via the ``interface`` parameter should work as well. :param str address: The IP Address with an optional port to listen on. @@ -99,6 +102,7 @@ Listen Sockets * ``tcpListenQueueSize=SOMAXCONN``: int - Set the size of the listen queue. Default is ``SOMAXCONN``. * ``maxInFlight=0``: int - Maximum number of in-flight queries. The default is 0, which disables out-of-order processing. * ``maxConcurrentTCPConnections=0``: int - Maximum number of concurrent incoming TCP connections. The default is 0 which means unlimited. + * ``allowProxyProtocol=true``: str - Whether to allow a proxy protocol v2 header in front of incoming queries. Both this option and :func:`setProxyProtocolACL` needs to agree for a payload to be accepted. Default is ``true``, meaning that queries are allowed if they come from an address present in the :func:`setProxyProtocolACL` ACL. .. code-block:: lua @@ -123,7 +127,7 @@ Listen Sockets ``additionalAddresses``, ``ignoreTLSConfigurationErrors`` and ``keepIncomingHeaders`` options added. .. versionchanged:: 1.9.0 - ``library``, ``readAhead`` and ``proxyProtocolOutsideTLS`` options added. + ``allowProxyProtocol``, ``library``, ``readAhead`` and ``proxyProtocolOutsideTLS`` options added. Listen on the specified address and TCP port for incoming DNS over HTTPS connections, presenting the specified X.509 certificate. If no certificate (or key) files are specified, listen for incoming DNS over HTTP connections instead. @@ -170,6 +174,7 @@ Listen Sockets * ``library``: str - Which underlying HTTP2 library should be used, either h2o or nghttp2. Until 1.9.0 only h2o was available, but the use of this library is now deprecated as it is no longer maintained. nghttp2 is the new default since 1.9.0. * ``readAhead``: bool - When the TLS provider is set to OpenSSL, whether we tell the library to read as many input bytes as possible, which leads to better performance by reducing the number of syscalls. Default is true. * ``proxyProtocolOutsideTLS``: bool - When the use of incoming proxy protocol is enabled, whether the payload is prepended after the start of the TLS session (so inside, meaning it is protected by the TLS layer providing encryption and authentication) or not (outside, meaning it is in clear-text). Default is false which means inside. Note that most third-party software like HAproxy expect the proxy protocol payload to be outside, in clear-text. + * ``allowProxyProtocol=true``: str - Whether to allow a proxy protocol v2 header in front of incoming queries. Both this option and :func:`setProxyProtocolACL` needs to agree for a payload to be accepted. Default is ``true``, meaning that queries are allowed if they come from an address present in the :func:`setProxyProtocolACL` ACL. .. function:: addDOQLocal(address, certFile(s), keyFile(s) [, options]) @@ -208,7 +213,7 @@ Listen Sockets ``certFile`` now accepts a TLSCertificate object or a list of such objects (see :func:`newTLSCertificate`). ``additionalAddresses``, ``ignoreTLSConfigurationErrors`` and ``ktls`` options added. .. versionchanged:: 1.9.0 - ``readAhead`` and ``proxyProtocolOutsideTLS`` options added. + ``allowProxyProtocol``, ``readAhead`` and ``proxyProtocolOutsideTLS`` options added. Listen on the specified address and TCP port for incoming DNS over TLS connections, presenting the specified X.509 certificate. @@ -248,6 +253,7 @@ Listen Sockets * ``ktls=false``: bool - Whether to enable the experimental kernel TLS support on Linux, if both the kernel and the OpenSSL library support it. Default is false. * ``readAhead``: bool - When the TLS provider is set to OpenSSL, whether we tell the library to read as many input bytes as possible, which leads to better performance by reducing the number of syscalls. Default is true. * ``proxyProtocolOutsideTLS``: bool - When the use of incoming proxy protocol is enabled, whether the payload is prepended after the start of the TLS session (so inside, meaning it is protected by the TLS layer providing encryption and authentication) or not (outside, meaning it is in clear-text). Default is false which means inside. Note that most third-party software like HAproxy expect the proxy protocol payload to be outside, in clear-text. + * ``allowProxyProtocol=true``: str - Whether to allow a proxy protocol v2 header in front of incoming queries. Both this option and :func:`setProxyProtocolACL` needs to agree for a payload to be accepted. Default is ``true``, meaning that queries are allowed if they come from an address present in the :func:`setProxyProtocolACL` ACL. .. function:: setLocal(address[, options]) diff --git a/pdns/dnsdistdist/test-dnsdistnghttp2-in_cc.cc b/pdns/dnsdistdist/test-dnsdistnghttp2-in_cc.cc index 49a891d856..3fa1eaae05 100644 --- a/pdns/dnsdistdist/test-dnsdistnghttp2-in_cc.cc +++ b/pdns/dnsdistdist/test-dnsdistnghttp2-in_cc.cc @@ -479,7 +479,7 @@ private: BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, 0, "", {}); + ClientState localCS(local, true, false, 0, "", {}, true); localCS.dohFrontend = std::make_shared(std::make_shared()); localCS.dohFrontend->d_urls.insert("/dns-query"); @@ -667,7 +667,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture) BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendTimeout, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, 0, "", {}); + ClientState localCS(local, true, false, 0, "", {}, true); localCS.dohFrontend = std::make_shared(std::make_shared()); localCS.dohFrontend->d_urls.insert("/dns-query"); diff --git a/pdns/dnsdistdist/test-dnsdistnghttp2_cc.cc b/pdns/dnsdistdist/test-dnsdistnghttp2_cc.cc index 50222414a2..b5aa47e816 100644 --- a/pdns/dnsdistdist/test-dnsdistnghttp2_cc.cc +++ b/pdns/dnsdistdist/test-dnsdistnghttp2_cc.cc @@ -557,7 +557,7 @@ struct TestFixture BOOST_FIXTURE_TEST_CASE(test_SingleQuery, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -633,7 +633,7 @@ BOOST_FIXTURE_TEST_CASE(test_SingleQuery, TestFixture) BOOST_FIXTURE_TEST_CASE(test_ConcurrentQueries, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -722,7 +722,7 @@ BOOST_FIXTURE_TEST_CASE(test_ConcurrentQueries, TestFixture) BOOST_FIXTURE_TEST_CASE(test_ConnectionReuse, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -830,7 +830,7 @@ BOOST_FIXTURE_TEST_CASE(test_ConnectionReuse, TestFixture) BOOST_FIXTURE_TEST_CASE(test_InvalidDNSAnswer, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -911,7 +911,7 @@ BOOST_FIXTURE_TEST_CASE(test_InvalidDNSAnswer, TestFixture) BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileWriting, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -998,7 +998,7 @@ BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileWriting, TestFixture) BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileReading, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1085,7 +1085,7 @@ BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileReading, TestFixture) BOOST_FIXTURE_TEST_CASE(test_ShortWrite, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1172,7 +1172,7 @@ BOOST_FIXTURE_TEST_CASE(test_ShortWrite, TestFixture) BOOST_FIXTURE_TEST_CASE(test_ShortRead, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1266,7 +1266,7 @@ BOOST_FIXTURE_TEST_CASE(test_ShortRead, TestFixture) BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileReading, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1352,7 +1352,7 @@ BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileReading, TestFixture) BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileWriting, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1446,7 +1446,7 @@ BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileWriting, TestFixture) BOOST_FIXTURE_TEST_CASE(test_GoAwayFromServer, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1557,7 +1557,7 @@ BOOST_FIXTURE_TEST_CASE(test_GoAwayFromServer, TestFixture) BOOST_FIXTURE_TEST_CASE(test_HTTP500FromServer, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1650,7 +1650,7 @@ BOOST_FIXTURE_TEST_CASE(test_HTTP500FromServer, TestFixture) BOOST_FIXTURE_TEST_CASE(test_WrongStreamID, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1750,7 +1750,7 @@ BOOST_FIXTURE_TEST_CASE(test_WrongStreamID, TestFixture) BOOST_FIXTURE_TEST_CASE(test_ProxyProtocol, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); tlsCtx->d_needProxyProtocol = true; localCS.tlsFrontend = std::make_shared(tlsCtx); diff --git a/pdns/dnsdistdist/test-dnsdisttcp_cc.cc b/pdns/dnsdistdist/test-dnsdisttcp_cc.cc index eacadf0401..d4d6089c77 100644 --- a/pdns/dnsdistdist/test-dnsdisttcp_cc.cc +++ b/pdns/dnsdistdist/test-dnsdisttcp_cc.cc @@ -488,7 +488,7 @@ static void testInit(const std::string& name, TCPClientThreadData& threadData) BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -735,7 +735,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture) BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -865,7 +865,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); auto tlsCtx = std::make_shared(); localCS.tlsFrontend = std::make_shared(tlsCtx); @@ -1765,7 +1765,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture) BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); /* enable out-of-order on the front side */ localCS.d_maxInFlightQueriesPerConn = 65536; @@ -3905,7 +3905,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture) BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR, TestFixture) { auto local = getBackendAddress("1", 80); - ClientState localCS(local, true, false, false, "", {}); + ClientState localCS(local, true, false, false, "", {}, true); /* enable out-of-order on the front side */ localCS.d_maxInFlightQueriesPerConn = 65536; diff --git a/regression-tests.dnsdist/test_ProxyProtocol.py b/regression-tests.dnsdist/test_ProxyProtocol.py index 1a42d92109..59752e9479 100644 --- a/regression-tests.dnsdist/test_ProxyProtocol.py +++ b/regression-tests.dnsdist/test_ProxyProtocol.py @@ -824,6 +824,74 @@ class TestProxyProtocolNotExpected(DNSDistTest): print('timeout') self.assertEqual(receivedResponse, None) +class TestProxyProtocolNotAllowedOnBind(DNSDistTest): + """ + dnsdist is configured to expect a Proxy Protocol header on incoming queries but not on the 127.0.0.1 bind + """ + _skipListeningOnCL = True + _config_template = """ + -- proxy protocol payloads are not allowed on this bind address! + addLocal('127.0.0.1:%d', {allowProxyProtocol=false}) + setProxyProtocolACL( { "127.0.0.1/8" } ) + newServer{address="127.0.0.1:%d"} + """ + # NORMAL responder, does not expect a proxy protocol payload! + _config_params = ['_dnsDistPort', '_testServerPort'] + + def testNoHeader(self): + """ + Unexpected Proxy Protocol: no header + """ + # no proxy protocol header and none is expected from this source, should be passed on + name = 'no-header.unexpected-proxy-protocol.tests.powerdns.com.' + query = dns.message.make_query(name, 'A', 'IN') + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + 60, + dns.rdataclass.IN, + dns.rdatatype.A, + '127.0.0.1') + + response.answer.append(rrset) + + for method in ("sendUDPQuery", "sendTCPQuery"): + sender = getattr(self, method) + (receivedQuery, receivedResponse) = sender(query, response) + receivedQuery.id = query.id + self.assertEqual(query, receivedQuery) + self.assertEqual(response, receivedResponse) + + def testIncomingProxyDest(self): + """ + Unexpected Proxy Protocol: should be dropped + """ + name = 'with-proxy-payload.unexpected-protocol-incoming.tests.powerdns.com.' + query = dns.message.make_query(name, 'A', 'IN') + + # Make sure that the proxy payload does NOT turn into a legal qname + destAddr = "ff:db8::ffff" + destPort = 65535 + srcAddr = "ff:db8::ffff" + srcPort = 65535 + + udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ]) + (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True) + self.assertEqual(receivedResponse, None) + + tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ]) + wire = query.to_wire() + + receivedResponse = None + try: + conn = self.openTCPConnection(2.0) + conn.send(tcpPayload) + conn.send(struct.pack("!H", len(wire))) + conn.send(wire) + receivedResponse = self.recvTCPResponseOverConnection(conn) + except socket.timeout: + print('timeout') + self.assertEqual(receivedResponse, None) + class TestDOHWithOutgoingProxyProtocol(DNSDistDOHTest): _serverKey = 'server.key'