summaryrefslogtreecommitdiffstats
path: root/src/network/kernel/qdnslookup_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/kernel/qdnslookup_win.cpp')
-rw-r--r--src/network/kernel/qdnslookup_win.cpp150
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