Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qdnslookup_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
2// Copyright (C) 2023 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <winsock2.h>
6#include "qdnslookup_p.h"
7
8#include <qurl.h>
9#include <private/qnativesocketengine_p.h>
10#include <private/qsystemerror_p.h>
11
12#include <qt_windows.h>
13#include <windns.h>
14#include <memory.h>
15
16#ifndef DNS_ADDR_MAX_SOCKADDR_LENGTH
17// MinGW headers are missing almost all of this
18typedef struct Qt_DnsAddr {
19 CHAR MaxSa[32];
22typedef struct Qt_DnsAddrArray {
23 DWORD MaxCount;
24 DWORD AddrCount;
25 DWORD Tag;
26 WORD Family;
28 DWORD Flags;
29 DWORD MatchFlag;
30 DWORD Reserved1;
31 DWORD Reserved2;
34# ifndef DNS_QUERY_RESULTS_VERSION1
35typedef struct Qt_DNS_QUERY_RESULT {
36 ULONG Version;
37 DNS_STATUS QueryStatus;
38 ULONG64 QueryOptions;
39 PDNS_RECORD pQueryRecords;
40 PVOID Reserved;
42typedef VOID WINAPI DNS_QUERY_COMPLETION_ROUTINE(PVOID pQueryContext,PDNS_QUERY_RESULT pQueryResults);
44# endif
45typedef struct Qt_DNS_QUERY_REQUEST {
46 ULONG Version;
47 PCWSTR QueryName;
49 ULONG64 QueryOptions;
55
56typedef void *PDNS_QUERY_CANCEL; // not really, but we don't need it
57extern "C" {
58DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest,
59 PDNS_QUERY_RESULT pQueryResults,
60 PDNS_QUERY_CANCEL pCancelHandle);
61}
62#endif
63
65
66void QDnsLookupRunnable::query(QDnsLookupReply *reply)
67{
68 // Perform DNS query.
69 alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[sizeof(DNS_ADDR_ARRAY) + sizeof(DNS_ADDR)];
71 request.Version = 1;
72 request.QueryName = reinterpret_cast<const wchar_t *>(requestName.constData());
73 request.QueryType = requestType;
74 request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN;
75
76 if (!nameserver.isNull()) {
77 memset(dnsAddresses, 0, sizeof(dnsAddresses));
78 request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY;
79 auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1];
80 auto sa = new (addr[0].MaxSa) sockaddr;
81 request.pDnsServerList->MaxCount = sizeof(dnsAddresses);
82 request.pDnsServerList->AddrCount = 1;
83 // ### setting port 53 seems to cause some systems to fail
84 setSockaddr(sa, nameserver, port == DnsPort ? 0 : port);
85 request.pDnsServerList->Family = sa->sa_family;
86 }
87
89 results.Version = 1;
90 const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr);
91 if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST)
92 return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1);
93 else if (status == ERROR_TIMEOUT)
94 return reply->makeTimeoutError();
95 else if (status != ERROR_SUCCESS)
96 return reply->makeResolverSystemError(status);
97
98 QStringView lastEncodedName;
99 QString cachedDecodedName;
100 auto extractAndCacheHost = [&](QStringView name) -> const QString & {
101 lastEncodedName = name;
102 cachedDecodedName = decodeLabel(name);
103 return cachedDecodedName;
104 };
105 auto extractMaybeCachedHost = [&](QStringView name) -> const QString & {
106 return lastEncodedName == name ? cachedDecodedName : extractAndCacheHost(name);
107 };
108
109 // Extract results.
110 for (PDNS_RECORD ptr = results.pQueryRecords; ptr != NULL; ptr = ptr->pNext) {
111 // warning: always assign name to the record before calling extractXxxHost() again
112 const QString &name = extractMaybeCachedHost(ptr->pName);
113 if (ptr->wType == QDnsLookup::A) {
115 record.d->name = name;
116 record.d->timeToLive = ptr->dwTtl;
117 record.d->value = QHostAddress(ntohl(ptr->Data.A.IpAddress));
118 reply->hostAddressRecords.append(record);
119 } else if (ptr->wType == QDnsLookup::AAAA) {
121 memcpy(&addr, &ptr->Data.AAAA.Ip6Address, sizeof(Q_IPV6ADDR));
122
124 record.d->name = name;
125 record.d->timeToLive = ptr->dwTtl;
126 record.d->value = QHostAddress(addr);
127 reply->hostAddressRecords.append(record);
128 } else if (ptr->wType == QDnsLookup::CNAME) {
130 record.d->name = name;
131 record.d->timeToLive = ptr->dwTtl;
132 record.d->value = extractAndCacheHost(ptr->Data.Cname.pNameHost);
133 reply->canonicalNameRecords.append(record);
134 } else if (ptr->wType == QDnsLookup::MX) {
136 record.d->name = name;
137 record.d->exchange = decodeLabel(QStringView(ptr->Data.Mx.pNameExchange));
138 record.d->preference = ptr->Data.Mx.wPreference;
139 record.d->timeToLive = ptr->dwTtl;
140 reply->mailExchangeRecords.append(record);
141 } else if (ptr->wType == QDnsLookup::NS) {
143 record.d->name = name;
144 record.d->timeToLive = ptr->dwTtl;
145 record.d->value = decodeLabel(QStringView(ptr->Data.Ns.pNameHost));
146 reply->nameServerRecords.append(record);
147 } else if (ptr->wType == QDnsLookup::PTR) {
149 record.d->name = name;
150 record.d->timeToLive = ptr->dwTtl;
151 record.d->value = decodeLabel(QStringView(ptr->Data.Ptr.pNameHost));
152 reply->pointerRecords.append(record);
153 } else if (ptr->wType == QDnsLookup::SRV) {
155 record.d->name = name;
156 record.d->target = decodeLabel(QStringView(ptr->Data.Srv.pNameTarget));
157 record.d->port = ptr->Data.Srv.wPort;
158 record.d->priority = ptr->Data.Srv.wPriority;
159 record.d->timeToLive = ptr->dwTtl;
160 record.d->weight = ptr->Data.Srv.wWeight;
161 reply->serviceRecords.append(record);
162 } else if (ptr->wType == QDnsLookup::TXT) {
164 record.d->name = name;
165 record.d->timeToLive = ptr->dwTtl;
166 for (unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) {
167 record.d->values << QStringView(ptr->Data.Txt.pStringArray[i]).toLatin1();
168 }
169 reply->textRecords.append(record);
170 }
171 }
172
173 DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList);
174}
175
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
The QDnsDomainNameRecord class stores information about a domain name record.
Definition qdnslookup.h:27
The QDnsHostAddressRecord class stores information about a host address record.
Definition qdnslookup.h:49
The QDnsMailExchangeRecord class stores information about a DNS MX record.
Definition qdnslookup.h:71
The QDnsServiceRecord class stores information about a DNS SRV record.
Definition qdnslookup.h:94
The QDnsTextRecord class stores information about a DNS TXT record.
Definition qdnslookup.h:119
The QHostAddress class provides an IP address.
bool isNull() const
Returns true if this host address is not valid for any host or interface.
\inmodule QtCore
Definition qstringview.h:76
QByteArray toLatin1() const
Returns a Latin-1 representation of the string as a QByteArray.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
Combined button and popup list for selecting options.
QT_SOCKLEN_T setSockaddr(sockaddr_in *sin, const QHostAddress &addr, quint16 port=0)
constexpr quint16 DnsPort
struct Qt_DnsAddrArray * PDNS_ADDR_ARRAY
struct Qt_DnsAddr DNS_ADDR
struct Qt_DnsAddrArray DNS_ADDR_ARRAY
VOID WINAPI DNS_QUERY_COMPLETION_ROUTINE(PVOID pQueryContext, PDNS_QUERY_RESULT pQueryResults)
void * PDNS_QUERY_CANCEL
DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest, PDNS_QUERY_RESULT pQueryResults, PDNS_QUERY_CANCEL pCancelHandle)
struct Qt_DNS_QUERY_RESULT DNS_QUERY_RESULT
struct Qt_DnsAddr * PDNS_ADDR
struct Qt_DNS_QUERY_RESULT * PDNS_QUERY_RESULT
struct Qt_DNS_QUERY_REQUEST * PDNS_QUERY_REQUEST
DNS_QUERY_COMPLETION_ROUTINE * PDNS_QUERY_COMPLETION_ROUTINE
struct Qt_DNS_QUERY_REQUEST DNS_QUERY_REQUEST
EGLOutputPortEXT port
QIPv6Address Q_IPV6ADDR
static ControlElement< T > * ptr(QWidget *widget)
GLuint name
GLenum const void * addr
unsigned char uchar
Definition qtypes.h:27
MyRecord record(int row) const
[0]
QNetworkRequest request(url)
QNetworkReply * reply
PDNS_ADDR_ARRAY pDnsServerList
PDNS_QUERY_COMPLETION_ROUTINE pQueryCompletionCallback
DWORD DnsAddrUserDword[8]