diff options
Diffstat (limited to 'src/network/kernel/qdnslookup_win.cpp')
-rw-r--r-- | src/network/kernel/qdnslookup_win.cpp | 150 |
1 files changed, 98 insertions, 52 deletions
diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp index 564966e395..72d5ae5c86 100644 --- a/src/network/kernel/qdnslookup_win.cpp +++ b/src/network/kernel/qdnslookup_win.cpp @@ -1,69 +1,115 @@ // Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org> +// Copyright (C) 2023 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include <winsock2.h> #include "qdnslookup_p.h" #include <qurl.h> +#include <private/qnativesocketengine_p.h> #include <private/qsystemerror_p.h> #include <qt_windows.h> #include <windns.h> #include <memory.h> +#ifndef DNS_ADDR_MAX_SOCKADDR_LENGTH +// MinGW headers are missing almost all of this +typedef struct Qt_DnsAddr { + CHAR MaxSa[32]; + DWORD DnsAddrUserDword[8]; +} DNS_ADDR, *PDNS_ADDR; +typedef struct Qt_DnsAddrArray { + DWORD MaxCount; + DWORD AddrCount; + DWORD Tag; + WORD Family; + WORD WordReserved; + DWORD Flags; + DWORD MatchFlag; + DWORD Reserved1; + DWORD Reserved2; + DNS_ADDR AddrArray[]; +} DNS_ADDR_ARRAY, *PDNS_ADDR_ARRAY; +# ifndef DNS_QUERY_RESULTS_VERSION1 +typedef struct Qt_DNS_QUERY_RESULT { + ULONG Version; + DNS_STATUS QueryStatus; + ULONG64 QueryOptions; + PDNS_RECORD pQueryRecords; + PVOID Reserved; +} DNS_QUERY_RESULT, *PDNS_QUERY_RESULT; +typedef VOID WINAPI DNS_QUERY_COMPLETION_ROUTINE(PVOID pQueryContext,PDNS_QUERY_RESULT pQueryResults); +typedef DNS_QUERY_COMPLETION_ROUTINE *PDNS_QUERY_COMPLETION_ROUTINE; +# endif +typedef struct Qt_DNS_QUERY_REQUEST { + ULONG Version; + PCWSTR QueryName; + WORD QueryType; + ULONG64 QueryOptions; + PDNS_ADDR_ARRAY pDnsServerList; + ULONG InterfaceIndex; + PDNS_QUERY_COMPLETION_ROUTINE pQueryCompletionCallback; + PVOID pQueryContext; +} DNS_QUERY_REQUEST, *PDNS_QUERY_REQUEST; + +typedef void *PDNS_QUERY_CANCEL; // not really, but we don't need it +extern "C" { +DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest, + PDNS_QUERY_RESULT pQueryResults, + PDNS_QUERY_CANCEL pCancelHandle); +} +#endif + QT_BEGIN_NAMESPACE -void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply) +void QDnsLookupRunnable::query(QDnsLookupReply *reply) { // Perform DNS query. - PDNS_RECORD dns_records = 0; - const QString requestNameUtf16 = QString::fromUtf8(requestName.data(), requestName.size()); - IP4_ARRAY srvList; - memset(&srvList, 0, sizeof(IP4_ARRAY)); + alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[sizeof(DNS_ADDR_ARRAY) + sizeof(DNS_ADDR)]; + DNS_QUERY_REQUEST request = {}; + request.Version = 1; + request.QueryName = reinterpret_cast<const wchar_t *>(requestName.constData()); + request.QueryType = requestType; + request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN; + if (!nameserver.isNull()) { - if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) { - // The below code is referenced from: http://support.microsoft.com/kb/831226 - srvList.AddrCount = 1; - srvList.AddrArray[0] = htonl(nameserver.toIPv4Address()); - } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) { - // For supoprting IPv6 nameserver addresses, we'll need to switch - // from DnsQuey() to DnsQueryEx() as it supports passing an IPv6 - // address in the nameserver list - qWarning("%s", QDnsLookupPrivate::msgNoIpV6NameServerAdresses); - reply->error = QDnsLookup::ResolverError; - reply->errorString = tr(QDnsLookupPrivate::msgNoIpV6NameServerAdresses); - return; - } - } - const DNS_STATUS status = DnsQuery_W(reinterpret_cast<const wchar_t*>(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, &srvList, &dns_records, NULL); - switch (status) { - case ERROR_SUCCESS: - break; - case DNS_ERROR_RCODE_FORMAT_ERROR: - reply->error = QDnsLookup::InvalidRequestError; - reply->errorString = tr("Server could not process query"); - return; - case DNS_ERROR_RCODE_SERVER_FAILURE: - reply->error = QDnsLookup::ServerFailureError; - reply->errorString = tr("Server failure"); - return; - case DNS_ERROR_RCODE_NAME_ERROR: - reply->error = QDnsLookup::NotFoundError; - reply->errorString = tr("Non existent domain"); - return; - case DNS_ERROR_RCODE_REFUSED: - reply->error = QDnsLookup::ServerRefusedError; - reply->errorString = tr("Server refused to answer"); - return; - default: - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = QSystemError(status, QSystemError::NativeError).toString(); - return; + memset(dnsAddresses, 0, sizeof(dnsAddresses)); + request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY; + auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1]; + auto sa = new (addr[0].MaxSa) sockaddr; + request.pDnsServerList->MaxCount = sizeof(dnsAddresses); + request.pDnsServerList->AddrCount = 1; + // ### setting port 53 seems to cause some systems to fail + setSockaddr(sa, nameserver, port == DnsPort ? 0 : port); + request.pDnsServerList->Family = sa->sa_family; } + DNS_QUERY_RESULT results = {}; + results.Version = 1; + const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr); + 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) + return reply->makeTimeoutError(); + else if (status != ERROR_SUCCESS) + return reply->makeResolverSystemError(status); + + QStringView lastEncodedName; + QString cachedDecodedName; + auto extractAndCacheHost = [&](QStringView name) -> const QString & { + lastEncodedName = name; + cachedDecodedName = decodeLabel(name); + return cachedDecodedName; + }; + auto extractMaybeCachedHost = [&](QStringView name) -> const QString & { + return lastEncodedName == name ? cachedDecodedName : extractAndCacheHost(name); + }; + // Extract results. - for (PDNS_RECORD ptr = dns_records; ptr != NULL; ptr = ptr->pNext) { - const QString name = QUrl::fromAce( QString::fromWCharArray( ptr->pName ).toLatin1() ); + for (PDNS_RECORD ptr = results.pQueryRecords; ptr != NULL; ptr = ptr->pNext) { + // warning: always assign name to the record before calling extractXxxHost() again + const QString &name = extractMaybeCachedHost(ptr->pName); if (ptr->wType == QDnsLookup::A) { QDnsHostAddressRecord record; record.d->name = name; @@ -83,12 +129,12 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN QDnsDomainNameRecord record; record.d->name = name; record.d->timeToLive = ptr->dwTtl; - record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Cname.pNameHost).toLatin1()); + record.d->value = extractAndCacheHost(ptr->Data.Cname.pNameHost); reply->canonicalNameRecords.append(record); } else if (ptr->wType == QDnsLookup::MX) { QDnsMailExchangeRecord record; record.d->name = name; - record.d->exchange = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Mx.pNameExchange).toLatin1()); + record.d->exchange = decodeLabel(QStringView(ptr->Data.Mx.pNameExchange)); record.d->preference = ptr->Data.Mx.wPreference; record.d->timeToLive = ptr->dwTtl; reply->mailExchangeRecords.append(record); @@ -96,18 +142,18 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN QDnsDomainNameRecord record; record.d->name = name; record.d->timeToLive = ptr->dwTtl; - record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Ns.pNameHost).toLatin1()); + record.d->value = decodeLabel(QStringView(ptr->Data.Ns.pNameHost)); reply->nameServerRecords.append(record); } else if (ptr->wType == QDnsLookup::PTR) { QDnsDomainNameRecord record; record.d->name = name; record.d->timeToLive = ptr->dwTtl; - record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Ptr.pNameHost).toLatin1()); + record.d->value = decodeLabel(QStringView(ptr->Data.Ptr.pNameHost)); reply->pointerRecords.append(record); } else if (ptr->wType == QDnsLookup::SRV) { QDnsServiceRecord record; record.d->name = name; - record.d->target = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Srv.pNameTarget).toLatin1()); + record.d->target = decodeLabel(QStringView(ptr->Data.Srv.pNameTarget)); record.d->port = ptr->Data.Srv.wPort; record.d->priority = ptr->Data.Srv.wPriority; record.d->timeToLive = ptr->dwTtl; @@ -118,13 +164,13 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN record.d->name = name; record.d->timeToLive = ptr->dwTtl; for (unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) { - record.d->values << QString::fromWCharArray((ptr->Data.Txt.pStringArray[i])).toLatin1();; + record.d->values << QStringView(ptr->Data.Txt.pStringArray[i]).toLatin1(); } reply->textRecords.append(record); } } - DnsRecordListFree(dns_records, DnsFreeRecordList); + DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList); } QT_END_NAMESPACE |