ednscookies.cc ednscookies.hh \
ednsextendederror.cc ednsextendederror.hh \
ednsoptions.cc ednsoptions.hh \
+ ednspadding.cc ednspadding.hh \
ednssubnet.cc ednssubnet.hh \
ext/json11/json11.cpp \
ext/json11/json11.hpp \
ednscookies.cc ednscookies.hh \
ednsextendederror.cc ednsextendederror.hh \
ednsoptions.cc ednsoptions.hh \
+ ednspadding.cc ednspadding.hh \
ednssubnet.cc ednssubnet.hh \
ext/json11/json11.cpp \
ext/json11/json11.hpp \
dnswriter.cc dnswriter.hh \
dolog.cc dolog.hh \
ednsoptions.cc ednsoptions.hh \
+ ednspadding.cc ednspadding.hh \
ednssubnet.cc ednssubnet.hh \
ext/json11/json11.cpp \
ext/json11/json11.hpp \
std::shared_ptr<DNSCryptContext> dnsCryptContext;
#endif /* defined(HAVE_DNSCRYPT) */
- auto state = std::make_shared<ClientState>(listeningAddress, protocol != "doq" && protocol != "doh3", bind.reuseport, bind.tcp.fast_open_queue_size, std::string(bind.interface), cpus, bind.enable_proxy_protocol);
+ auto state = std::make_shared<ClientState>(listeningAddress, protocol != "doq" && protocol != "doh3", bind.reuseport, bind.tcp.fast_open_queue_size, std::string(bind.interface), cpus, bind.enable_proxy_protocol, bind.pad_responses);
if (bind.tcp.listen_queue_size > 0) {
state->tcpListenQueueSize = bind.tcp.listen_queue_size;
config.d_frontends.emplace_back(std::move(state));
if (protocol == "do53" || protocol == "dnscrypt") {
/* also create the UDP listener */
- state = std::make_shared<ClientState>(ComboAddress(std::string(bind.listen_address), defaultPort), false, bind.reuseport, bind.tcp.fast_open_queue_size, std::string(bind.interface), cpus, bind.enable_proxy_protocol);
+ state = std::make_shared<ClientState>(ComboAddress(std::string(bind.listen_address), defaultPort), false, bind.reuseport, bind.tcp.fast_open_queue_size, std::string(bind.interface), cpus, bind.enable_proxy_protocol, bind.pad_responses);
#if defined(HAVE_DNSCRYPT)
state->dnscryptCtx = std::move(dnsCryptContext);
#endif /* defined(HAVE_DNSCRYPT) */
#include "dnsdist-ecs.hh"
#include "dnsdist-edns.hh"
#include "ednsoptions.hh"
+#include "ednspadding.hh"
#include "ednsextendederror.hh"
namespace dnsdist::edns
std::string edeOption;
generateEDNSOption(EDNSOptionCode::EXTENDEDERROR, edeOptionPayload, edeOption);
+ PacketBuffer newContent;
+ bool ednsAdded = false;
+ bool edeAdded = false;
+ if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::EXTENDEDERROR, edeAdded, setErrorOp.clearExisting, !setErrorOp.clearExisting, edeOption)) {
+ return false;
+ }
+
+ if (newContent.size() > maximumPacketSize) {
+ return false;
+ }
+
+ packet = std::move(newContent);
+ return true;
+}
+
+bool addEDNSPadding(PacketBuffer& packet, size_t maximumPacketSize)
+{
+ uint16_t optStart = 0;
+ size_t optLen = 0;
+ bool last = false;
+
+ int res = locateEDNSOptRR(packet, &optStart, &optLen, &last);
+
+ if (res != 0) {
+ /* no EDNS OPT record in the response, something is not right */
+ return false;
+ }
+
+ if (isEDNSOptionInOpt(packet, optStart, optLen, EDNSOptionCode::PADDING)) {
+ /* padding is already present, exit */
+ return false;
+ }
+
+ if (packet.size() < maximumPacketSize - 4) {
+ return true;
+ }
+
+ size_t remaining = maximumPacketSize - (packet.size() + 4);
+
+ const size_t blockSize = 468;
+ size_t modulo = (packet.size() + 4) % blockSize;
+ size_t padSize = 0;
+ if (modulo > 0) {
+ padSize = std::min(blockSize - modulo, remaining);
+ }
+
+ std::string paddingPayload = makeEDNSPaddingOptString(padSize);
+ std::string padding;
+ generateEDNSOption(EDNSOptionCode::PADDING, paddingPayload, padding);
+
/* we might have one record after the OPT one, we need to rewrite
the whole packet because of compression */
PacketBuffer newContent;
bool ednsAdded = false;
bool edeAdded = false;
- if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::EXTENDEDERROR, edeAdded, setErrorOp.clearExisting, !setErrorOp.clearExisting, edeOption)) {
+ if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::PADDING, edeAdded, true, false, padding)) {
return false;
}
std::pair<std::optional<uint16_t>, std::optional<std::string>> getExtendedDNSError(const PacketBuffer& packet);
bool addExtendedDNSError(PacketBuffer& packet, size_t maximumPacketSize, const SetExtendedDNSErrorOperation& setErrorOp);
+bool addEDNSPadding(PacketBuffer& packet, size_t maximumPacketSize);
}
}
// only works pre-startup, so no sync necessary
- auto udpCS = std::make_shared<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
- auto tcpCS = std::make_shared<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto udpCS = std::make_shared<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, false);
+ auto tcpCS = std::make_shared<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, false);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
try {
ComboAddress loc(addr, 53);
// only works pre-startup, so no sync necessary
- auto udpCS = std::make_shared<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
- auto tcpCS = std::make_shared<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto udpCS = std::make_shared<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, false);
+ auto tcpCS = std::make_shared<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, false);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
auto ctx = std::make_shared<DNSCryptContext>(providerName, certKeys);
/* UDP */
- auto clientState = std::make_shared<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto clientState = std::make_shared<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, false);
clientState->dnscryptCtx = ctx;
dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
});
/* TCP */
- clientState = std::make_shared<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState = std::make_shared<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, false);
clientState->dnscryptCtx = std::move(ctx);
if (tcpListenQueueSize > 0) {
clientState->tcpListenQueueSize = tcpListenQueueSize;
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> additionalAddresses;
bool enableProxyProtocol = true;
+ bool padResponses = false;
if (vars) {
parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
getOptionalValue<std::string>(vars, "provider", frontend->d_tlsContext->d_provider);
boost::algorithm::to_lower(frontend->d_tlsContext->d_provider);
getOptionalValue<bool>(vars, "proxyProtocolOutsideTLS", frontend->d_tlsContext->d_proxyProtocolOutsideTLS);
+ getOptionalValue<bool>(vars, "padResponses", padResponses);
LuaAssociativeTable<std::string> customResponseHeaders;
if (getOptionalValue<decltype(customResponseHeaders)>(vars, "customResponseHeaders", customResponseHeaders) > 0) {
}
}
- auto clientState = std::make_shared<ClientState>(frontend->d_tlsContext->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto clientState = std::make_shared<ClientState>(frontend->d_tlsContext->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, padResponses);
clientState->dohFrontend = std::move(frontend);
clientState->d_additionalAddresses = std::move(additionalAddresses);
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> additionalAddresses;
bool enableProxyProtocol = true;
+ bool padResponses = false;
if (vars) {
parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
getOptionalValue<int>(vars, "internalPipeBufferSize", frontend->d_internalPipeBufferSize);
getOptionalValue<int>(vars, "idleTimeout", frontend->d_quicheParams.d_idleTimeout);
getOptionalValue<std::string>(vars, "keyLogFile", frontend->d_quicheParams.d_keyLogFile);
+ getOptionalValue<bool>(vars, "padResponses", padResponses);
{
std::string valueStr;
if (getOptionalValue<std::string>(vars, "congestionControlAlgo", valueStr) > 0) {
checkAllParametersConsumed("addDOH3Local", vars);
}
- auto clientState = std::make_shared<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto clientState = std::make_shared<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, padResponses);
clientState->doh3Frontend = std::move(frontend);
clientState->d_additionalAddresses = std::move(additionalAddresses);
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> additionalAddresses;
bool enableProxyProtocol = true;
+ bool padResponses = false;
if (vars) {
parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
getOptionalValue<int>(vars, "internalPipeBufferSize", frontend->d_internalPipeBufferSize);
getOptionalValue<int>(vars, "idleTimeout", frontend->d_quicheParams.d_idleTimeout);
getOptionalValue<std::string>(vars, "keyLogFile", frontend->d_quicheParams.d_keyLogFile);
+ getOptionalValue<bool>(vars, "padResponses", padResponses);
{
std::string valueStr;
if (getOptionalValue<std::string>(vars, "congestionControlAlgo", valueStr) > 0) {
checkAllParametersConsumed("addDOQLocal", vars);
}
- auto clientState = std::make_shared<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto clientState = std::make_shared<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, padResponses);
clientState->doqFrontend = std::move(frontend);
clientState->d_additionalAddresses = std::move(additionalAddresses);
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> additionalAddresses;
bool enableProxyProtocol = true;
+ bool padResponses = false;
if (vars) {
parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConns, enableProxyProtocol);
getOptionalValue<std::string>(vars, "provider", frontend->d_provider);
boost::algorithm::to_lower(frontend->d_provider);
getOptionalValue<bool>(vars, "proxyProtocolOutsideTLS", frontend->d_proxyProtocolOutsideTLS);
+ getOptionalValue<bool>(vars, "padResponses", padResponses);
LuaArray<std::string> addresses;
if (getOptionalValue<decltype(addresses)>(vars, "additionalAddresses", addresses) > 0) {
getLogger("addTLSLocal")->info(Logr::Info, "Loading default TLS provider for DoT frontend", "frontend.address", Logging::Loggable(addr), "tls.provider", Logging::Loggable(provider)));
}
// only works pre-startup, so no sync necessary
- auto clientState = std::make_shared<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto clientState = std::make_shared<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol, padResponses);
clientState->tlsFrontend = std::move(frontend);
clientState->d_additionalAddresses = std::move(additionalAddresses);
if (tcpListenQueueSize > 0) {
type: "bool"
default: "true"
description: "Whether to expect a proxy protocol v2 header in front of incoming queries coming from an address allowed by the ACL in :ref:`yaml-settings-ProxyProtocolConfiguration`. Default is ``true``, meaning that queries are expected to have a proxy protocol payload if they come from an address present in the proxy protocol ACL"
+ - name: "pad_responses"
+ type: "bool"
+ default: "false"
+ description: "Whether to pad DNS responses as specified in RFC 7830."
- name: "tcp"
type: "IncomingTcpConfiguration"
default: true
}
}
+ if (dnsResponse.ids.cs->d_padResponses && !dnsResponse.ids.ednsAdded) {
+ dnsdist::edns::addEDNSPadding(dnsResponse.getMutableData(), dnsResponse.getMaximumSize());
+ }
+
#ifdef HAVE_DNSCRYPT
if (!muted) {
if (!encryptResponse(response, dnsResponse.getMaximumSize(), dnsResponse.overTCP(), dnsResponse.ids.dnsCryptQuery)) {
}
}
+ if (dnsResponse.ids.cs->d_padResponses && !dnsResponse.ids.ednsAdded) {
+ dnsdist::edns::addEDNSPadding(dnsResponse.getMutableData(), dnsResponse.getMaximumSize());
+ }
+
if (cacheHit) {
++dnsdist::metrics::g_stats.cacheHits;
}
for (const auto& loc : cmdLine.locals) {
/* UDP */
- frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}, true));
+ frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}, true, false));
/* TCP */
- frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}, true));
+ frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}, true, false));
}
}
if (frontends.empty()) {
/* UDP */
- frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}, true));
+ frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}, true, false));
/* TCP */
- frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}, true));
+ frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}, true, false));
}
dnsdist::configuration::updateImmutableConfiguration([&frontends](dnsdist::configuration::ImmutableConfiguration& config) {
struct ClientState
{
- ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_, bool enableProxyProtocol) :
- cpus(cpus_), interface(itfName), local(local_), fastOpenQueueSize(fastOpenQueue), tcp(isTCP_), reuseport(doReusePort), d_enableProxyProtocol(enableProxyProtocol)
+ ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_, bool enableProxyProtocol, bool padResponses) :
+ cpus(cpus_), interface(itfName), local(local_), fastOpenQueueSize(fastOpenQueue), tcp(isTCP_), reuseport(doReusePort), d_enableProxyProtocol(enableProxyProtocol), d_padResponses(padResponses)
{
}
bool tcp;
bool reuseport;
bool d_enableProxyProtocol{true}; // the global proxy protocol ACL still applies
+ bool d_padResponses{false};
bool ready{false};
int getSocket() const
.. versionchanged:: 1.9.0
``enableProxyProtocol``, ``ktls``, ``library``, ``proxyProtocolOutsideTLS``, ``readAhead``, ``tlsAsyncMode`` options added.
+ .. versionchanged:: 2.2.0
+ ``padResponses`` option added.
+
Listen on the specified address and TCP port for incoming DNS over HTTPS connections, presenting the specified X.509 certificate. See :doc:`../advanced/tls-certificates-management` for details about the handling of TLS certificates and keys.
If no certificate (or key) files are specified, listen for incoming DNS over HTTP connections instead.
More information is available in :doc:`../guides/dns-over-https`.
* ``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.
* ``enableProxyProtocol=true``: bool - Whether to expect a proxy protocol v2 header in front of incoming queries coming from an address in :func:`setProxyProtocolACL`. Default is ``true``, meaning that queries are expected to have a proxy protocol payload if they come from an address present in the :func:`setProxyProtocolACL` ACL.
+ * ``padResponses``: bool - Whether to pad DNS responses as specified in RFC 7830. Default is ``false``, meaning responses are not padded.
.. function:: addDOH3Local(address, certFile(s), keyFile(s) [, options])
.. versionchanged:: 2.1.0
The default congestion algorithm used to be ``reno`` and is now ``cubic``.
+ .. versionchanged:: 2.2.0
+ ``padResponses`` option added.
+
Listen on the specified address and UDP port for incoming DNS over HTTP3 connections, presenting the specified X.509 certificate. See :doc:`../advanced/tls-certificates-management` for details about the handling of TLS certificates and keys.
More information is available in :doc:`../guides/dns-over-http3`.
* ``maxInFlight=65535``: int - Maximum number of in-flight queries. The default is 0, which disables out-of-order processing.
* ``congestionControlAlgo="cubic"``: str - The congestion control algorithm to be chosen between ``reno``, ``cubic`` and ``bbr``.
* ``keyLogFile``: str - Write the TLS keys in the specified file so that an external program can decrypt TLS exchanges, in the format described in https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+ * ``padResponses``: bool - Whether to pad DNS responses as specified in RFC 7830. Default is ``false``, meaning responses are not padded.
.. function:: addDOQLocal(address, certFile(s), keyFile(s) [, options])
.. versionchanged:: 2.1.0
The default congestion algorithm used to be ``reno`` and is now ``cubic``.
+ .. versionchanged:: 2.2.0
+ ``padResponses`` option added.
+
Listen on the specified address and UDP port for incoming DNS over QUIC connections, presenting the specified X.509 certificate.
See :doc:`../advanced/tls-certificates-management` for details about the handling of TLS certificates and keys.
More information is available at :doc:`../guides/dns-over-quic`.
* ``maxInFlight=65535``: int - Maximum number of in-flight queries. The default is 0, which disables out-of-order processing.
* ``congestionControlAlgo="cubic"``: str - The congestion control algorithm to be chosen between ``reno``, ``cubic`` and ``bbr``.
* ``keyLogFile``: str - Write the TLS keys in the specified file so that an external program can decrypt TLS exchanges, in the format described in https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+ * ``padResponses``: bool - Whether to pad DNS responses as specified in RFC 7830. Default is ``false``, meaning responses are not padded.
.. function:: addTLSLocal(address, certFile(s), keyFile(s) [, options])
``additionalAddresses``, ``ignoreTLSConfigurationErrors`` and ``ktls`` options added.
.. versionchanged:: 1.9.0
``enableProxyProtocol``, ``readAhead`` and ``proxyProtocolOutsideTLS`` options added.
+ .. versionchanged:: 2.2.0
+ ``padResponses`` option added.
Listen on the specified address and TCP port for incoming DNS over TLS connections, presenting the specified X.509 certificate. See :doc:`../advanced/tls-certificates-management` for details about the handling of TLS certificates and keys.
More information is available at :doc:`../guides/dns-over-tls`.
* ``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.
* ``enableProxyProtocol=true``: str - Whether to expect a proxy protocol v2 header in front of incoming queries coming from an address in :func:`setProxyProtocolACL`. Default is ``true``, meaning that queries are expected to have a proxy protocol payload if they come from an address present in the :func:`setProxyProtocolACL` ACL.
+ * ``padResponses``: bool - Whether to pad DNS responses as specified in RFC 7830. Default is ``false``, meaning responses are not padded.
.. function:: setLocal(address[, options])
--- /dev/null
+../ednspadding.cc
\ No newline at end of file
--- /dev/null
+../ednspadding.hh
\ No newline at end of file
src_dir / 'ednscookies.cc',
src_dir / 'ednsextendederror.cc',
src_dir / 'ednsoptions.cc',
+ src_dir / 'ednspadding.cc',
src_dir / 'ednssubnet.cc',
src_dir / 'gettime.cc',
src_dir / 'iputils.cc',
{
/* frontend without and interface set */
const std::string interface{};
- ClientState frontend(ids.origDest, false, false, 0, interface, {}, false);
+ ClientState frontend(ids.origDest, false, false, 0, interface, {}, false, false);
ids.cs = &frontend;
const auto* itfPtr = dnsdist_ffi_dnsquestion_get_incoming_interface(&lightDQ);
BOOST_REQUIRE(itfPtr != nullptr);
{
/* frontend with interface set */
const std::string interface{"interface-name-0"};
- ClientState frontend(ids.origDest, false, false, 0, interface, {}, false);
+ ClientState frontend(ids.origDest, false, false, 0, interface, {}, false, false);
ids.cs = &frontend;
const auto* itfPtr = dnsdist_ffi_dnsquestion_get_incoming_interface(&lightDQ);
BOOST_REQUIRE(itfPtr != nullptr);
BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
localCS.dohFrontend = std::make_shared<DOHFrontend>(std::make_shared<MockupTLSCtx>());
localCS.dohFrontend->d_urls.insert("/dns-query");
BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_ClientTimeout_BackendTimeout, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
tlsCtx->d_needProxyProtocol = true;
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
{
const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
{
const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
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, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
{
const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
/* enable out-of-order on the front side */
localCS.d_maxInFlightQueriesPerConn = 65536;
{
const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
/* enable out-of-order on the front side */
localCS.d_maxInFlightQueriesPerConn = 65536;
BOOST_FIXTURE_TEST_CASE(test_Pipelined_Queries_Immediate_Responses, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, 0, "", {}, true);
+ ClientState localCS(local, true, false, 0, "", {}, true, false);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
--- /dev/null
+#!/usr/bin/env python
+
+import dns
+import dns.edns
+import dns.flags
+import dns.message
+import dns.query
+
+
+class PaddingOption(dns.edns.Option):
+ """Implementation of rfc7830."""
+
+ def __init__(self, numberOfBytes):
+ super(PaddingOption, self).__init__(12)
+ self.numberOfBytes = numberOfBytes
+
+ def to_wire(self, file=None):
+ """Create EDNS packet as defined in rfc7830."""
+
+ if not file:
+ return bytes(self.numberOfBytes)
+ file.write(bytes(self.numberOfBytes))
+ return None
+
+ def from_wire(cls, otype, wire, current, olen):
+ """Read EDNS packet as defined in rfc7830.
+
+ Returns:
+ An instance of PaddingOption based on the EDNS packet
+ """
+
+ numberOfBytes = olen
+
+ return cls(numberOfBytes)
+
+ from_wire = classmethod(from_wire)
+
+ # needed in 2.0.0
+ @classmethod
+ def from_wire_parser(cls, otype, parser):
+ data = parser.get_remaining()
+ return cls(len(data))
+
+ def __repr__(self):
+ return "%s(%d)" % (self.__class__.__name__, self.numberOfBytes)
+
+ def to_text(self):
+ return self.__repr__()
+
+ def __eq__(self, other):
+ if not isinstance(other, PaddingOption):
+ return False
+ return self.numberOfBytes == numberOfBytes
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
+dns.edns._type_to_class[0x000C] = PaddingOption
import clientsubnetoption
from dnsdistdohtests import DNSDistDOHTest
from dnsdisttests import DNSDistTest, pickAvailablePort
+import paddingoption
class DOHTests(object):
class TestDOHXFRNGHTTP2(DOHXFR, DNSDistDOHTest):
_dohLibrary = "nghttp2"
+
+
+class DOHEDNSPadding(object):
+ _serverKey = "server.key"
+ _serverCert = "server.chain"
+ _serverName = "tls.tests.dnsdist.org"
+ _caCert = "ca.pem"
+ _dohServerPort = pickAvailablePort()
+ _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
+ _config_template = """
+ newServer{address="127.0.0.1:%d"}
+
+ addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {padResponses=true, library='%s'})
+ """
+ _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
+
+ def testDOHWithPadding(self):
+ """
+ DOH with EDNS Padding
+ """
+ name = "padded.doh.tests.powerdns.com."
+ po = paddingoption.PaddingOption(64)
+ query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[po])
+
+ (_, receivedResponse) = self.sendDOHQuery(
+ self._dohServerPort,
+ self._serverName,
+ self._dohBaseURL,
+ query,
+ caFile=self._caCert,
+ )
+ self.assertEqual(len(receivedResponse.to_wire()) % 468, 0)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(receivedResponse.edns, 0)
+ self.assertEqual(len(receivedResponse.options), 1)
+ for option in receivedResponse.options:
+ self.assertEqual(option.otype, 12)
+
+ def testDOHWithPaddedResponse(self):
+ """
+ DOH with EDNS Padding, with already padded response
+ """
+ name = "paddedresponse.doh.tests.powerdns.com."
+ po = paddingoption.PaddingOption(64)
+ query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[po])
+ response = dns.message.make_response(query, pad=128)
+ rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
+ response.answer.append(rrset)
+
+ (_, receivedResponse) = self.sendDOHQuery(
+ self._dohServerPort,
+ self._serverName,
+ self._dohBaseURL,
+ query,
+ response=response,
+ caFile=self._caCert,
+ )
+ self.assertEqual(len(receivedResponse.to_wire()) % 128, 0)
+ self.assertNotEqual(len(receivedResponse.to_wire()) % 468, 0)
+ self.assertTrue(receivedResponse)
+ self.assertEqual(receivedResponse.edns, 0)
+ self.assertEqual(len(receivedResponse.options), 1)
+ for option in receivedResponse.options:
+ self.assertEqual(option.otype, 12)
+
+ def testDOHWithoutEDNS(self):
+ """
+ DOH without EDNS in query
+ """
+ name = "no.edns.doh.tests.powerdns.com."
+ query = dns.message.make_query(name, "A", "IN")
+
+ (_, receivedResponse) = self.sendDOHQuery(
+ self._dohServerPort,
+ self._serverName,
+ self._dohBaseURL,
+ query,
+ caFile=self._caCert,
+ )
+ self.assertTrue(receivedResponse)
+ self.assertNotEqual(receivedResponse.edns, 0)
+ self.assertEqual(len(receivedResponse.options), 0)
+
+
+class TestDOHEDNSPadding(DOHEDNSPadding, DNSDistDOHTest):
+ _dohLibrary = "nghttp2"
+++ /dev/null
-#!/usr/bin/env python
-
-import dns
-import dns.edns
-import dns.flags
-import dns.message
-import dns.query
-
-
-class PaddingOption(dns.edns.Option):
- """Implementation of rfc7830."""
-
- def __init__(self, numberOfBytes):
- super(PaddingOption, self).__init__(12)
- self.numberOfBytes = numberOfBytes
-
- def to_wire(self, file=None):
- """Create EDNS packet as defined in rfc7830."""
-
- if not file:
- return bytes(self.numberOfBytes)
- file.write(bytes(self.numberOfBytes))
- return None
-
- def from_wire(cls, otype, wire, current, olen):
- """Read EDNS packet as defined in rfc7830.
-
- Returns:
- An instance of PaddingOption based on the EDNS packet
- """
-
- numberOfBytes = olen
-
- return cls(numberOfBytes)
-
- from_wire = classmethod(from_wire)
-
- # needed in 2.0.0
- @classmethod
- def from_wire_parser(cls, otype, parser):
- data = parser.get_remaining()
- return cls(len(data))
-
- def __repr__(self):
- return "%s(%d)" % (self.__class__.__name__, self.numberOfBytes)
-
- def to_text(self):
- return self.__repr__()
-
- def __eq__(self, other):
- if not isinstance(other, PaddingOption):
- return False
- return self.numberOfBytes == numberOfBytes
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
-
-dns.edns._type_to_class[0x000C] = PaddingOption
--- /dev/null
+../regression-tests.common/paddingoption.py
\ No newline at end of file