diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2023-05-08 20:29:39 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2023-05-14 21:44:21 -0700 |
commit | 9a73bc5f3d48f6ccaef02871ad62284dd61eff38 (patch) | |
tree | ea403b7bb8eb813956d8835815535f8c2f9b766d /src/network | |
parent | 678964b242342684455e5889d4e7e6e514bf77b0 (diff) | |
download | qtbase-9a73bc5f3d48f6ccaef02871ad62284dd61eff38.tar.gz |
QDnsLookup/Windows: use DnsQueryEx so IPv6 servers are supported
Similar test with link-local server on the same network:
$ $objdir/tests/manual/qdnslookup/qdnslookup.exe @fe80::1e1b:dff:fee2:49e6%Ethernet
; <<>> QDnsLookup 6.6.0 <<>> qdnslookup @fe80::1e1b:dff:fee2:49e6%Ethernet
;; status: NoError
;; QUESTION:
;qt-project.org IN A
;; ANSWER:
qt-project.org 3532 IN A 52.18.144.254
;; Query time: 17 ms
;; SERVER: fe80::1e1b:dff:fee2:49e6%Ethernet#53
Server's dnsmasq log shows it was queried.
We don't know why we must set the port to 0. It works for me the regular
way, but not for everyone who tested this patch.
[ChangeLog][QtNetwork][QDnsLookup] setNameserver() now supports IPv6
servers with on Apple systems, AIX, FreeBSD, NetBSD, Solaris, and
Windows.
(AIX, NetBSD and Solaris not directly tested, but their docs online show
they have res_setservers())
Change-Id: I3e3bfef633af4130a03afffd175d5bfd4e7922b9
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/kernel/qdnslookup_win.cpp | 79 |
1 files changed, 60 insertions, 19 deletions
diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp index 796ff9c206..7a09035774 100644 --- a/src/network/kernel/qdnslookup_win.cpp +++ b/src/network/kernel/qdnslookup_win.cpp @@ -5,37 +5,78 @@ #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; +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) { // 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 *>(requestNameUtf16.constData()); + request.QueryType = requestType; + request.QueryOptions = DNS_QUERY_STANDARD; + 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; - } + 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, 0); + request.pDnsServerList->Family = sa->sa_family; } - const DNS_STATUS status = DnsQuery_W(reinterpret_cast<const wchar_t*>(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, &srvList, &dns_records, NULL); + + DNS_QUERY_RESULT results = {}; + results.Version = 1; + const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr); switch (status) { case ERROR_SUCCESS: break; @@ -63,7 +104,7 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN } // Extract results. - for (PDNS_RECORD ptr = dns_records; ptr != NULL; ptr = ptr->pNext) { + for (PDNS_RECORD ptr = results.pQueryRecords; ptr != NULL; ptr = ptr->pNext) { const QString name = QUrl::fromAce( QString::fromWCharArray( ptr->pName ).toLatin1() ); if (ptr->wType == QDnsLookup::A) { QDnsHostAddressRecord record; @@ -125,7 +166,7 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN } } - DnsRecordListFree(dns_records, DnsFreeRecordList); + DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList); } QT_END_NAMESPACE |