diff options
Diffstat (limited to 'src/network/kernel/qdnslookup_win.cpp')
-rw-r--r-- | src/network/kernel/qdnslookup_win.cpp | 90 |
1 files changed, 87 insertions, 3 deletions
diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp index 72d5ae5c86..1b07776db9 100644 --- a/src/network/kernel/qdnslookup_win.cpp +++ b/src/network/kernel/qdnslookup_win.cpp @@ -5,9 +5,11 @@ #include <winsock2.h> #include "qdnslookup_p.h" -#include <qurl.h> +#include <qendian.h> #include <private/qnativesocketengine_p.h> #include <private/qsystemerror_p.h> +#include <qurl.h> +#include <qspan.h> #include <qt_windows.h> #include <windns.h> @@ -63,6 +65,58 @@ DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest, QT_BEGIN_NAMESPACE +static DNS_STATUS sendAlternate(QDnsLookupRunnable *self, QDnsLookupReply *reply, + PDNS_QUERY_REQUEST request, PDNS_QUERY_RESULT results) +{ + // WinDNS wants MTU - IP Header - UDP header for some reason, in spite + // of never needing that much + QVarLengthArray<unsigned char, 1472> query(1472); + + auto dnsBuffer = new (query.data()) DNS_MESSAGE_BUFFER; + DWORD dnsBufferSize = query.size(); + WORD xid = 0; + bool recursionDesired = true; + + SetLastError(ERROR_SUCCESS); + + // MinGW winheaders incorrectly declare the third parameter as LPWSTR + if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize, + const_cast<LPWSTR>(request->QueryName), request->QueryType, + xid, recursionDesired)) { + // let's try reallocating + query.resize(dnsBufferSize); + if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize, + const_cast<LPWSTR>(request->QueryName), request->QueryType, + xid, recursionDesired)) { + return GetLastError(); + } + } + + // set AD bit: we want to trust this server + dnsBuffer->MessageHead.AuthenticatedData = true; + + QDnsLookupRunnable::ReplyBuffer replyBuffer; + if (!self->sendDnsOverTls(reply, { query.data(), qsizetype(dnsBufferSize) }, replyBuffer)) + return DNS_STATUS(-1); // error set in reply + + // interpret the RCODE in the reply + auto response = reinterpret_cast<PDNS_MESSAGE_BUFFER>(replyBuffer.data()); + DNS_HEADER *header = &response->MessageHead; + if (!header->IsResponse) + return DNS_ERROR_BAD_PACKET; // not a reply + + // Convert the byte order for the 16-bit quantities in the header, so + // DnsExtractRecordsFromMessage can parse the contents. + //header->Xid = qFromBigEndian(header->Xid); + header->QuestionCount = qFromBigEndian(header->QuestionCount); + header->AnswerCount = qFromBigEndian(header->AnswerCount); + header->NameServerCount = qFromBigEndian(header->NameServerCount); + header->AdditionalCount = qFromBigEndian(header->AdditionalCount); + + results->QueryOptions = request->QueryOptions; + return DnsExtractRecordsFromMessage_W(response, replyBuffer.size(), &results->pQueryRecords); +} + void QDnsLookupRunnable::query(QDnsLookupReply *reply) { // Perform DNS query. @@ -73,7 +127,7 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) request.QueryType = requestType; request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN; - if (!nameserver.isNull()) { + if (protocol == QDnsLookup::Standard && !nameserver.isNull()) { memset(dnsAddresses, 0, sizeof(dnsAddresses)); request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY; auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1]; @@ -87,7 +141,18 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) DNS_QUERY_RESULT results = {}; results.Version = 1; - const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr); + DNS_STATUS status = ERROR_INVALID_PARAMETER; + switch (protocol) { + case QDnsLookup::Standard: + status = DnsQueryEx(&request, &results, nullptr); + break; + case QDnsLookup::DnsOverTls: + status = sendAlternate(this, reply, &request, &results); + break; + } + + if (status == DNS_STATUS(-1)) + return; // error already set in reply if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST) return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1); else if (status == ERROR_TIMEOUT) @@ -159,6 +224,25 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply) record.d->timeToLive = ptr->dwTtl; record.d->weight = ptr->Data.Srv.wWeight; reply->serviceRecords.append(record); + } else if (ptr->wType == QDnsLookup::TLSA) { + // Note: untested, because the DNS_RECORD reply appears to contain + // no records relating to TLSA. Maybe WinDNS filters them out of + // zones without DNSSEC. + QDnsTlsAssociationRecord record; + record.d->name = name; + record.d->timeToLive = ptr->dwTtl; + + const auto &tlsa = ptr->Data.Tlsa; + const quint8 usage = tlsa.bCertUsage; + const quint8 selector = tlsa.bSelector; + const quint8 matchType = tlsa.bMatchingType; + + record.d->usage = QDnsTlsAssociationRecord::CertificateUsage(usage); + record.d->selector = QDnsTlsAssociationRecord::Selector(selector); + record.d->matchType = QDnsTlsAssociationRecord::MatchingType(matchType); + record.d->value.assign(tlsa.bCertificateAssociationData, + tlsa.bCertificateAssociationData + tlsa.bCertificateAssociationDataLength); + reply->tlsAssociationRecords.append(std::move(record)); } else if (ptr->wType == QDnsLookup::TXT) { QDnsTextRecord record; record.d->name = name; |