Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdnslookup.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// Qt-Security score:critical reason:data-parser
5
6#include "qdnslookup.h"
7#include "qdnslookup_p.h"
8
9#include <qapplicationstatic.h>
10#include <qcoreapplication.h>
11#include <qdatetime.h>
12#include <qendian.h>
13#include <qloggingcategory.h>
14#include <qrandom.h>
15#include <qspan.h>
16#include <qurl.h>
17
18#if QT_CONFIG(ssl)
19# include <qsslsocket.h>
20#endif
21
22#include <algorithm>
23
25
26using namespace Qt::StringLiterals;
27
28Q_STATIC_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup", QtCriticalMsg)
29
30namespace {
31struct QDnsLookupThreadPool : QThreadPool
32{
33 QDnsLookupThreadPool()
34 {
35 // Run up to 5 lookups in parallel.
36 setMaxThreadCount(5);
37 }
38};
39}
40
41Q_APPLICATION_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
42
43static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
44{
45 // Lower numbers are more preferred than higher ones.
46 return r1.preference() < r2.preference();
47}
48
49/*
50 Sorts a list of QDnsMailExchangeRecord objects according to RFC 5321.
51*/
52
53static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &records)
54{
55 // If we have no more than one result, we are done.
56 if (records.size() <= 1)
57 return;
58
59 // Order the records by preference.
60 std::sort(records.begin(), records.end(), qt_qdnsmailexchangerecord_less_than);
61
62 int i = 0;
63 while (i < records.size()) {
64
65 // Determine the slice of records with the current preference.
66 QList<QDnsMailExchangeRecord> slice;
67 const quint16 slicePreference = records.at(i).preference();
68 for (int j = i; j < records.size(); ++j) {
69 if (records.at(j).preference() != slicePreference)
70 break;
71 slice << records.at(j);
72 }
73
74 // Randomize the slice of records.
75 while (!slice.isEmpty()) {
76 const unsigned int pos = QRandomGenerator::global()->bounded(slice.size());
77 records[i++] = slice.takeAt(pos);
78 }
79 }
80}
81
82static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2)
83{
84 // Order by priority, or if the priorities are equal,
85 // put zero weight records first.
86 return r1.priority() < r2.priority()
87 || (r1.priority() == r2.priority()
88 && r1.weight() == 0 && r2.weight() > 0);
89}
90
91/*
92 Sorts a list of QDnsServiceRecord objects according to RFC 2782.
93*/
94
95static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
96{
97 // If we have no more than one result, we are done.
98 if (records.size() <= 1)
99 return;
100
101 // Order the records by priority, and for records with an equal
102 // priority, put records with a zero weight first.
103 std::sort(records.begin(), records.end(), qt_qdnsservicerecord_less_than);
104
105 int i = 0;
106 while (i < records.size()) {
107
108 // Determine the slice of records with the current priority.
109 QList<QDnsServiceRecord> slice;
110 const quint16 slicePriority = records.at(i).priority();
111 unsigned int sliceWeight = 0;
112 for (int j = i; j < records.size(); ++j) {
113 if (records.at(j).priority() != slicePriority)
114 break;
115 sliceWeight += records.at(j).weight();
116 slice << records.at(j);
117 }
118#ifdef QDNSLOOKUP_DEBUG
119 qDebug("qt_qdnsservicerecord_sort() : priority %i (size: %i, total weight: %i)",
120 slicePriority, slice.size(), sliceWeight);
121#endif
122
123 // Order the slice of records.
124 while (!slice.isEmpty()) {
125 const unsigned int weightThreshold = QRandomGenerator::global()->bounded(sliceWeight + 1);
126 unsigned int summedWeight = 0;
127 for (int j = 0; j < slice.size(); ++j) {
128 summedWeight += slice.at(j).weight();
129 if (summedWeight >= weightThreshold) {
130#ifdef QDNSLOOKUP_DEBUG
131 qDebug("qt_qdnsservicerecord_sort() : adding %s %i (weight: %i)",
132 qPrintable(slice.at(j).target()), slice.at(j).port(),
133 slice.at(j).weight());
134#endif
135 // Adjust the slice weight and take the current record.
136 sliceWeight -= slice.at(j).weight();
137 records[i++] = slice.takeAt(j);
138 break;
139 }
140 }
141 }
142 }
143}
144
145/*!
146 \class QDnsLookup
147 \brief The QDnsLookup class represents a DNS lookup.
148 \since 5.0
149
150 \inmodule QtNetwork
151 \ingroup network
152
153 QDnsLookup uses the mechanisms provided by the operating system to perform
154 DNS lookups. To perform a lookup you need to specify a \l name and \l type
155 then invoke the \l{QDnsLookup::lookup()}{lookup()} slot. The
156 \l{QDnsLookup::finished()}{finished()} signal will be emitted upon
157 completion.
158
159 For example, you can determine which servers an XMPP chat client should
160 connect to for a given domain with:
161
162 \snippet code/src_network_kernel_qdnslookup.cpp 0
163
164 Once the request finishes you can handle the results with:
165
166 \snippet code/src_network_kernel_qdnslookup.cpp 1
167
168 \note If you simply want to find the IP address(es) associated with a host
169 name, or the host name associated with an IP address you should use
170 QHostInfo instead.
171
172 \section1 DNS-over-TLS and Authentic Data
173
174 QDnsLookup supports DNS-over-TLS (DoT, as specified by \l{RFC 7858}) on
175 some platforms. That currently includes all Unix platforms where regular
176 queries are supported, if \l QSslSocket support is present in Qt. To query
177 if support is present at runtime, use isProtocolSupported().
178
179 When using DNS-over-TLS, QDnsLookup only implements the "Opportunistic
180 Privacy Profile" method of authentication, as described in \l{RFC 7858}
181 section 4.1. In this mode, QDnsLookup (through \l QSslSocket) only
182 validates that the server presents a certificate that is valid for the
183 server being connected to. Clients may use setSslConfiguration() to impose
184 additional restrictions and sslConfiguration() to obtain information after
185 the query is complete.
186
187 QDnsLookup will request DNS servers queried over TLS to perform
188 authentication on the data they return. If they confirm the data is valid,
189 the \l authenticData property will be set to true. QDnsLookup does not
190 verify the integrity of the data by itself, so applications should only
191 trust this property on servers they have confirmed through other means to
192 be trustworthy.
193
194 \section2 Authentic Data without TLS
195
196 QDnsLookup request Authentic Data for any server set with setNameserver(),
197 even if TLS encryption is not required. This is useful when querying a
198 caching nameserver on the same host as the application or on a trusted
199 network. Though similar to the TLS case, the application is responsible for
200 determining if the server it chose to use is trustworthy, and if the
201 unencrypted connection cannot be tampered with.
202
203 QDnsLookup obeys the system configuration to request Authentic Data on the
204 default nameserver (that is, if setNameserver() is not called). This is
205 currently only supported on Linux systems using glibc 2.31 or later. On any
206 other systems, QDnsLookup will ignore the AD bit in the query header.
207*/
208
209/*!
210 \enum QDnsLookup::Error
211
212 Indicates all possible error conditions found during the
213 processing of the DNS lookup.
214
215 \value NoError no error condition.
216
217 \value ResolverError there was an error initializing the system's
218 DNS resolver.
219
220 \value OperationCancelledError the lookup was aborted using the abort()
221 method.
222
223 \value InvalidRequestError the requested DNS lookup was invalid.
224
225 \value InvalidReplyError the reply returned by the server was invalid.
226
227 \value ServerFailureError the server encountered an internal failure
228 while processing the request (SERVFAIL).
229
230 \value ServerRefusedError the server refused to process the request for
231 security or policy reasons (REFUSED).
232
233 \value NotFoundError the requested domain name does not exist
234 (NXDOMAIN).
236 \value TimeoutError the server was not reached or did not reply
237 in time (since 6.6).
238*/
239
240/*!
241 \enum QDnsLookup::Type
242
243 Indicates the type of DNS lookup that was performed.
244
245 \value A IPv4 address records.
246
247 \value AAAA IPv6 address records.
248
249 \value ANY any records.
250
251 \value CNAME canonical name records.
252
253 \value MX mail exchange records.
254
255 \value NS name server records.
256
257 \value PTR pointer records.
258
259 \value SRV service records.
260
261 \value[since 6.8] TLSA TLS association records.
262
263 \value TXT text records.
264*/
265
266/*!
267 \enum QDnsLookup::Protocol
268
269 Indicates the type of DNS server that is being queried.
270
271 \value Standard
272 Regular, unencrypted DNS, using UDP and falling back to TCP as necessary
273 (default port: 53)
274
275 \value DnsOverTls
276 Encrypted DNS over TLS (DoT, as specified by \l{RFC 7858}), over TCP
277 (default port: 853)
278
279 \sa isProtocolSupported(), nameserverProtocol, setNameserver()
280*/
281
282/*!
283 \since 6.8
284
285 Returns true if DNS queries using \a protocol are supported with QDnsLookup.
286
287 \sa nameserverProtocol
288*/
289bool QDnsLookup::isProtocolSupported(Protocol protocol)
290{
291#if QT_CONFIG(libresolv) || defined(Q_OS_WIN)
292 switch (protocol) {
293 case QDnsLookup::Standard:
294 return true;
295 case QDnsLookup::DnsOverTls:
296# if QT_CONFIG(ssl)
297 if (QSslSocket::supportsSsl())
298 return true;
299# endif
300 return false;
301 }
302#else
303 Q_UNUSED(protocol)
304#endif
305 return false;
306}
307
308/*!
309 \since 6.8
310
311 Returns the standard (default) port number for the protocol \a protocol.
312
313 \sa isProtocolSupported()
314*/
315quint16 QDnsLookup::defaultPortForProtocol(Protocol protocol) noexcept
316{
317 switch (protocol) {
318 case QDnsLookup::Standard:
319 return DnsPort;
320 case QDnsLookup::DnsOverTls:
321 return DnsOverTlsPort;
322 }
323 return 0; // will probably fail somewhere
324}
325
326/*!
327 \fn void QDnsLookup::finished()
328
329 This signal is emitted when the reply has finished processing.
330*/
331
332/*!
333 \fn void QDnsLookup::nameChanged(const QString &name)
334
335 This signal is emitted when the lookup \l name changes.
336 \a name is the new lookup name.
337*/
338
339/*!
340 \fn void QDnsLookup::typeChanged(QDnsLookup::Type type)
341
342 This signal is emitted when the lookup \l type changes.
343 \a type is the new lookup type.
344*/
345
346/*!
347 Constructs a QDnsLookup object and sets \a parent as the parent object.
348
349 The \l type property will default to QDnsLookup::A.
350*/
351
352QDnsLookup::QDnsLookup(QObject *parent)
353 : QObject(*new QDnsLookupPrivate, parent)
354{
355}
356
357/*!
358 Constructs a QDnsLookup object for the given \a type and \a name and sets
359 \a parent as the parent object.
360*/
361
362QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
363 : QObject(*new QDnsLookupPrivate, parent)
364{
365 Q_D(QDnsLookup);
366 d->name = name;
367 d->type = type;
368}
369
370/*!
371 \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
372 \since 5.4
373
374 Constructs a QDnsLookup object to issue a query for \a name of record type
375 \a type, using the DNS server \a nameserver running on the default DNS port,
376 and sets \a parent as the parent object.
377*/
378
379QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
380 : QDnsLookup(type, name, nameserver, 0, parent)
381{
382}
383
384/*!
385 \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
386 \since 6.6
387
388 Constructs a QDnsLookup object to issue a query for \a name of record type
389 \a type, using the DNS server \a nameserver running on port \a port, and
390 sets \a parent as the parent object.
391
392//! [nameserver-port]
393 \note Setting the port number to any value other than the default (53) can
394 cause the name resolution to fail, depending on the operating system
395 limitations and firewalls, if the nameserverProtocol() to be used
396 QDnsLookup::Standard. Notably, the Windows API used by QDnsLookup is unable
397 to handle alternate port numbers.
398//! [nameserver-port]
399*/
400QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
401 : QObject(*new QDnsLookupPrivate, parent)
402{
403 Q_D(QDnsLookup);
404 d->name = name;
405 d->type = type;
406 d->port = port;
407 d->nameserver = nameserver;
408}
409
410/*!
411 \since 6.8
412
413 Constructs a QDnsLookup object to issue a query for \a name of record type
414 \a type, using the DNS server \a nameserver running on port \a port, and
415 sets \a parent as the parent object.
416
417 The query will be sent using \a protocol, if supported. Use
418 isProtocolSupported() to check if it is supported.
419
420 \include qdnslookup.cpp nameserver-port
421*/
422QDnsLookup::QDnsLookup(Type type, const QString &name, Protocol protocol,
423 const QHostAddress &nameserver, quint16 port, QObject *parent)
424 : QObject(*new QDnsLookupPrivate, parent)
425{
426 Q_D(QDnsLookup);
427 d->name = name;
428 d->type = type;
429 d->nameserver = nameserver;
430 d->port = port;
431 d->protocol = protocol;
432}
433
434/*!
435 Destroys the QDnsLookup object.
436
437 It is safe to delete a QDnsLookup object even if it is not finished, you
438 will simply never receive its results.
439*/
440
441QDnsLookup::~QDnsLookup()
442{
443}
444
445/*!
446 \since 6.8
447 \property QDnsLookup::authenticData
448 \brief whether the reply was authenticated by the resolver.
449
450 QDnsLookup does not perform the authentication itself. Instead, it trusts
451 the name server that was queried to perform the authentication and report
452 it. The application is responsible for determining if any servers it
453 configured with setNameserver() are trustworthy; if no server was set,
454 QDnsLookup obeys system configuration on whether responses should be
455 trusted.
456
457 This property may be set even if error() indicates a resolver error
458 occurred.
459
460 \sa setNameserver(), nameserverProtocol()
461*/
462bool QDnsLookup::isAuthenticData() const
463{
464 return d_func()->reply.authenticData;
465}
466
467/*!
468 \property QDnsLookup::error
469 \brief the type of error that occurred if the DNS lookup failed, or NoError.
470*/
471
472QDnsLookup::Error QDnsLookup::error() const
473{
474 return d_func()->reply.error;
475}
476
477/*!
478 \property QDnsLookup::errorString
479 \brief a human-readable description of the error if the DNS lookup failed.
480*/
481
482QString QDnsLookup::errorString() const
483{
484 return d_func()->reply.errorString;
485}
486
487/*!
488 Returns whether the reply has finished or was aborted.
489*/
490
491bool QDnsLookup::isFinished() const
492{
493 return d_func()->isFinished;
494}
495
496/*!
497 \property QDnsLookup::name
498 \brief the name to lookup.
499
500 If the name to look up is empty, QDnsLookup will attempt to resolve the
501 root domain of DNS. That query is usually performed with QDnsLookup::type
502 set to \l{QDnsLookup::Type}{NS}.
503
504 \note The name will be encoded using IDNA, which means it's unsuitable for
505 querying SRV records compatible with the DNS-SD specification.
506*/
507
508QString QDnsLookup::name() const
509{
510 return d_func()->name;
511}
512
513void QDnsLookup::setName(const QString &name)
514{
515 Q_D(QDnsLookup);
516 d->name = name;
517}
518
519QBindable<QString> QDnsLookup::bindableName()
520{
521 Q_D(QDnsLookup);
522 return &d->name;
523}
524
525/*!
526 \property QDnsLookup::type
527 \brief the type of DNS lookup.
528*/
529
530QDnsLookup::Type QDnsLookup::type() const
531{
532 return d_func()->type;
533}
534
535void QDnsLookup::setType(Type type)
536{
537 Q_D(QDnsLookup);
538 d->type = type;
539}
540
541QBindable<QDnsLookup::Type> QDnsLookup::bindableType()
542{
543 Q_D(QDnsLookup);
544 return &d->type;
545}
546
547/*!
548 \property QDnsLookup::nameserver
549 \brief the nameserver to use for DNS lookup.
550*/
551
552QHostAddress QDnsLookup::nameserver() const
553{
554 return d_func()->nameserver;
555}
556
557void QDnsLookup::setNameserver(const QHostAddress &nameserver)
558{
559 Q_D(QDnsLookup);
560 d->nameserver = nameserver;
561}
562
563QBindable<QHostAddress> QDnsLookup::bindableNameserver()
564{
565 Q_D(QDnsLookup);
566 return &d->nameserver;
567}
568
569/*!
570 \property QDnsLookup::nameserverPort
571 \since 6.6
572 \brief the port number of nameserver to use for DNS lookup.
573
574 The value of 0 indicates that QDnsLookup should use the default port for
575 the nameserverProtocol().
576
577 \include qdnslookup.cpp nameserver-port
578*/
579
580quint16 QDnsLookup::nameserverPort() const
581{
582 return d_func()->port;
583}
584
585void QDnsLookup::setNameserverPort(quint16 nameserverPort)
586{
587 Q_D(QDnsLookup);
588 d->port = nameserverPort;
589}
590
591QBindable<quint16> QDnsLookup::bindableNameserverPort()
592{
593 Q_D(QDnsLookup);
594 return &d->port;
595}
596
597/*!
598 \property QDnsLookup::nameserverProtocol
599 \since 6.8
600 \brief the protocol to use when sending the DNS query
601
602 \sa isProtocolSupported()
603*/
604QDnsLookup::Protocol QDnsLookup::nameserverProtocol() const
605{
606 return d_func()->protocol;
607}
608
609void QDnsLookup::setNameserverProtocol(Protocol protocol)
610{
611 d_func()->protocol = protocol;
612}
613
614QBindable<QDnsLookup::Protocol> QDnsLookup::bindableNameserverProtocol()
615{
616 return &d_func()->protocol;
617}
618
619/*!
620 \fn void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
621 \since 6.6
622
623 Sets the nameserver to \a nameserver and the port to \a port.
624
625 \include qdnslookup.cpp nameserver-port
626
627 \sa QDnsLookup::nameserver, QDnsLookup::nameserverPort
628*/
629
630void QDnsLookup::setNameserver(Protocol protocol, const QHostAddress &nameserver, quint16 port)
631{
632 Qt::beginPropertyUpdateGroup();
633 setNameserver(nameserver);
634 setNameserverPort(port);
635 setNameserverProtocol(protocol);
636 Qt::endPropertyUpdateGroup();
637}
638
639/*!
640 Returns the list of canonical name records associated with this lookup.
641*/
642
643QList<QDnsDomainNameRecord> QDnsLookup::canonicalNameRecords() const
644{
645 return d_func()->reply.canonicalNameRecords;
646}
647
648/*!
649 Returns the list of host address records associated with this lookup.
650*/
651
652QList<QDnsHostAddressRecord> QDnsLookup::hostAddressRecords() const
653{
654 return d_func()->reply.hostAddressRecords;
655}
656
657/*!
658 Returns the list of mail exchange records associated with this lookup.
659
660 The records are sorted according to
661 \l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them
662 to connect to servers, you should try them in the order they are listed.
663*/
664
665QList<QDnsMailExchangeRecord> QDnsLookup::mailExchangeRecords() const
666{
667 return d_func()->reply.mailExchangeRecords;
668}
669
670/*!
671 Returns the list of name server records associated with this lookup.
672*/
673
674QList<QDnsDomainNameRecord> QDnsLookup::nameServerRecords() const
675{
676 return d_func()->reply.nameServerRecords;
677}
678
679/*!
680 Returns the list of pointer records associated with this lookup.
681*/
682
683QList<QDnsDomainNameRecord> QDnsLookup::pointerRecords() const
684{
685 return d_func()->reply.pointerRecords;
686}
687
688/*!
689 Returns the list of service records associated with this lookup.
690
691 The records are sorted according to
692 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them
693 to connect to servers, you should try them in the order they are listed.
694*/
695
696QList<QDnsServiceRecord> QDnsLookup::serviceRecords() const
697{
698 return d_func()->reply.serviceRecords;
699}
700
701/*!
702 Returns the list of text records associated with this lookup.
703*/
704
705QList<QDnsTextRecord> QDnsLookup::textRecords() const
706{
707 return d_func()->reply.textRecords;
708}
709
710/*!
711 \since 6.8
712 Returns the list of TLS association records associated with this lookup.
713
714 According to the standards relating to DNS-based Authentication of Named
715 Entities (DANE), this field should be ignored and must not be used for
716 verifying the authentity of a given server if the authenticity of the DNS
717 reply cannot itself be confirmed. See isAuthenticData() for more
718 information.
719 */
720QList<QDnsTlsAssociationRecord> QDnsLookup::tlsAssociationRecords() const
721{
722 return d_func()->reply.tlsAssociationRecords;
723}
724
725#if QT_CONFIG(ssl)
726/*!
727 \since 6.8
728 Sets the \a sslConfiguration to use for outgoing DNS-over-TLS connections.
729
730 \sa sslConfiguration(), QSslSocket::setSslConfiguration()
731*/
732void QDnsLookup::setSslConfiguration(const QSslConfiguration &sslConfiguration)
733{
734 Q_D(QDnsLookup);
735 d->sslConfiguration.emplace(sslConfiguration);
736}
737
738/*!
739 Returns the current SSL configuration.
740
741 \sa setSslConfiguration()
742*/
743QSslConfiguration QDnsLookup::sslConfiguration() const
744{
745 const Q_D(QDnsLookup);
746 return d->sslConfiguration.value_or(QSslConfiguration::defaultConfiguration());
747}
748#endif
749
750/*!
751 Aborts the DNS lookup operation.
752
753 If the lookup is already finished, does nothing.
754*/
755
756void QDnsLookup::abort()
757{
758 Q_D(QDnsLookup);
759 if (d->runnable) {
760 d->runnable = nullptr;
761 d->reply = QDnsLookupReply();
762 d->reply.error = QDnsLookup::OperationCancelledError;
763 d->reply.errorString = tr("Operation cancelled");
764 d->isFinished = true;
765 emit finished();
766 }
767}
768
769/*!
770 Performs the DNS lookup.
771
772 The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion.
773*/
774
775void QDnsLookup::lookup()
776{
777 Q_D(QDnsLookup);
778 d->isFinished = false;
779 d->reply = QDnsLookupReply();
780 if (!QCoreApplication::instanceExists()) {
781 // NOT qCWarning because this isn't a result of the lookup
782 qWarning("QDnsLookup requires a QCoreApplication");
783 return;
784 }
785
786 auto l = [this](const QDnsLookupReply &reply) {
787 Q_D(QDnsLookup);
788 if (d->runnable == sender()) {
789#ifdef QDNSLOOKUP_DEBUG
790 qDebug("DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString));
791#endif
792#if QT_CONFIG(ssl)
793 d->sslConfiguration = std::move(reply.sslConfiguration);
794#endif
795 d->reply = reply;
796 d->runnable = nullptr;
797 d->isFinished = true;
798 emit finished();
799 }
800 };
801
802 d->runnable = new QDnsLookupRunnable(d);
803 connect(d->runnable, &QDnsLookupRunnable::finished, this, l,
804 Qt::BlockingQueuedConnection);
805 theDnsLookupThreadPool->start(d->runnable);
806}
807
808/*!
809 \class QDnsDomainNameRecord
810 \brief The QDnsDomainNameRecord class stores information about a domain
811 name record.
812
813 \inmodule QtNetwork
814 \ingroup network
815 \ingroup shared
816
817 When performing a name server lookup, zero or more records will be returned.
818 Each record is represented by a QDnsDomainNameRecord instance.
819
820 \sa QDnsLookup
821*/
822
823/*!
824 Constructs an empty domain name record object.
825*/
826
827QDnsDomainNameRecord::QDnsDomainNameRecord()
828 : d(new QDnsDomainNameRecordPrivate)
829{
830}
831
832/*!
833 Constructs a copy of \a other.
834*/
835
836QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other)
837 : d(other.d)
838{
839}
840
841/*!
842 Destroys a domain name record.
843*/
844
845QDnsDomainNameRecord::~QDnsDomainNameRecord()
846{
847}
848
849/*!
850 Returns the name for this record.
851*/
852
853QString QDnsDomainNameRecord::name() const
854{
855 return d->name;
856}
857
858/*!
859 Returns the duration in seconds for which this record is valid.
860*/
861
862quint32 QDnsDomainNameRecord::timeToLive() const
863{
864 return d->timeToLive;
865}
866
867/*!
868 Returns the value for this domain name record.
869*/
870
871QString QDnsDomainNameRecord::value() const
872{
873 return d->value;
874}
875
876/*!
877 Assigns the data of the \a other object to this record object,
878 and returns a reference to it.
879*/
880
881QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other)
882{
883 d = other.d;
884 return *this;
885}
886
887/*!
888 \fn void QDnsDomainNameRecord::swap(QDnsDomainNameRecord &other)
889 \memberswap{domain-name record instance}
890*/
891
892/*!
893 \class QDnsHostAddressRecord
894 \brief The QDnsHostAddressRecord class stores information about a host
895 address record.
896
897 \inmodule QtNetwork
898 \ingroup network
899 \ingroup shared
900
901 When performing an address lookup, zero or more records will be
902 returned. Each record is represented by a QDnsHostAddressRecord instance.
903
904 \sa QDnsLookup
905*/
906
907/*!
908 Constructs an empty host address record object.
909*/
910
911QDnsHostAddressRecord::QDnsHostAddressRecord()
912 : d(new QDnsHostAddressRecordPrivate)
913{
914}
915
916/*!
917 Constructs a copy of \a other.
918*/
919
920QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other)
921 : d(other.d)
922{
923}
924
925/*!
926 Destroys a host address record.
927*/
928
929QDnsHostAddressRecord::~QDnsHostAddressRecord()
930{
931}
932
933/*!
934 Returns the name for this record.
935*/
936
937QString QDnsHostAddressRecord::name() const
938{
939 return d->name;
940}
941
942/*!
943 Returns the duration in seconds for which this record is valid.
944*/
945
946quint32 QDnsHostAddressRecord::timeToLive() const
947{
948 return d->timeToLive;
949}
950
951/*!
952 Returns the value for this host address record.
953*/
954
955QHostAddress QDnsHostAddressRecord::value() const
956{
957 return d->value;
958}
959
960/*!
961 Assigns the data of the \a other object to this record object,
962 and returns a reference to it.
963*/
964
965QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other)
966{
967 d = other.d;
968 return *this;
969}
970
971/*!
972 \fn void QDnsHostAddressRecord::swap(QDnsHostAddressRecord &other)
973 \memberswap{host address record instance}
974*/
975
976/*!
977 \class QDnsMailExchangeRecord
978 \brief The QDnsMailExchangeRecord class stores information about a DNS MX record.
979
980 \inmodule QtNetwork
981 \ingroup network
982 \ingroup shared
983
984 When performing a lookup on a service, zero or more records will be
985 returned. Each record is represented by a QDnsMailExchangeRecord instance.
986
987 The meaning of the fields is defined in
988 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
989
990 \sa QDnsLookup
991*/
992
993/*!
994 Constructs an empty mail exchange record object.
995*/
996
997QDnsMailExchangeRecord::QDnsMailExchangeRecord()
998 : d(new QDnsMailExchangeRecordPrivate)
999{
1000}
1001
1002/*!
1003 Constructs a copy of \a other.
1004*/
1005
1006QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other)
1007 : d(other.d)
1008{
1009}
1010
1011/*!
1012 Destroys a mail exchange record.
1013*/
1014
1015QDnsMailExchangeRecord::~QDnsMailExchangeRecord()
1016{
1017}
1018
1019/*!
1020 Returns the domain name of the mail exchange for this record.
1021*/
1022
1023QString QDnsMailExchangeRecord::exchange() const
1024{
1025 return d->exchange;
1026}
1027
1028/*!
1029 Returns the name for this record.
1030*/
1031
1032QString QDnsMailExchangeRecord::name() const
1033{
1034 return d->name;
1035}
1036
1037/*!
1038 Returns the preference for this record.
1039*/
1040
1041quint16 QDnsMailExchangeRecord::preference() const
1042{
1043 return d->preference;
1044}
1045
1046/*!
1047 Returns the duration in seconds for which this record is valid.
1048*/
1049
1050quint32 QDnsMailExchangeRecord::timeToLive() const
1051{
1052 return d->timeToLive;
1053}
1054
1055/*!
1056 Assigns the data of the \a other object to this record object,
1057 and returns a reference to it.
1058*/
1059
1060QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other)
1061{
1062 d = other.d;
1063 return *this;
1064}
1065/*!
1066 \fn void QDnsMailExchangeRecord::swap(QDnsMailExchangeRecord &other)
1067 \memberswap{mail exchange record}
1068*/
1069
1070/*!
1071 \class QDnsServiceRecord
1072 \brief The QDnsServiceRecord class stores information about a DNS SRV record.
1073
1074 \inmodule QtNetwork
1075 \ingroup network
1076 \ingroup shared
1077
1078 When performing a lookup on a service, zero or more records will be
1079 returned. Each record is represented by a QDnsServiceRecord instance.
1080
1081 The meaning of the fields is defined in
1082 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}.
1083
1084 \sa QDnsLookup
1085*/
1086
1087/*!
1088 Constructs an empty service record object.
1089*/
1090
1091QDnsServiceRecord::QDnsServiceRecord()
1092 : d(new QDnsServiceRecordPrivate)
1093{
1094}
1095
1096/*!
1097 Constructs a copy of \a other.
1098*/
1099
1100QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other)
1101 : d(other.d)
1102{
1103}
1104
1105/*!
1106 Destroys a service record.
1107*/
1108
1109QDnsServiceRecord::~QDnsServiceRecord()
1110{
1111}
1112
1113/*!
1114 Returns the name for this record.
1115*/
1116
1117QString QDnsServiceRecord::name() const
1118{
1119 return d->name;
1120}
1121
1122/*!
1123 Returns the port on the target host for this service record.
1124*/
1125
1126quint16 QDnsServiceRecord::port() const
1127{
1128 return d->port;
1129}
1130
1131/*!
1132 Returns the priority for this service record.
1133
1134 A client must attempt to contact the target host with the lowest-numbered
1135 priority.
1136*/
1137
1138quint16 QDnsServiceRecord::priority() const
1139{
1140 return d->priority;
1141}
1142
1143/*!
1144 Returns the domain name of the target host for this service record.
1145*/
1146
1147QString QDnsServiceRecord::target() const
1148{
1149 return d->target;
1150}
1151
1152/*!
1153 Returns the duration in seconds for which this record is valid.
1154*/
1155
1156quint32 QDnsServiceRecord::timeToLive() const
1157{
1158 return d->timeToLive;
1159}
1160
1161/*!
1162 Returns the weight for this service record.
1163
1164 The weight field specifies a relative weight for entries with the same
1165 priority. Entries with higher weights should be selected with a higher
1166 probability.
1167*/
1168
1169quint16 QDnsServiceRecord::weight() const
1170{
1171 return d->weight;
1172}
1173
1174/*!
1175 Assigns the data of the \a other object to this record object,
1176 and returns a reference to it.
1177*/
1178
1179QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other)
1180{
1181 d = other.d;
1182 return *this;
1183}
1184/*!
1185 \fn void QDnsServiceRecord::swap(QDnsServiceRecord &other)
1186 \memberswap{service record instance}
1187*/
1188
1189/*!
1190 \class QDnsTextRecord
1191 \brief The QDnsTextRecord class stores information about a DNS TXT record.
1192
1193 \inmodule QtNetwork
1194 \ingroup network
1195 \ingroup shared
1196
1197 When performing a text lookup, zero or more records will be
1198 returned. Each record is represented by a QDnsTextRecord instance.
1199
1200 The meaning of the fields is defined in
1201 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
1202
1203 \sa QDnsLookup
1204*/
1205
1206/*!
1207 Constructs an empty text record object.
1208*/
1209
1210QDnsTextRecord::QDnsTextRecord()
1211 : d(new QDnsTextRecordPrivate)
1212{
1213}
1214
1215/*!
1216 Constructs a copy of \a other.
1217*/
1218
1219QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other)
1220 : d(other.d)
1221{
1222}
1223
1224/*!
1225 Destroys a text record.
1226*/
1227
1228QDnsTextRecord::~QDnsTextRecord()
1229{
1230}
1231
1232/*!
1233 Returns the name for this text record.
1234*/
1235
1236QString QDnsTextRecord::name() const
1237{
1238 return d->name;
1239}
1240
1241/*!
1242 Returns the duration in seconds for which this record is valid.
1243*/
1244
1245quint32 QDnsTextRecord::timeToLive() const
1246{
1247 return d->timeToLive;
1248}
1249
1250/*!
1251 Returns the values for this text record.
1252*/
1253
1254QList<QByteArray> QDnsTextRecord::values() const
1255{
1256 return d->values;
1257}
1258
1259/*!
1260 Assigns the data of the \a other object to this record object,
1261 and returns a reference to it.
1262*/
1263
1264QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
1265{
1266 d = other.d;
1267 return *this;
1268}
1269/*!
1270 \fn void QDnsTextRecord::swap(QDnsTextRecord &other)
1271 \memberswap{text record instance}
1272*/
1273
1274/*!
1275 \class QDnsTlsAssociationRecord
1276 \since 6.8
1277 \brief The QDnsTlsAssociationRecord class stores information about a DNS TLSA record.
1278
1279 \inmodule QtNetwork
1280 \ingroup network
1281 \ingroup shared
1282
1283 When performing a text lookup, zero or more records will be returned. Each
1284 record is represented by a QDnsTlsAssociationRecord instance.
1285
1286 The meaning of the fields is defined in \l{RFC 6698}.
1287
1288 \sa QDnsLookup
1289*/
1290
1291QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
1292
1293/*!
1294 \enum QDnsTlsAssociationRecord::CertificateUsage
1295
1296 This enumeration contains valid values for the certificate usage field of
1297 TLS Association queries. The following list is up-to-date with \l{RFC 6698}
1298 section 2.1.1 and RFC 7218 section 2.1. Please refer to those documents for
1299 authoritative instructions on interpreting this enumeration.
1300
1301 \value CertificateAuthorityConstrait
1302 Indicates the record includes an association to a specific Certificate
1303 Authority that must be found in the TLS server's certificate chain and
1304 must pass PKIX validation.
1305
1306 \value ServiceCertificateConstraint
1307 Indicates the record includes an association to a certificate that must
1308 match the end entity certificate provided by the TLS server and must
1309 pass PKIX validation.
1310
1311 \value TrustAnchorAssertion
1312 Indicates the record includes an association to a certificate that MUST
1313 be used as the ultimate trust anchor to validate the TLS server's
1314 certificate and must pass PKIX validation.
1315
1316 \value DomainIssuedCertificate
1317 Indicates the record includes an association to a certificate that must
1318 match the end entity certificate provided by the TLS server. PKIX
1319 validation is not tested.
1320
1321 \value PrivateUse
1322 No standard meaning applied.
1323
1324 \value PKIX_TA
1325 Alias; mnemonic for Public Key Infrastructure Trust Anchor
1326
1327 \value PKIX_EE
1328 Alias; mnemonic for Public Key Infrastructure End Entity
1329
1330 \value DANE_TA
1331 Alias; mnemonic for DNS-based Authentication of Named Entities Trust Anchor
1332
1333 \value DANE_EE
1334 Alias; mnemonic for DNS-based Authentication of Named Entities End Entity
1335
1336 \value PrivCert
1337 Alias
1338
1339 Other values are currently reserved, but may be unreserved by future
1340 standards. This enumeration can be used for those values even if no
1341 enumerator is provided.
1342
1343 \sa usage()
1344*/
1345
1346/*!
1347 \enum QDnsTlsAssociationRecord::Selector
1348
1349 This enumeration contains valid values for the selector field of TLS
1350 Association queries. The following list is up-to-date with \l{RFC 6698}
1351 section 2.1.2 and RFC 7218 section 2.2. Please refer to those documents for
1352 authoritative instructions on interpreting this enumeration.
1353
1354 \value FullCertificate
1355 Indicates this record refers to the full certificate in its binary
1356 structure form.
1357
1358 \value SubjectPublicKeyInfo
1359 Indicates the record refers to the certificate's subject and public
1360 key information, in DER-encoded binary structure form.
1361
1362 \value PrivateUse
1363 No standard meaning applied.
1364
1365 \value Cert
1366 Alias
1367
1368 \value SPKI
1369 Alias
1370
1371 \value PrivSel
1372 Alias
1373
1374 Other values are currently reserved, but may be unreserved by future
1375 standards. This enumeration can be used for those values even if no
1376 enumerator is provided.
1377
1378 \sa selector()
1379*/
1380
1381/*!
1382 \enum QDnsTlsAssociationRecord::MatchingType
1383
1384 This enumeration contains valid values for the matching type field of TLS
1385 Association queries. The following list is up-to-date with \l{RFC 6698}
1386 section 2.1.3 and RFC 7218 section 2.3. Please refer to those documents for
1387 authoritative instructions on interpreting this enumeration.
1388
1389 \value Exact
1390 Indicates this the certificate or SPKI data is stored verbatim in this
1391 record.
1392
1393 \value Sha256
1394 Indicates this a SHA-256 checksum of the the certificate or SPKI data
1395 present in this record.
1396
1397 \value Sha512
1398 Indicates this a SHA-512 checksum of the the certificate or SPKI data
1399 present in this record.
1400
1401 \value PrivateUse
1402 No standard meaning applied.
1403
1404 \value PrivMatch
1405 Alias
1406
1407 Other values are currently reserved, but may be unreserved by future
1408 standards. This enumeration can be used for those values even if no
1409 enumerator is provided.
1410
1411 \sa matchType()
1412*/
1413
1414/*!
1415 Constructs an empty TLS Association record.
1416 */
1417QDnsTlsAssociationRecord::QDnsTlsAssociationRecord()
1418 : d(new QDnsTlsAssociationRecordPrivate)
1419{
1420}
1421
1422/*!
1423 Constructs a copy of \a other.
1424 */
1425QDnsTlsAssociationRecord::QDnsTlsAssociationRecord(const QDnsTlsAssociationRecord &other) = default;
1426
1427/*!
1428 Moves the content of \a other into this object.
1429 */
1431QDnsTlsAssociationRecord::operator=(const QDnsTlsAssociationRecord &other) = default;
1432
1433/*!
1434 Destroys this TLS Association record object.
1435 */
1437
1438/*!
1439 Returns the name of this record.
1440*/
1441QString QDnsTlsAssociationRecord::name() const
1442{
1443 return d->name;
1444}
1445
1446/*!
1447 Returns the duration in seconds for which this record is valid.
1448*/
1449quint32 QDnsTlsAssociationRecord::timeToLive() const
1450{
1451 return d->timeToLive;
1452}
1453
1454/*!
1455 Returns the certificate usage field for this record.
1456 */
1457QDnsTlsAssociationRecord::CertificateUsage QDnsTlsAssociationRecord::usage() const
1458{
1459 return d->usage;
1460}
1461
1462/*!
1463 Returns the selector field for this record.
1464 */
1465QDnsTlsAssociationRecord::Selector QDnsTlsAssociationRecord::selector() const
1466{
1467 return d->selector;
1468}
1469
1470/*!
1471 Returns the match type field for this record.
1472 */
1473QDnsTlsAssociationRecord::MatchingType QDnsTlsAssociationRecord::matchType() const
1474{
1475 return d->matchType;
1476}
1477
1478/*!
1479 Returns the binary data field for this record. The interpretation of this
1480 binary data depends on the three numeric fields provided by
1481 certificateUsage(), selector(), and matchType().
1482
1483 Do note this is a binary field, even for the checksums, similar to what
1484 QCyrptographicHash::result() returns.
1485 */
1486QByteArray QDnsTlsAssociationRecord::value() const
1487{
1488 return d->value;
1489}
1490
1491static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
1492{
1493 QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.';
1494 if (label.isEmpty())
1495 return QDnsLookupRunnable::EncodedLabel(1, rootDomain);
1496
1497 QString encodedLabel = qt_ACE_do(label, ToAceOnly, ForbidLeadingDot);
1498#ifdef Q_OS_WIN
1499 return encodedLabel;
1500#else
1501 return std::move(encodedLabel).toLatin1();
1502#endif
1503}
1504
1508 requestType(d->type),
1509 port(d->port),
1511{
1512 if (port == 0)
1513 port = QDnsLookup::defaultPortForProtocol(protocol);
1514#if QT_CONFIG(ssl)
1515 sslConfiguration = d->sslConfiguration;
1516#endif
1517}
1518
1520{
1521 QDnsLookupReply reply;
1522
1523 // Validate input.
1524 if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) {
1525 reply.error = QDnsLookup::InvalidRequestError;
1526 reply.errorString = QDnsLookup::tr("Invalid domain name");
1527 } else {
1528 // Perform request.
1529 query(&reply);
1530
1531 // Sort results.
1532 qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
1533 qt_qdnsservicerecord_sort(reply.serviceRecords);
1534 }
1535
1536 emit finished(reply);
1537
1538 // maybe print the lookup error as warning
1539 switch (reply.error) {
1540 case QDnsLookup::NoError:
1541 case QDnsLookup::OperationCancelledError:
1542 case QDnsLookup::NotFoundError:
1543 case QDnsLookup::ServerFailureError:
1544 case QDnsLookup::ServerRefusedError:
1545 case QDnsLookup::TimeoutError:
1546 break; // no warning for these
1547
1548 case QDnsLookup::ResolverError:
1549 case QDnsLookup::InvalidRequestError:
1550 case QDnsLookup::InvalidReplyError:
1551 qCWarning(lcDnsLookup()).nospace()
1552 << "DNS lookup failed (" << reply.error << "): "
1553 << qUtf16Printable(reply.errorString)
1554 << "; request was " << this; // continues below
1555 }
1556}
1557
1558inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
1559{
1560 // continued: print the information about the request
1561 d << r->requestName.left(MaxDomainNameLength);
1562 if (r->requestName.size() > MaxDomainNameLength)
1563 d << "... (truncated)";
1564 d << " type " << r->requestType;
1565 if (!r->nameserver.isNull()) {
1566 d << " to nameserver " << qUtf16Printable(r->nameserver.toString())
1567 << " port " << (r->port ? r->port : QDnsLookup::defaultPortForProtocol(r->protocol));
1568 switch (r->protocol) {
1569 case QDnsLookup::Standard:
1570 break;
1571 case QDnsLookup::DnsOverTls:
1572 d << " (TLS)";
1573 }
1574 }
1575 return d;
1576}
1577
1578#if QT_CONFIG(ssl)
1579static constexpr std::chrono::milliseconds DnsOverTlsConnectTimeout(15'000);
1580static constexpr std::chrono::milliseconds DnsOverTlsTimeout(120'000);
1581static constexpr quint8 DnsAuthenticDataBit = 0x20;
1582
1583static int makeReplyErrorFromSocket(QDnsLookupReply *reply, const QAbstractSocket *socket)
1584{
1585 QDnsLookup::Error error = [&] {
1586 switch (socket->error()) {
1587 case QAbstractSocket::SocketTimeoutError:
1588 case QAbstractSocket::ProxyConnectionTimeoutError:
1589 return QDnsLookup::TimeoutError;
1590 default:
1591 return QDnsLookup::ResolverError;
1592 }
1593 }();
1594 reply->setError(error, socket->errorString());
1595 return false;
1596}
1597
1598bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query,
1599 ReplyBuffer &response)
1600{
1601 QSslSocket socket;
1602 socket.setSslConfiguration(sslConfiguration.value_or(QSslConfiguration::defaultConfiguration()));
1603
1604# if QT_CONFIG(networkproxy)
1605 socket.setProtocolTag("domain-s"_L1);
1606# endif
1607
1608 // Request the name server attempt to authenticate the reply.
1609 query[3] |= DnsAuthenticDataBit;
1610
1611 do {
1612 quint16 size = qToBigEndian<quint16>(query.size());
1613 QDeadlineTimer timeout(DnsOverTlsTimeout);
1614
1615 socket.connectToHostEncrypted(nameserver.toString(), port);
1616 socket.write(reinterpret_cast<const char *>(&size), sizeof(size));
1617 socket.write(reinterpret_cast<const char *>(query.data()), query.size());
1618 if (!socket.waitForEncrypted(DnsOverTlsConnectTimeout.count()))
1619 break;
1620
1621 reply->sslConfiguration = socket.sslConfiguration();
1622
1623 // accumulate reply
1624 auto waitForBytes = [&](void *buffer, int count) {
1625 int remaining = timeout.remainingTime();
1626 while (remaining >= 0 && socket.bytesAvailable() < count) {
1627 if (!socket.waitForReadyRead(remaining))
1628 return false;
1629 }
1630 return socket.read(static_cast<char *>(buffer), count) == count;
1631 };
1632 if (!waitForBytes(&size, sizeof(size)))
1633 break;
1634
1635 // note: strictly speaking, we're allocating memory based on untrusted data
1636 // but in practice, due to limited range of the data type (16 bits),
1637 // the maximum allocation is small.
1638 size = qFromBigEndian(size);
1639 response.resize(size);
1640 if (waitForBytes(response.data(), size)) {
1641 // check if the AD bit is set; we'll trust it over TLS requests
1642 if (size >= 4)
1643 reply->authenticData = response[3] & DnsAuthenticDataBit;
1644 return true;
1645 }
1646 } while (false);
1647
1648 // handle errors
1649 return makeReplyErrorFromSocket(reply, &socket);
1650}
1651#else
1652bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query,
1653 ReplyBuffer &response)
1654{
1655 Q_UNUSED(query)
1656 Q_UNUSED(response)
1657 reply->setError(QDnsLookup::ResolverError, QDnsLookup::tr("SSL/TLS support not present"));
1658 return false;
1659}
1660#endif
1661
1662QT_END_NAMESPACE
1663
1664#include "moc_qdnslookup.cpp"
1665#include "moc_qdnslookup_p.cpp"
QDnsLookupRunnable(const QDnsLookupPrivate *d)
void run() override
Implement this pure virtual function in your subclass.
bool sendDnsOverTls(QDnsLookupReply *reply, QSpan< unsigned char > query, ReplyBuffer &response)
The QDnsTlsAssociationRecord class stores information about a DNS TLSA record.
Definition qdnslookup.h:146
Q_NETWORK_EXPORT ~QDnsTlsAssociationRecord()
Destroys this TLS Association record object.
#define Q_APPLICATION_STATIC(TYPE, NAME,...)
static void qt_qdnsmailexchangerecord_sort(QList< QDnsMailExchangeRecord > &records)
static void qt_qdnsservicerecord_sort(QList< QDnsServiceRecord > &records)
static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2)
static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
#define qCWarning(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)