using localbind_t = LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int>, LuaArray<std::string>, LuaAssociativeTable<std::string>>>;
-static void parseLocalBindVars(boost::optional<localbind_t>& vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus, int& tcpListenQueueSize, uint64_t& maxInFlightQueriesPerConnection, uint64_t& tcpMaxConcurrentConnections)
+static void parseLocalBindVars(boost::optional<localbind_t>& vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus, int& tcpListenQueueSize, uint64_t& maxInFlightQueriesPerConnection, uint64_t& tcpMaxConcurrentConnections, bool& allowProxyProtocol)
{
if (vars) {
LuaArray<int> setCpus;
getOptionalValue<bool>(vars, "reusePort", reusePort);
+ getOptionalValue<bool>(vars, "allowProxyProtocol", allowProxyProtocol);
getOptionalValue<int>(vars, "tcpFastOpenQueueSize", tcpFastOpenQueueSize);
getOptionalValue<int>(vars, "tcpListenQueueSize", tcpListenQueueSize);
getOptionalValue<int>(vars, "maxConcurrentTCPConnections", tcpMaxConcurrentConnections);
uint64_t tcpMaxConcurrentConnections = 0;
std::string interface;
std::set<int> 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);
}
// only works pre-startup, so no sync necessary
- g_frontends.push_back(std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus));
- auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ g_frontends.push_back(std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol));
+ auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
uint64_t tcpMaxConcurrentConnections = 0;
std::string interface;
std::set<int> 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<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus));
- auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ g_frontends.push_back(std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol));
+ auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
std::string interface;
std::set<int> cpus;
std::vector<DNSCryptContext::CertKeyPaths> 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)) {
auto ctx = std::make_shared<DNSCryptContext>(providerName, certKeys);
/* UDP */
- auto cs = std::make_unique<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ auto cs = std::make_unique<ClientState>(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<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ cs = std::make_unique<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol);
cs->dnscryptCtx = std::move(ctx);
if (tcpListenQueueSize > 0) {
cs->tcpListenQueueSize = tcpListenQueueSize;
std::string interface;
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> 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<int>(vars, "idleTimeout", frontend->d_idleTimeout);
getOptionalValue<std::string>(vars, "serverTokens", frontend->d_serverTokens);
getOptionalValue<std::string>(vars, "provider", frontend->d_tlsContext.d_provider);
}
g_dohlocals.push_back(frontend);
- auto cs = std::make_unique<ClientState>(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ auto cs = std::make_unique<ClientState>(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol);
cs->dohFrontend = std::move(frontend);
cs->d_additionalAddresses = std::move(additionalAddresses);
std::string interface;
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> 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;
}
checkAllParametersConsumed("addDOQLocal", vars);
}
g_doqlocals.push_back(frontend);
- auto cs = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ auto cs = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol);
cs->doqFrontend = std::move(frontend);
cs->d_additionalAddresses = std::move(additionalAddresses);
std::string interface;
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> 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<std::string>(vars, "provider", frontend->d_provider);
boost::algorithm::to_lower(frontend->d_provider);
vinfolog("Loading default TLS provider '%s'", provider);
}
// only works pre-startup, so no sync necessary
- auto cs = std::make_unique<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ auto cs = std::make_unique<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, allowProxyProtocol);
cs->tlsFrontend = frontend;
cs->d_additionalAddresses = std::move(additionalAddresses);
if (tcpListenQueueSize > 0) {
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;
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;
return processResponseAfterRules(response, cacheInsertedRespRuleActions, dr, muted);
}
-static size_t getInitialUDPPacketBufferSize()
+static size_t getInitialUDPPacketBufferSize(bool expectProxyProtocol)
{
static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
- if (g_proxyProtocolACL.empty()) {
+ if (!expectProxyProtocol || g_proxyProtocolACL.empty()) {
return s_initialUDPPacketBufferSize;
}
static size_t getMaximumIncomingPacketSize(const ClientState& cs)
{
if (cs.dnscryptCtx) {
- return getInitialUDPPacketBufferSize();
+ return getInitialUDPPacketBufferSize(cs.d_allowProxyProtocol);
}
- if (g_proxyProtocolACL.empty()) {
+ if (!cs.d_allowProxyProtocol || g_proxyProtocolACL.empty()) {
return s_udpIncomingBufferSize;
}
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;
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;
- 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 */
size_t maxIncomingPacketSize{0};
int socket{-1};
};
- const size_t initialBufferSize = getInitialUDPPacketBufferSize();
+ const size_t initialBufferSize = getInitialUDPPacketBufferSize(true);
PacketBuffer packet(initialBufferSize);
struct msghdr msgh;
for (const auto& loc : g_cmdLine.locals) {
/* UDP */
- g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}));
+ g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}, true));
/* TCP */
- g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}));
+ g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}, true));
}
}
if (g_frontends.empty()) {
/* UDP */
- g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}));
+ g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}, true));
/* TCP */
- g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}));
+ g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}, true));
}
}
struct ClientState
{
- ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& 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<int>& cpus_, bool allowProxyProtocol): cpus(cpus_), interface(itfName), local(local_), fastOpenQueueSize(fastOpenQueue), tcp(isTCP_), reuseport(doReusePort), d_allowProxyProtocol(allowProxyProtocol)
{
}
bool muted{false};
bool tcp;
bool reuseport;
+ bool d_allowProxyProtocol{true}; // the global proxy protocol ACL still applies
bool ready{false};
int getSocket() const
}
}
- 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;
}
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;
.. 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.
* ``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
``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.
* ``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])
``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.
* ``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])
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<DOHFrontend>(std::make_shared<MockupTLSCtx>());
localCS.dohFrontend->d_urls.insert("/dns-query");
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<DOHFrontend>(std::make_shared<MockupTLSCtx>());
localCS.dohFrontend->d_urls.insert("/dns-query");
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
tlsCtx->d_needProxyProtocol = true;
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
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;
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;
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'