QDnsLookup/Unix large replies: manually handle VC [3/3]

The current code was inefficient when replies exceeded the initial
buffer size because the res_nsend() function switched to VC to get the
full reply, but that wouldn't fit our buffer before we enlarged it. This
commit tells res_nsend() to only use UDP or only use TCP, avoiding the
two unnecessary transactions in the lookup.

Since we don't get that second TCP reply now that would tell us the size
of the reply, we must allocate the largest possible buffer for a DNS
reply.

Change-Id: I3e3bfef633af4130a03afffd175e73d2e9fa9bf1
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Thiago Macieira 2023-05-12 09:42:00 -07:00
parent df07d98243
commit 5ecdce0c35

View File

@ -179,10 +179,25 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
return responseLength;
};
// strictly use UDP, we'll deal with truncated replies ourselves
state.options |= RES_IGNTC;
int responseLength = attemptToSend();
if (responseLength > buffer.size()) {
// increase our buffer size
buffer.resize(responseLength);
if (responseLength < 0)
return;
// check if we need to use the virtual circuit (TCP)
auto header = reinterpret_cast<HEADER *>(buffer.data());
if (header->rcode == NOERROR && header->tc) {
// yes, increase our buffer size
buffer.resize(std::numeric_limits<quint16>::max());
header = reinterpret_cast<HEADER *>(buffer.data());
// remove the EDNS record in the query
reinterpret_cast<HEADER *>(qbuffer.data())->arcount = 0;
queryLength -= sizeof(Edns0Record);
// send using the virtual circuit
state.options |= RES_USEVC;
responseLength = attemptToSend();
if (Q_UNLIKELY(responseLength > buffer.size())) {
// Ok, we give up.
@ -198,7 +213,6 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
return reply->makeInvalidReplyError();
// Parse the reply.
auto header = reinterpret_cast<HEADER *>(buffer.data());
if (header->rcode)
return reply->makeDnsRcodeError(header->rcode);