10#include <private/qnativesocketengine_p.h>
11#include <private/qsystemerror_p.h>
15#include <qt_windows.h>
19#ifndef DNS_ADDR_MAX_SOCKADDR_LENGTH
36} DNS_ADDR_ARRAY, *PDNS_ADDR_ARRAY;
37# ifndef DNS_QUERY_RESULTS_VERSION1
44} DNS_QUERY_RESULT, *PDNS_QUERY_RESULT;
45typedef VOID WINAPI DNS_QUERY_COMPLETION_ROUTINE(PVOID pQueryContext,PDNS_QUERY_RESULT pQueryResults);
57} DNS_QUERY_REQUEST, *PDNS_QUERY_REQUEST;
61DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest,
62 PDNS_QUERY_RESULT pQueryResults,
63 PDNS_QUERY_CANCEL pCancelHandle);
69static DNS_STATUS sendAlternate(QDnsLookupRunnable *self, QDnsLookupReply *reply,
70 PDNS_QUERY_REQUEST request, PDNS_QUERY_RESULT results)
74 QVarLengthArray<
unsigned char, 1472> query(1472);
76 auto dnsBuffer =
new (query.data()) DNS_MESSAGE_BUFFER;
77 DWORD dnsBufferSize = query.size();
79 bool recursionDesired =
true;
81 SetLastError(ERROR_SUCCESS);
84 if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize,
85 const_cast<LPWSTR>(request->QueryName), request->QueryType,
86 xid, recursionDesired)) {
88 query.resize(dnsBufferSize);
89 if (!DnsWriteQuestionToBuffer_W(dnsBuffer, &dnsBufferSize,
90 const_cast<LPWSTR>(request->QueryName), request->QueryType,
91 xid, recursionDesired)) {
92 return GetLastError();
97 dnsBuffer->MessageHead.AuthenticatedData =
true;
99 QDnsLookupRunnable::ReplyBuffer replyBuffer;
100 if (!self->sendDnsOverTls(reply, { query.data(), qsizetype(dnsBufferSize) }, replyBuffer))
101 return DNS_STATUS(-1);
104 auto response =
reinterpret_cast<PDNS_MESSAGE_BUFFER>(replyBuffer.data());
105 DNS_HEADER *header = &response->MessageHead;
106 if (!header->IsResponse)
107 return DNS_ERROR_BAD_PACKET;
112 header->QuestionCount = qFromBigEndian(header->QuestionCount);
113 header->AnswerCount = qFromBigEndian(header->AnswerCount);
114 header->NameServerCount = qFromBigEndian(header->NameServerCount);
115 header->AdditionalCount = qFromBigEndian(header->AdditionalCount);
117 results->QueryOptions = request->QueryOptions;
118 return DnsExtractRecordsFromMessage_W(response, replyBuffer.size(), &results->pQueryRecords);
124 alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[
sizeof(DNS_ADDR_ARRAY) +
sizeof(
DNS_ADDR)];
125 DNS_QUERY_REQUEST request = {};
127 request.QueryName =
reinterpret_cast<
const wchar_t *>(requestName.constData());
128 request.QueryType = requestType;
129 request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN;
131 if (protocol == QDnsLookup::Standard && !nameserver.isNull()) {
132 memset(dnsAddresses, 0,
sizeof(dnsAddresses));
134 auto addr =
new (request.pDnsServerList->AddrArray) DNS_ADDR[1];
135 auto sa =
new (addr[0].MaxSa) sockaddr;
139 setSockaddr(sa, nameserver, port == DnsPort ? 0 : port);
143 DNS_QUERY_RESULT results = {};
145 DNS_STATUS status = ERROR_INVALID_PARAMETER;
147 case QDnsLookup::Standard:
148 status = DnsQueryEx(&request, &results,
nullptr);
150 case QDnsLookup::DnsOverTls:
151 status = sendAlternate(
this, reply, &request, &results);
155 if (status == DNS_STATUS(-1))
157 if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST)
158 return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1);
159 else if (status == ERROR_TIMEOUT)
161 else if (status != ERROR_SUCCESS)
162 return reply->makeResolverSystemError(status);
164 QStringView lastEncodedName;
165 QString cachedDecodedName;
166 auto extractAndCacheHost = [&](QStringView name) ->
const QString & {
167 lastEncodedName = name;
168 cachedDecodedName = decodeLabel(name);
169 return cachedDecodedName;
171 auto extractMaybeCachedHost = [&](QStringView name) ->
const QString & {
172 return lastEncodedName == name ? cachedDecodedName : extractAndCacheHost(name);
176 for (PDNS_RECORD ptr = results.pQueryRecords; ptr != NULL; ptr = ptr->pNext) {
178 const QString &name = extractMaybeCachedHost(ptr->pName);
179 if (ptr->wType == QDnsLookup::A) {
180 QDnsHostAddressRecord record;
181 record.d->name = name;
182 record.d->timeToLive = ptr->dwTtl;
183 record.d->value = QHostAddress(ntohl(ptr->Data.A.IpAddress));
184 reply->hostAddressRecords.append(record);
185 }
else if (ptr->wType == QDnsLookup::AAAA) {
187 memcpy(&addr, &ptr->Data.AAAA.Ip6Address,
sizeof(Q_IPV6ADDR));
189 QDnsHostAddressRecord record;
190 record.d->name = name;
191 record.d->timeToLive = ptr->dwTtl;
192 record.d->value = QHostAddress(addr);
193 reply->hostAddressRecords.append(record);
194 }
else if (ptr->wType == QDnsLookup::CNAME) {
195 QDnsDomainNameRecord record;
196 record.d->name = name;
197 record.d->timeToLive = ptr->dwTtl;
198 record.d->value = extractAndCacheHost(ptr->Data.Cname.pNameHost);
199 reply->canonicalNameRecords.append(record);
200 }
else if (ptr->wType == QDnsLookup::MX) {
201 QDnsMailExchangeRecord record;
202 record.d->name = name;
203 record.d->exchange = decodeLabel(QStringView(ptr->Data.Mx.pNameExchange));
204 record.d->preference = ptr->Data.Mx.wPreference;
205 record.d->timeToLive = ptr->dwTtl;
206 reply->mailExchangeRecords.append(record);
207 }
else if (ptr->wType == QDnsLookup::NS) {
208 QDnsDomainNameRecord record;
209 record.d->name = name;
210 record.d->timeToLive = ptr->dwTtl;
211 record.d->value = decodeLabel(QStringView(ptr->Data.Ns.pNameHost));
212 reply->nameServerRecords.append(record);
213 }
else if (ptr->wType == QDnsLookup::PTR) {
214 QDnsDomainNameRecord record;
215 record.d->name = name;
216 record.d->timeToLive = ptr->dwTtl;
217 record.d->value = decodeLabel(QStringView(ptr->Data.Ptr.pNameHost));
218 reply->pointerRecords.append(record);
219 }
else if (ptr->wType == QDnsLookup::SRV) {
220 QDnsServiceRecord record;
221 record.d->name = name;
222 record.d->target = decodeLabel(QStringView(ptr->Data.Srv.pNameTarget));
223 record.d->port = ptr->Data.Srv.wPort;
224 record.d->priority = ptr->Data.Srv.wPriority;
225 record.d->timeToLive = ptr->dwTtl;
226 record.d->weight = ptr->Data.Srv.wWeight;
227 reply->serviceRecords.append(record);
228 }
else if (ptr->wType == QDnsLookup::TLSA) {
232 QDnsTlsAssociationRecord record;
233 record.d->name = name;
234 record.d->timeToLive = ptr->dwTtl;
236 const auto &tlsa = ptr->Data.Tlsa;
237 const quint8 usage = tlsa.bCertUsage;
238 const quint8 selector = tlsa.bSelector;
239 const quint8 matchType = tlsa.bMatchingType;
241 record.d->usage = QDnsTlsAssociationRecord::CertificateUsage(usage);
242 record.d->selector = QDnsTlsAssociationRecord::Selector(selector);
243 record.d->matchType = QDnsTlsAssociationRecord::MatchingType(matchType);
244 record.d->value.assign(tlsa.bCertificateAssociationData,
245 tlsa.bCertificateAssociationData + tlsa.bCertificateAssociationDataLength);
246 reply->tlsAssociationRecords.append(
std::move(record));
247 }
else if (ptr->wType == QDnsLookup::TXT) {
248 QDnsTextRecord record;
249 record.d->name = name;
250 record.d->timeToLive = ptr->dwTtl;
251 for (
unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) {
252 record.d->values << QStringView(ptr->Data.Txt.pStringArray[i]).toLatin1();
254 reply->textRecords.append(record);
258 DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList);
DNS_QUERY_COMPLETION_ROUTINE * PDNS_QUERY_COMPLETION_ROUTINE
PDNS_ADDR_ARRAY pDnsServerList
PDNS_QUERY_COMPLETION_ROUTINE pQueryCompletionCallback
PDNS_RECORD pQueryRecords