summaryrefslogtreecommitdiffstats
path: root/dnsdist-tcp-downstream.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:14:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:14:51 +0000
commitbc282425088455198a7a99511c75914477d4ed32 (patch)
tree1b1fb887a634136a093deea7e4dd95d054201e7a /dnsdist-tcp-downstream.cc
parentReleasing progress-linux version 1.8.3-3~progress7.99u1. (diff)
downloaddnsdist-bc282425088455198a7a99511c75914477d4ed32.tar.xz
dnsdist-bc282425088455198a7a99511c75914477d4ed32.zip
Merging upstream version 1.9.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dnsdist-tcp-downstream.cc')
-rw-r--r--dnsdist-tcp-downstream.cc78
1 files changed, 44 insertions, 34 deletions
diff --git a/dnsdist-tcp-downstream.cc b/dnsdist-tcp-downstream.cc
index 6c6fcf2..904913e 100644
--- a/dnsdist-tcp-downstream.cc
+++ b/dnsdist-tcp-downstream.cc
@@ -118,7 +118,7 @@ bool ConnectionToBackend::reconnect()
return true;
}
catch (const std::runtime_error& e) {
- vinfolog("Connection to downstream server %s failed: %s", d_ds->getName(), e.what());
+ vinfolog("Connection to downstream server %s failed: %s", d_ds->getNameWithAddr(), e.what());
d_downstreamFailures++;
if (d_downstreamFailures >= d_ds->d_config.d_retries) {
throw;
@@ -173,7 +173,7 @@ static uint32_t getSerialFromRawSOAContent(const std::vector<uint8_t>& raw)
static bool getSerialFromIXFRQuery(TCPQuery& query)
{
try {
- size_t proxyPayloadSize = query.d_proxyProtocolPayloadAdded ? query.d_proxyProtocolPayloadAddedSize : 0;
+ size_t proxyPayloadSize = query.d_proxyProtocolPayloadAdded ? query.d_idstate.d_proxyProtocolPayloadSize : 0;
if (query.d_buffer.size() <= (proxyPayloadSize + sizeof(uint16_t))) {
return false;
}
@@ -191,7 +191,7 @@ static bool getSerialFromIXFRQuery(TCPQuery& query)
if (!unknownContent) {
return false;
}
- auto raw = unknownContent->getRawContent();
+ const auto& raw = unknownContent->getRawContent();
query.d_ixfrQuerySerial = getSerialFromRawSOAContent(raw);
return true;
}
@@ -232,24 +232,25 @@ static void prepareQueryForSending(TCPQuery& query, uint16_t id, QueryState quer
if (query.d_proxyProtocolPayload.size() > 0 && !query.d_proxyProtocolPayloadAdded) {
query.d_buffer.insert(query.d_buffer.begin(), query.d_proxyProtocolPayload.begin(), query.d_proxyProtocolPayload.end());
query.d_proxyProtocolPayloadAdded = true;
- query.d_proxyProtocolPayloadAddedSize = query.d_proxyProtocolPayload.size();
+ query.d_idstate.d_proxyProtocolPayloadSize = query.d_proxyProtocolPayload.size();
}
}
else if (connectionState == ConnectionState::proxySent) {
if (query.d_proxyProtocolPayloadAdded) {
- if (query.d_buffer.size() < query.d_proxyProtocolPayloadAddedSize) {
+ if (query.d_buffer.size() < query.d_idstate.d_proxyProtocolPayloadSize) {
throw std::runtime_error("Trying to remove a proxy protocol payload of size " + std::to_string(query.d_proxyProtocolPayload.size()) + " from a buffer of size " + std::to_string(query.d_buffer.size()));
}
- query.d_buffer.erase(query.d_buffer.begin(), query.d_buffer.begin() + query.d_proxyProtocolPayloadAddedSize);
+ // NOLINTNEXTLINE(*-narrowing-conversions): the size of the payload is limited to 2^16-1
+ query.d_buffer.erase(query.d_buffer.begin(), query.d_buffer.begin() + static_cast<ssize_t>(query.d_idstate.d_proxyProtocolPayloadSize));
query.d_proxyProtocolPayloadAdded = false;
- query.d_proxyProtocolPayloadAddedSize = 0;
+ query.d_idstate.d_proxyProtocolPayloadSize = 0;
}
}
if (query.d_idstate.qclass == QClass::IN && query.d_idstate.qtype == QType::IXFR) {
getSerialFromIXFRQuery(query);
}
- editPayloadID(query.d_buffer, id, query.d_proxyProtocolPayloadAdded ? query.d_proxyProtocolPayloadAddedSize : 0, true);
+ editPayloadID(query.d_buffer, id, query.d_proxyProtocolPayloadAdded ? query.d_idstate.d_proxyProtocolPayloadSize : 0, true);
}
IOState TCPConnectionToBackend::queueNextQuery(std::shared_ptr<TCPConnectionToBackend>& conn)
@@ -268,7 +269,7 @@ IOState TCPConnectionToBackend::queueNextQuery(std::shared_ptr<TCPConnectionToBa
IOState TCPConnectionToBackend::sendQuery(std::shared_ptr<TCPConnectionToBackend>& conn, const struct timeval& now)
{
- DEBUGLOG("sending query to backend "<<conn->getDS()->getName()<<" over FD "<<conn->d_handler->getDescriptor());
+ DEBUGLOG("sending query to backend "<<conn->getDS()->getNameWithAddr()<<" over FD "<<conn->d_handler->getDescriptor());
IOState state = conn->d_handler->tryWrite(conn->d_currentQuery.d_query.d_buffer, conn->d_currentPos, conn->d_currentQuery.d_query.d_buffer.size());
@@ -361,7 +362,7 @@ void TCPConnectionToBackend::handleIO(std::shared_ptr<TCPConnectionToBackend>& c
iostate = conn->handleResponse(conn, now);
}
catch (const std::exception& e) {
- vinfolog("Got an exception while handling TCP response from %s (client is %s): %s", conn->d_ds ? conn->d_ds->getName() : "unknown", conn->d_currentQuery.d_query.d_idstate.origRemote.toStringWithPort(), e.what());
+ vinfolog("Got an exception while handling TCP response from %s (client is %s): %s", conn->d_ds ? conn->d_ds->getNameWithAddr() : "unknown", conn->d_currentQuery.d_query.d_idstate.origRemote.toStringWithPort(), e.what());
ioGuard.release();
conn->release();
return;
@@ -433,7 +434,8 @@ void TCPConnectionToBackend::handleIO(std::shared_ptr<TCPConnectionToBackend>& c
/* this one can't be restarted, sorry */
DEBUGLOG("A XFR for which a response has already been sent cannot be restarted");
try {
- pending.second.d_sender->notifyIOError(std::move(pending.second.d_query.d_idstate), now);
+ TCPResponse response(std::move(pending.second.d_query));
+ pending.second.d_sender->notifyIOError(now, std::move(response));
}
catch (const std::exception& e) {
vinfolog("Got an exception while notifying: %s", e.what());
@@ -553,16 +555,16 @@ void TCPConnectionToBackend::handleTimeout(const struct timeval& now, bool write
if (write) {
if (isFresh() && d_queries == 0) {
++d_ds->tcpConnectTimeouts;
- vinfolog("Timeout while connecting to TCP backend %s", d_ds->getName());
+ vinfolog("Timeout while connecting to TCP backend %s", d_ds->getNameWithAddr());
}
else {
++d_ds->tcpWriteTimeouts;
- vinfolog("Timeout while writing to TCP backend %s", d_ds->getName());
+ vinfolog("Timeout while writing to TCP backend %s", d_ds->getNameWithAddr());
}
}
else {
++d_ds->tcpReadTimeouts;
- vinfolog("Timeout while reading from TCP backend %s", d_ds->getName());
+ vinfolog("Timeout while reading from TCP backend %s", d_ds->getNameWithAddr());
}
try {
@@ -606,25 +608,28 @@ void TCPConnectionToBackend::notifyAllQueriesFailed(const struct timeval& now, F
try {
if (d_state == State::sendingQueryToBackend) {
increaseCounters(d_currentQuery.d_query.d_idstate.cs);
- auto sender = d_currentQuery.d_sender;
+ auto sender = std::move(d_currentQuery.d_sender);
if (sender->active()) {
- sender->notifyIOError(std::move(d_currentQuery.d_query.d_idstate), now);
+ TCPResponse response(std::move(d_currentQuery.d_query));
+ sender->notifyIOError(now, std::move(response));
}
}
for (auto& query : pendingQueries) {
increaseCounters(query.d_query.d_idstate.cs);
- auto sender = query.d_sender;
+ auto sender = std::move(query.d_sender);
if (sender->active()) {
- sender->notifyIOError(std::move(query.d_query.d_idstate), now);
+ TCPResponse response(std::move(query.d_query));
+ sender->notifyIOError(now, std::move(response));
}
}
for (auto& response : pendingResponses) {
increaseCounters(response.second.d_query.d_idstate.cs);
- auto sender = response.second.d_sender;
+ auto sender = std::move(response.second.d_sender);
if (sender->active()) {
- sender->notifyIOError(std::move(response.second.d_query.d_idstate), now);
+ TCPResponse tresp(std::move(response.second.d_query));
+ sender->notifyIOError(now, std::move(tresp));
}
}
}
@@ -721,12 +726,20 @@ IOState TCPConnectionToBackend::handleResponse(std::shared_ptr<TCPConnectionToBa
d_state = State::idle;
t_downstreamTCPConnectionsManager.moveToIdle(conn);
}
+ else if (!d_pendingResponses.empty()) {
+ d_currentPos = 0;
+ d_state = State::waitingForResponseFromBackend;
+ }
+ // be very careful that handleResponse() might trigger new queries being assigned to us,
+ // which may reset our d_currentPos, d_state and/or d_responseBuffer, so we cannot assume
+ // anything without checking first
auto shared = conn;
if (sender->active()) {
DEBUGLOG("passing response to client connection for "<<ids.qname);
// make sure that we still exist after calling handleResponse()
- sender->handleResponse(now, TCPResponse(std::move(d_responseBuffer), std::move(ids), conn, conn->d_ds));
+ TCPResponse response(std::move(d_responseBuffer), std::move(ids), conn, conn->d_ds);
+ sender->handleResponse(now, std::move(response));
}
if (!d_pendingQueries.empty()) {
@@ -735,9 +748,6 @@ IOState TCPConnectionToBackend::handleResponse(std::shared_ptr<TCPConnectionToBa
}
else if (!d_pendingResponses.empty()) {
DEBUGLOG("still have some responses to read");
- d_state = State::waitingForResponseFromBackend;
- d_currentPos = 0;
- d_responseBuffer.resize(sizeof(uint16_t));
return IOState::NeedRead;
}
else {
@@ -805,13 +815,13 @@ bool TCPConnectionToBackend::isXFRFinished(const TCPResponse& response, TCPQuery
if (!unknownContent) {
continue;
}
- auto raw = unknownContent->getRawContent();
+ const auto& raw = unknownContent->getRawContent();
auto serial = getSerialFromRawSOAContent(raw);
- if (query.d_xfrMasterSerial == 0) {
+ if (query.d_xfrPrimarySerial == 0) {
// store the first SOA in our client's connection metadata
- query.d_xfrMasterSerial = serial;
- if (query.d_idstate.qtype == QType::IXFR && (query.d_xfrMasterSerial == query.d_ixfrQuerySerial || rfc1982LessThan(query.d_xfrMasterSerial, query.d_ixfrQuerySerial))) {
- /* This is the first message with a master SOA:
+ query.d_xfrPrimarySerial = serial;
+ if (query.d_idstate.qtype == QType::IXFR && (query.d_xfrPrimarySerial == query.d_ixfrQuerySerial || rfc1982LessThan(query.d_xfrPrimarySerial, query.d_ixfrQuerySerial))) {
+ /* This is the first message with a primary SOA:
RFC 1995 Section 2:
If an IXFR query with the same or newer version number
than that of the server is received, it is replied to
@@ -823,16 +833,16 @@ bool TCPConnectionToBackend::isXFRFinished(const TCPResponse& response, TCPQuery
}
++query.d_xfrSerialCount;
- if (serial == query.d_xfrMasterSerial) {
- ++query.d_xfrMasterSerialCount;
- // figure out if it's end when receiving master's SOA again
+ if (serial == query.d_xfrPrimarySerial) {
+ ++query.d_xfrPrimarySerialCount;
+ // figure out if it's end when receiving primary's SOA again
if (query.d_xfrSerialCount == 2) {
// if there are only two SOA records marks a finished AXFR
done = true;
break;
}
- if (query.d_xfrMasterSerialCount == 3) {
- // receiving master's SOA 3 times marks a finished IXFR
+ if (query.d_xfrPrimarySerialCount == 3) {
+ // receiving primary's SOA 3 times marks a finished IXFR
done = true;
break;
}