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).
235
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.
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) || QT_CONFIG(android_dnsresolver)
292 || QT_CONFIG(harmony_dnsresolver) || defined(Q_OS_WIN)
293 switch (protocol) {
294 case QDnsLookup::Standard:
295# if QT_CONFIG(android_dnsresolver)
296 return qt_androidDnsResolverAvailable();
297# else
298 return true;
299# endif
300 case QDnsLookup::DnsOverTls:
301# if QT_CONFIG(ssl)
302 if (QSslSocket::supportsSsl())
303 return true;
304# endif
305 return false;
306 }
307#else
308 Q_UNUSED(protocol)
309#endif
310 return false;
311}
312
313/*!
314 \since 6.8
315
316 Returns the standard (default) port number for the protocol \a protocol.
317
318 \sa isProtocolSupported()
319*/
320quint16 QDnsLookup::defaultPortForProtocol(Protocol protocol) noexcept
321{
322 switch (protocol) {
323 case QDnsLookup::Standard:
324 return DnsPort;
325 case QDnsLookup::DnsOverTls:
326 return DnsOverTlsPort;
327 }
328 return 0; // will probably fail somewhere
329}
330
331/*!
332 \fn void QDnsLookup::finished()
333
334 This signal is emitted when the reply has finished processing.
335*/
336
337/*!
338 \fn void QDnsLookup::nameChanged(const QString &name)
339
340 This signal is emitted when the lookup \l name changes.
341 \a name is the new lookup name.
342*/
343
344/*!
345 \fn void QDnsLookup::typeChanged(QDnsLookup::Type type)
346
347 This signal is emitted when the lookup \l type changes.
348 \a type is the new lookup type.
349*/
350
351/*!
352 Constructs a QDnsLookup object and sets \a parent as the parent object.
353
354 The \l type property will default to QDnsLookup::A.
355*/
356
357QDnsLookup::QDnsLookup(QObject *parent)
358 : QObject(*new QDnsLookupPrivate, parent)
359{
360}
361
362/*!
363 Constructs a QDnsLookup object for the given \a type and \a name and sets
364 \a parent as the parent object.
365*/
366
367QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
368 : QObject(*new QDnsLookupPrivate, parent)
369{
370 Q_D(QDnsLookup);
371 d->name = name;
372 d->type = type;
373}
374
375/*!
376 \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
377 \since 5.4
378
379 Constructs a QDnsLookup object to issue a query for \a name of record type
380 \a type, using the DNS server \a nameserver running on the default DNS port,
381 and sets \a parent as the parent object.
382*/
383
384QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
385 : QDnsLookup(type, name, nameserver, 0, parent)
386{
387}
388
389/*!
390 \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
391 \since 6.6
392
393 Constructs a QDnsLookup object to issue a query for \a name of record type
394 \a type, using the DNS server \a nameserver running on port \a port, and
395 sets \a parent as the parent object.
396
397//! [nameserver-port]
398 \note Setting the port number to any value other than the default (53) can
399 cause the name resolution to fail, depending on the operating system
400 limitations and firewalls, if the nameserverProtocol() to be used
401 QDnsLookup::Standard. Notably, the Windows API used by QDnsLookup is unable
402 to handle alternate port numbers.
403//! [nameserver-port]
404*/
405QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
406 : QObject(*new QDnsLookupPrivate, parent)
407{
408 Q_D(QDnsLookup);
409 d->name = name;
410 d->type = type;
411 d->port = port;
412 d->nameserver = nameserver;
413}
414
415/*!
416 \since 6.8
417
418 Constructs a QDnsLookup object to issue a query for \a name of record type
419 \a type, using the DNS server \a nameserver running on port \a port, and
420 sets \a parent as the parent object.
421
422 The query will be sent using \a protocol, if supported. Use
423 isProtocolSupported() to check if it is supported.
424
425 \include qdnslookup.cpp nameserver-port
426*/
427QDnsLookup::QDnsLookup(Type type, const QString &name, Protocol protocol,
428 const QHostAddress &nameserver, quint16 port, QObject *parent)
429 : QObject(*new QDnsLookupPrivate, parent)
430{
431 Q_D(QDnsLookup);
432 d->name = name;
433 d->type = type;
434 d->nameserver = nameserver;
435 d->port = port;
436 d->protocol = protocol;
437}
438
439/*!
440 Destroys the QDnsLookup object.
441
442 It is safe to delete a QDnsLookup object even if it is not finished, you
443 will simply never receive its results.
444*/
445
446QDnsLookup::~QDnsLookup()
447{
448}
449
450/*!
451 \since 6.8
452 \property QDnsLookup::authenticData
453 \brief whether the reply was authenticated by the resolver.
454
455 QDnsLookup does not perform the authentication itself. Instead, it trusts
456 the name server that was queried to perform the authentication and report
457 it. The application is responsible for determining if any servers it
458 configured with setNameserver() are trustworthy; if no server was set,
459 QDnsLookup obeys system configuration on whether responses should be
460 trusted.
461
462 This property may be set even if error() indicates a resolver error
463 occurred.
464
465 \sa setNameserver(), nameserverProtocol()
466*/
467bool QDnsLookup::isAuthenticData() const
468{
469 return d_func()->reply.authenticData;
470}
471
472/*!
473 \property QDnsLookup::error
474 \brief the type of error that occurred if the DNS lookup failed, or NoError.
475*/
476
477QDnsLookup::Error QDnsLookup::error() const
478{
479 return d_func()->reply.error;
480}
481
482/*!
483 \property QDnsLookup::errorString
484 \brief a human-readable description of the error if the DNS lookup failed.
485*/
486
487QString QDnsLookup::errorString() const
488{
489 return d_func()->reply.errorString;
490}
491
492/*!
493 Returns whether the reply has finished or was aborted.
494*/
495
496bool QDnsLookup::isFinished() const
497{
498 return d_func()->isFinished;
499}
500
501/*!
502 \property QDnsLookup::name
503 \brief the name to lookup.
504
505 If the name to look up is empty, QDnsLookup will attempt to resolve the
506 root domain of DNS. That query is usually performed with QDnsLookup::type
507 set to \l{QDnsLookup::Type}{NS}.
508
509 \note The name will be encoded using IDNA, which means it's unsuitable for
510 querying SRV records compatible with the DNS-SD specification.
511*/
512
513QString QDnsLookup::name() const
514{
515 return d_func()->name;
516}
517
518void QDnsLookup::setName(const QString &name)
519{
520 Q_D(QDnsLookup);
521 d->name = name;
522}
523
524QBindable<QString> QDnsLookup::bindableName()
525{
526 Q_D(QDnsLookup);
527 return &d->name;
528}
529
530/*!
531 \property QDnsLookup::type
532 \brief the type of DNS lookup.
533*/
534
535QDnsLookup::Type QDnsLookup::type() const
536{
537 return d_func()->type;
538}
539
540void QDnsLookup::setType(Type type)
541{
542 Q_D(QDnsLookup);
543 d->type = type;
544}
545
546QBindable<QDnsLookup::Type> QDnsLookup::bindableType()
547{
548 Q_D(QDnsLookup);
549 return &d->type;
550}
551
552/*!
553 \property QDnsLookup::nameserver
554 \brief the nameserver to use for DNS lookup.
555*/
556
557QHostAddress QDnsLookup::nameserver() const
558{
559 return d_func()->nameserver;
560}
561
562void QDnsLookup::setNameserver(const QHostAddress &nameserver)
563{
564 Q_D(QDnsLookup);
565 d->nameserver = nameserver;
566}
567
568QBindable<QHostAddress> QDnsLookup::bindableNameserver()
569{
570 Q_D(QDnsLookup);
571 return &d->nameserver;
572}
573
574/*!
575 \property QDnsLookup::nameserverPort
576 \since 6.6
577 \brief the port number of nameserver to use for DNS lookup.
578
579 The value of 0 indicates that QDnsLookup should use the default port for
580 the nameserverProtocol().
581
582 \include qdnslookup.cpp nameserver-port
583*/
584
585quint16 QDnsLookup::nameserverPort() const
586{
587 return d_func()->port;
588}
589
590void QDnsLookup::setNameserverPort(quint16 nameserverPort)
591{
592 Q_D(QDnsLookup);
593 d->port = nameserverPort;
594}
595
596QBindable<quint16> QDnsLookup::bindableNameserverPort()
597{
598 Q_D(QDnsLookup);
599 return &d->port;
600}
601
602/*!
603 \property QDnsLookup::nameserverProtocol
604 \since 6.8
605 \brief the protocol to use when sending the DNS query
606
607 \sa isProtocolSupported()
608*/
609QDnsLookup::Protocol QDnsLookup::nameserverProtocol() const
610{
611 return d_func()->protocol;
612}
613
614void QDnsLookup::setNameserverProtocol(Protocol protocol)
615{
616 d_func()->protocol = protocol;
617}
618
619QBindable<QDnsLookup::Protocol> QDnsLookup::bindableNameserverProtocol()
620{
621 return &d_func()->protocol;
622}
623
624/*!
625 \fn void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
626 \since 6.6
627
628 Sets the nameserver to \a nameserver and the port to \a port.
629
630 \include qdnslookup.cpp nameserver-port
631
632 \sa QDnsLookup::nameserver, QDnsLookup::nameserverPort
633*/
634
635void QDnsLookup::setNameserver(Protocol protocol, const QHostAddress &nameserver, quint16 port)
636{
637 Qt::beginPropertyUpdateGroup();
638 setNameserver(nameserver);
639 setNameserverPort(port);
640 setNameserverProtocol(protocol);
641 Qt::endPropertyUpdateGroup();
642}
643
644/*!
645 Returns the list of canonical name records associated with this lookup.
646*/
647
648QList<QDnsDomainNameRecord> QDnsLookup::canonicalNameRecords() const
649{
650 return d_func()->reply.canonicalNameRecords;
651}
652
653/*!
654 Returns the list of host address records associated with this lookup.
655*/
656
657QList<QDnsHostAddressRecord> QDnsLookup::hostAddressRecords() const
658{
659 return d_func()->reply.hostAddressRecords;
660}
661
662/*!
663 Returns the list of mail exchange records associated with this lookup.
664
665 The records are sorted according to
666 \l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them
667 to connect to servers, you should try them in the order they are listed.
668*/
669
670QList<QDnsMailExchangeRecord> QDnsLookup::mailExchangeRecords() const
671{
672 return d_func()->reply.mailExchangeRecords;
673}
674
675/*!
676 Returns the list of name server records associated with this lookup.
677*/
678
679QList<QDnsDomainNameRecord> QDnsLookup::nameServerRecords() const
680{
681 return d_func()->reply.nameServerRecords;
682}
683
684/*!
685 Returns the list of pointer records associated with this lookup.
686*/
687
688QList<QDnsDomainNameRecord> QDnsLookup::pointerRecords() const
689{
690 return d_func()->reply.pointerRecords;
691}
692
693/*!
694 Returns the list of service records associated with this lookup.
695
696 The records are sorted according to
697 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them
698 to connect to servers, you should try them in the order they are listed.
699*/
700
701QList<QDnsServiceRecord> QDnsLookup::serviceRecords() const
702{
703 return d_func()->reply.serviceRecords;
704}
705
706/*!
707 Returns the list of text records associated with this lookup.
708*/
709
710QList<QDnsTextRecord> QDnsLookup::textRecords() const
711{
712 return d_func()->reply.textRecords;
713}
714
715/*!
716 \since 6.8
717 Returns the list of TLS association records associated with this lookup.
718
719 According to the standards relating to DNS-based Authentication of Named
720 Entities (DANE), this field should be ignored and must not be used for
721 verifying the authentity of a given server if the authenticity of the DNS
722 reply cannot itself be confirmed. See isAuthenticData() for more
723 information.
724 */
725QList<QDnsTlsAssociationRecord> QDnsLookup::tlsAssociationRecords() const
726{
727 return d_func()->reply.tlsAssociationRecords;
728}
729
730#if QT_CONFIG(ssl)
731/*!
732 \since 6.8
733 Sets the \a sslConfiguration to use for outgoing DNS-over-TLS connections.
734
735 \sa sslConfiguration(), QSslSocket::setSslConfiguration()
736*/
737void QDnsLookup::setSslConfiguration(const QSslConfiguration &sslConfiguration)
738{
739 Q_D(QDnsLookup);
740 d->sslConfiguration.emplace(sslConfiguration);
741}
742
743/*!
744 Returns the current SSL configuration.
745
746 \sa setSslConfiguration()
747*/
748QSslConfiguration QDnsLookup::sslConfiguration() const
749{
750 const Q_D(QDnsLookup);
751 return d->sslConfiguration.value_or(QSslConfiguration::defaultConfiguration());
752}
753#endif
754
755/*!
756 Aborts the DNS lookup operation.
757
758 If the lookup is already finished, does nothing.
759*/
760
761void QDnsLookup::abort()
762{
763 Q_D(QDnsLookup);
764 if (d->runnable) {
765 d->runnable = nullptr;
766 d->reply = QDnsLookupReply();
767 d->reply.error = QDnsLookup::OperationCancelledError;
768 d->reply.errorString = tr("Operation cancelled");
769 d->isFinished = true;
770 emit finished();
771 }
772}
773
774/*!
775 Performs the DNS lookup.
776
777 The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion.
778*/
779
780void QDnsLookup::lookup()
781{
782 Q_D(QDnsLookup);
783 d->isFinished = false;
784 d->reply = QDnsLookupReply();
785 if (!QCoreApplication::instanceExists()) {
786 // NOT qCWarning because this isn't a result of the lookup
787 qWarning("QDnsLookup requires a QCoreApplication");
788 return;
789 }
790
791 auto l = [this](const QDnsLookupReply &reply) {
792 Q_D(QDnsLookup);
793 if (d->runnable == sender()) {
794#ifdef QDNSLOOKUP_DEBUG
795 qDebug("DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString));
796#endif
797#if QT_CONFIG(ssl)
798 d->sslConfiguration = std::move(reply.sslConfiguration);
799#endif
800 d->reply = reply;
801 d->runnable = nullptr;
802 d->isFinished = true;
803 emit finished();
804 }
805 };
806
807 d->runnable = new QDnsLookupRunnable(d);
808 connect(d->runnable, &QDnsLookupRunnable::finished, this, l,
809 Qt::BlockingQueuedConnection);
810 theDnsLookupThreadPool->start(d->runnable);
811}
812
813/*!
814 \class QDnsDomainNameRecord
815 \brief The QDnsDomainNameRecord class stores information about a domain
816 name record.
817
818 \inmodule QtNetwork
819 \ingroup network
820 \ingroup shared
821
822 When performing a name server lookup, zero or more records will be returned.
823 Each record is represented by a QDnsDomainNameRecord instance.
824
825 \sa QDnsLookup
826*/
827
828/*!
829 Constructs an empty domain name record object.
830*/
831
832QDnsDomainNameRecord::QDnsDomainNameRecord()
833 : d(new QDnsDomainNameRecordPrivate)
834{
835}
836
837/*!
838 Constructs a copy of \a other.
839*/
840
841QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other)
842 : d(other.d)
843{
844}
845
846/*!
847 Destroys a domain name record.
848*/
849
850QDnsDomainNameRecord::~QDnsDomainNameRecord()
851{
852}
853
854/*!
855 Returns the name for this record.
856*/
857
858QString QDnsDomainNameRecord::name() const
859{
860 return d->name;
861}
862
863/*!
864 Returns the duration in seconds for which this record is valid.
865*/
866
867quint32 QDnsDomainNameRecord::timeToLive() const
868{
869 return d->timeToLive;
870}
871
872/*!
873 Returns the value for this domain name record.
874*/
875
876QString QDnsDomainNameRecord::value() const
877{
878 return d->value;
879}
880
881/*!
882 Assigns the data of the \a other object to this record object,
883 and returns a reference to it.
884*/
885
886QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other)
887{
888 d = other.d;
889 return *this;
890}
891
892/*!
893 \fn void QDnsDomainNameRecord::swap(QDnsDomainNameRecord &other)
894 \memberswap{domain-name record instance}
895*/
896
897/*!
898 \class QDnsHostAddressRecord
899 \brief The QDnsHostAddressRecord class stores information about a host
900 address record.
901
902 \inmodule QtNetwork
903 \ingroup network
904 \ingroup shared
905
906 When performing an address lookup, zero or more records will be
907 returned. Each record is represented by a QDnsHostAddressRecord instance.
908
909 \sa QDnsLookup
910*/
911
912/*!
913 Constructs an empty host address record object.
914*/
915
916QDnsHostAddressRecord::QDnsHostAddressRecord()
917 : d(new QDnsHostAddressRecordPrivate)
918{
919}
920
921/*!
922 Constructs a copy of \a other.
923*/
924
925QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other)
926 : d(other.d)
927{
928}
929
930/*!
931 Destroys a host address record.
932*/
933
934QDnsHostAddressRecord::~QDnsHostAddressRecord()
935{
936}
937
938/*!
939 Returns the name for this record.
940*/
941
942QString QDnsHostAddressRecord::name() const
943{
944 return d->name;
945}
946
947/*!
948 Returns the duration in seconds for which this record is valid.
949*/
950
951quint32 QDnsHostAddressRecord::timeToLive() const
952{
953 return d->timeToLive;
954}
955
956/*!
957 Returns the value for this host address record.
958*/
959
960QHostAddress QDnsHostAddressRecord::value() const
961{
962 return d->value;
963}
964
965/*!
966 Assigns the data of the \a other object to this record object,
967 and returns a reference to it.
968*/
969
970QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other)
971{
972 d = other.d;
973 return *this;
974}
975
976/*!
977 \fn void QDnsHostAddressRecord::swap(QDnsHostAddressRecord &other)
978 \memberswap{host address record instance}
979*/
980
981/*!
982 \class QDnsMailExchangeRecord
983 \brief The QDnsMailExchangeRecord class stores information about a DNS MX record.
984
985 \inmodule QtNetwork
986 \ingroup network
987 \ingroup shared
988
989 When performing a lookup on a service, zero or more records will be
990 returned. Each record is represented by a QDnsMailExchangeRecord instance.
991
992 The meaning of the fields is defined in
993 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
994
995 \sa QDnsLookup
996*/
997
998/*!
999 Constructs an empty mail exchange record object.
1000*/
1001
1002QDnsMailExchangeRecord::QDnsMailExchangeRecord()
1003 : d(new QDnsMailExchangeRecordPrivate)
1004{
1005}
1006
1007/*!
1008 Constructs a copy of \a other.
1009*/
1010
1011QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other)
1012 : d(other.d)
1013{
1014}
1015
1016/*!
1017 Destroys a mail exchange record.
1018*/
1019
1020QDnsMailExchangeRecord::~QDnsMailExchangeRecord()
1021{
1022}
1023
1024/*!
1025 Returns the domain name of the mail exchange for this record.
1026*/
1027
1028QString QDnsMailExchangeRecord::exchange() const
1029{
1030 return d->exchange;
1031}
1032
1033/*!
1034 Returns the name for this record.
1035*/
1036
1037QString QDnsMailExchangeRecord::name() const
1038{
1039 return d->name;
1040}
1041
1042/*!
1043 Returns the preference for this record.
1044*/
1045
1046quint16 QDnsMailExchangeRecord::preference() const
1047{
1048 return d->preference;
1049}
1050
1051/*!
1052 Returns the duration in seconds for which this record is valid.
1053*/
1054
1055quint32 QDnsMailExchangeRecord::timeToLive() const
1056{
1057 return d->timeToLive;
1058}
1059
1060/*!
1061 Assigns the data of the \a other object to this record object,
1062 and returns a reference to it.
1063*/
1064
1065QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other)
1066{
1067 d = other.d;
1068 return *this;
1069}
1070/*!
1071 \fn void QDnsMailExchangeRecord::swap(QDnsMailExchangeRecord &other)
1072 \memberswap{mail exchange record}
1073*/
1074
1075/*!
1076 \class QDnsServiceRecord
1077 \brief The QDnsServiceRecord class stores information about a DNS SRV record.
1078
1079 \inmodule QtNetwork
1080 \ingroup network
1081 \ingroup shared
1082
1083 When performing a lookup on a service, zero or more records will be
1084 returned. Each record is represented by a QDnsServiceRecord instance.
1085
1086 The meaning of the fields is defined in
1087 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}.
1088
1089 \sa QDnsLookup
1090*/
1091
1092/*!
1093 Constructs an empty service record object.
1094*/
1095
1096QDnsServiceRecord::QDnsServiceRecord()
1097 : d(new QDnsServiceRecordPrivate)
1098{
1099}
1100
1101/*!
1102 Constructs a copy of \a other.
1103*/
1104
1105QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other)
1106 : d(other.d)
1107{
1108}
1109
1110/*!
1111 Destroys a service record.
1112*/
1113
1114QDnsServiceRecord::~QDnsServiceRecord()
1115{
1116}
1117
1118/*!
1119 Returns the name for this record.
1120*/
1121
1122QString QDnsServiceRecord::name() const
1123{
1124 return d->name;
1125}
1126
1127/*!
1128 Returns the port on the target host for this service record.
1129*/
1130
1131quint16 QDnsServiceRecord::port() const
1132{
1133 return d->port;
1134}
1135
1136/*!
1137 Returns the priority for this service record.
1138
1139 A client must attempt to contact the target host with the lowest-numbered
1140 priority.
1141*/
1142
1143quint16 QDnsServiceRecord::priority() const
1144{
1145 return d->priority;
1146}
1147
1148/*!
1149 Returns the domain name of the target host for this service record.
1150*/
1151
1152QString QDnsServiceRecord::target() const
1153{
1154 return d->target;
1155}
1156
1157/*!
1158 Returns the duration in seconds for which this record is valid.
1159*/
1160
1161quint32 QDnsServiceRecord::timeToLive() const
1162{
1163 return d->timeToLive;
1164}
1165
1166/*!
1167 Returns the weight for this service record.
1168
1169 The weight field specifies a relative weight for entries with the same
1170 priority. Entries with higher weights should be selected with a higher
1171 probability.
1172*/
1173
1174quint16 QDnsServiceRecord::weight() const
1175{
1176 return d->weight;
1177}
1178
1179/*!
1180 Assigns the data of the \a other object to this record object,
1181 and returns a reference to it.
1182*/
1183
1184QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other)
1185{
1186 d = other.d;
1187 return *this;
1188}
1189/*!
1190 \fn void QDnsServiceRecord::swap(QDnsServiceRecord &other)
1191 \memberswap{service record instance}
1192*/
1193
1194/*!
1195 \class QDnsTextRecord
1196 \brief The QDnsTextRecord class stores information about a DNS TXT record.
1197
1198 \inmodule QtNetwork
1199 \ingroup network
1200 \ingroup shared
1201
1202 When performing a text lookup, zero or more records will be
1203 returned. Each record is represented by a QDnsTextRecord instance.
1204
1205 The meaning of the fields is defined in
1206 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
1207
1208 \sa QDnsLookup
1209*/
1210
1211/*!
1212 Constructs an empty text record object.
1213*/
1214
1215QDnsTextRecord::QDnsTextRecord()
1216 : d(new QDnsTextRecordPrivate)
1217{
1218}
1219
1220/*!
1221 Constructs a copy of \a other.
1222*/
1223
1224QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other)
1225 : d(other.d)
1226{
1227}
1228
1229/*!
1230 Destroys a text record.
1231*/
1232
1233QDnsTextRecord::~QDnsTextRecord()
1234{
1235}
1236
1237/*!
1238 Returns the name for this text record.
1239*/
1240
1241QString QDnsTextRecord::name() const
1242{
1243 return d->name;
1244}
1245
1246/*!
1247 Returns the duration in seconds for which this record is valid.
1248*/
1249
1250quint32 QDnsTextRecord::timeToLive() const
1251{
1252 return d->timeToLive;
1253}
1254
1255/*!
1256 Returns the values for this text record.
1257*/
1258
1259QList<QByteArray> QDnsTextRecord::values() const
1260{
1261 return d->values;
1262}
1263
1264/*!
1265 Assigns the data of the \a other object to this record object,
1266 and returns a reference to it.
1267*/
1268
1269QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
1270{
1271 d = other.d;
1272 return *this;
1273}
1274/*!
1275 \fn void QDnsTextRecord::swap(QDnsTextRecord &other)
1276 \memberswap{text record instance}
1277*/
1278
1279/*!
1280 \class QDnsTlsAssociationRecord
1281 \since 6.8
1282 \brief The QDnsTlsAssociationRecord class stores information about a DNS TLSA record.
1283
1284 \inmodule QtNetwork
1285 \ingroup network
1286 \ingroup shared
1287
1288 When performing a text lookup, zero or more records will be returned. Each
1289 record is represented by a QDnsTlsAssociationRecord instance.
1290
1291 The meaning of the fields is defined in \l{RFC 6698}.
1292
1293 \sa QDnsLookup
1294*/
1295
1296QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
1297
1298/*!
1299 \enum QDnsTlsAssociationRecord::CertificateUsage
1300
1301 This enumeration contains valid values for the certificate usage field of
1302 TLS Association queries. The following list is up-to-date with \l{RFC 6698}
1303 section 2.1.1 and RFC 7218 section 2.1. Please refer to those documents for
1304 authoritative instructions on interpreting this enumeration.
1305
1306 \value CertificateAuthorityConstrait
1307 Indicates the record includes an association to a specific Certificate
1308 Authority that must be found in the TLS server's certificate chain and
1309 must pass PKIX validation.
1310
1311 \value ServiceCertificateConstraint
1312 Indicates the record includes an association to a certificate that must
1313 match the end entity certificate provided by the TLS server and must
1314 pass PKIX validation.
1315
1316 \value TrustAnchorAssertion
1317 Indicates the record includes an association to a certificate that MUST
1318 be used as the ultimate trust anchor to validate the TLS server's
1319 certificate and must pass PKIX validation.
1320
1321 \value DomainIssuedCertificate
1322 Indicates the record includes an association to a certificate that must
1323 match the end entity certificate provided by the TLS server. PKIX
1324 validation is not tested.
1325
1326 \value PrivateUse
1327 No standard meaning applied.
1328
1329 \value PKIX_TA
1330 Alias; mnemonic for Public Key Infrastructure Trust Anchor
1331
1332 \value PKIX_EE
1333 Alias; mnemonic for Public Key Infrastructure End Entity
1334
1335 \value DANE_TA
1336 Alias; mnemonic for DNS-based Authentication of Named Entities Trust Anchor
1337
1338 \value DANE_EE
1339 Alias; mnemonic for DNS-based Authentication of Named Entities End Entity
1340
1341 \value PrivCert
1342 Alias
1343
1344 Other values are currently reserved, but may be unreserved by future
1345 standards. This enumeration can be used for those values even if no
1346 enumerator is provided.
1347
1348 \sa usage()
1349*/
1350
1351/*!
1352 \enum QDnsTlsAssociationRecord::Selector
1353
1354 This enumeration contains valid values for the selector field of TLS
1355 Association queries. The following list is up-to-date with \l{RFC 6698}
1356 section 2.1.2 and RFC 7218 section 2.2. Please refer to those documents for
1357 authoritative instructions on interpreting this enumeration.
1358
1359 \value FullCertificate
1360 Indicates this record refers to the full certificate in its binary
1361 structure form.
1362
1363 \value SubjectPublicKeyInfo
1364 Indicates the record refers to the certificate's subject and public
1365 key information, in DER-encoded binary structure form.
1366
1367 \value PrivateUse
1368 No standard meaning applied.
1369
1370 \value Cert
1371 Alias
1372
1373 \value SPKI
1374 Alias
1375
1376 \value PrivSel
1377 Alias
1378
1379 Other values are currently reserved, but may be unreserved by future
1380 standards. This enumeration can be used for those values even if no
1381 enumerator is provided.
1382
1383 \sa selector()
1384*/
1385
1386/*!
1387 \enum QDnsTlsAssociationRecord::MatchingType
1388
1389 This enumeration contains valid values for the matching type field of TLS
1390 Association queries. The following list is up-to-date with \l{RFC 6698}
1391 section 2.1.3 and RFC 7218 section 2.3. Please refer to those documents for
1392 authoritative instructions on interpreting this enumeration.
1393
1394 \value Exact
1395 Indicates this the certificate or SPKI data is stored verbatim in this
1396 record.
1397
1398 \value Sha256
1399 Indicates this a SHA-256 checksum of the the certificate or SPKI data
1400 present in this record.
1401
1402 \value Sha512
1403 Indicates this a SHA-512 checksum of the the certificate or SPKI data
1404 present in this record.
1405
1406 \value PrivateUse
1407 No standard meaning applied.
1408
1409 \value PrivMatch
1410 Alias
1411
1412 Other values are currently reserved, but may be unreserved by future
1413 standards. This enumeration can be used for those values even if no
1414 enumerator is provided.
1415
1416 \sa matchType()
1417*/
1418
1419/*!
1420 Constructs an empty TLS Association record.
1421 */
1422QDnsTlsAssociationRecord::QDnsTlsAssociationRecord()
1423 : d(new QDnsTlsAssociationRecordPrivate)
1424{
1425}
1426
1427/*!
1428 Constructs a copy of \a other.
1429 */
1430QDnsTlsAssociationRecord::QDnsTlsAssociationRecord(const QDnsTlsAssociationRecord &other) = default;
1431
1432/*!
1433 Moves the content of \a other into this object.
1434 */
1436QDnsTlsAssociationRecord::operator=(const QDnsTlsAssociationRecord &other) = default;
1437
1438/*!
1439 Destroys this TLS Association record object.
1440 */
1442
1443/*!
1444 Returns the name of this record.
1445*/
1446QString QDnsTlsAssociationRecord::name() const
1447{
1448 return d->name;
1449}
1450
1451/*!
1452 Returns the duration in seconds for which this record is valid.
1453*/
1454quint32 QDnsTlsAssociationRecord::timeToLive() const
1455{
1456 return d->timeToLive;
1457}
1458
1459/*!
1460 Returns the certificate usage field for this record.
1461 */
1462QDnsTlsAssociationRecord::CertificateUsage QDnsTlsAssociationRecord::usage() const
1463{
1464 return d->usage;
1465}
1466
1467/*!
1468 Returns the selector field for this record.
1469 */
1470QDnsTlsAssociationRecord::Selector QDnsTlsAssociationRecord::selector() const
1471{
1472 return d->selector;
1473}
1474
1475/*!
1476 Returns the match type field for this record.
1477 */
1478QDnsTlsAssociationRecord::MatchingType QDnsTlsAssociationRecord::matchType() const
1479{
1480 return d->matchType;
1481}
1482
1483/*!
1484 Returns the binary data field for this record. The interpretation of this
1485 binary data depends on the three numeric fields provided by
1486 certificateUsage(), selector(), and matchType().
1487
1488 Do note this is a binary field, even for the checksums, similar to what
1489 QCyrptographicHash::result() returns.
1490 */
1491QByteArray QDnsTlsAssociationRecord::value() const
1492{
1493 return d->value;
1494}
1495
1496static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
1497{
1498 QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.';
1499 if (label.isEmpty())
1500 return QDnsLookupRunnable::EncodedLabel(1, rootDomain);
1501
1502 QString encodedLabel = qt_ACE_do(label, ToAceOnly, ForbidLeadingDot);
1503#ifdef Q_OS_WIN
1504 return encodedLabel;
1505#else
1506 return std::move(encodedLabel).toLatin1();
1507#endif
1508}
1509
1513 requestType(d->type),
1514 port(d->port),
1516{
1517 if (port == 0)
1518 port = QDnsLookup::defaultPortForProtocol(protocol);
1519#if QT_CONFIG(ssl)
1520 sslConfiguration = d->sslConfiguration;
1521#endif
1522}
1523
1525{
1526 QDnsLookupReply reply;
1527
1528 // Validate input.
1529 if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) {
1530 reply.error = QDnsLookup::InvalidRequestError;
1531 reply.errorString = QDnsLookup::tr("Invalid domain name");
1532 } else {
1533 // Perform request.
1534 query(&reply);
1535
1536 // Sort results.
1537 qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
1538 qt_qdnsservicerecord_sort(reply.serviceRecords);
1539 }
1540
1541 emit finished(reply);
1542
1543 // maybe print the lookup error as warning
1544 switch (reply.error) {
1545 case QDnsLookup::NoError:
1546 case QDnsLookup::OperationCancelledError:
1547 case QDnsLookup::NotFoundError:
1548 case QDnsLookup::ServerFailureError:
1549 case QDnsLookup::ServerRefusedError:
1550 case QDnsLookup::TimeoutError:
1551 break; // no warning for these
1552
1553 case QDnsLookup::ResolverError:
1554 case QDnsLookup::InvalidRequestError:
1555 case QDnsLookup::InvalidReplyError:
1556 qCWarning(lcDnsLookup()).nospace()
1557 << "DNS lookup failed (" << reply.error << "): "
1558 << qUtf16Printable(reply.errorString)
1559 << "; request was " << this; // continues below
1560 }
1561}
1562
1563inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
1564{
1565 // continued: print the information about the request
1566 d << r->requestName.left(MaxDomainNameLength);
1567 if (r->requestName.size() > MaxDomainNameLength)
1568 d << "... (truncated)";
1569 d << " type " << r->requestType;
1570 if (!r->nameserver.isNull()) {
1571 d << " to nameserver " << qUtf16Printable(r->nameserver.toString())
1572 << " port " << (r->port ? r->port : QDnsLookup::defaultPortForProtocol(r->protocol));
1573 switch (r->protocol) {
1574 case QDnsLookup::Standard:
1575 break;
1576 case QDnsLookup::DnsOverTls:
1577 d << " (TLS)";
1578 }
1579 }
1580 return d;
1581}
1582
1583#if QT_CONFIG(ssl)
1584static constexpr std::chrono::milliseconds DnsOverTlsConnectTimeout(15'000);
1585static constexpr std::chrono::milliseconds DnsOverTlsTimeout(120'000);
1586static constexpr quint8 DnsAuthenticDataBit = 0x20;
1587
1588static int makeReplyErrorFromSocket(QDnsLookupReply *reply, const QAbstractSocket *socket)
1589{
1590 QDnsLookup::Error error = [&] {
1591 switch (socket->error()) {
1592 case QAbstractSocket::SocketTimeoutError:
1593 case QAbstractSocket::ProxyConnectionTimeoutError:
1594 return QDnsLookup::TimeoutError;
1595 default:
1596 return QDnsLookup::ResolverError;
1597 }
1598 }();
1599 reply->setError(error, socket->errorString());
1600 return false;
1601}
1602
1603bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query,
1604 ReplyBuffer &response)
1605{
1606 QSslSocket socket;
1607 socket.setSslConfiguration(sslConfiguration.value_or(QSslConfiguration::defaultConfiguration()));
1608
1609# if QT_CONFIG(networkproxy)
1610 socket.setProtocolTag("domain-s"_L1);
1611# endif
1612
1613 // Request the name server attempt to authenticate the reply.
1614 query[3] |= DnsAuthenticDataBit;
1615
1616 do {
1617 quint16 size = qToBigEndian<quint16>(query.size());
1618 QDeadlineTimer timeout(DnsOverTlsTimeout);
1619
1620 socket.connectToHostEncrypted(nameserver.toString(), port);
1621 socket.write(reinterpret_cast<const char *>(&size), sizeof(size));
1622 socket.write(reinterpret_cast<const char *>(query.data()), query.size());
1623 if (!socket.waitForEncrypted(DnsOverTlsConnectTimeout.count()))
1624 break;
1625
1626 reply->sslConfiguration = socket.sslConfiguration();
1627
1628 // accumulate reply
1629 auto waitForBytes = [&](void *buffer, int count) {
1630 int remaining = timeout.remainingTime();
1631 while (remaining >= 0 && socket.bytesAvailable() < count) {
1632 if (!socket.waitForReadyRead(remaining))
1633 return false;
1634 }
1635 return socket.read(static_cast<char *>(buffer), count) == count;
1636 };
1637 if (!waitForBytes(&size, sizeof(size)))
1638 break;
1639
1640 // note: strictly speaking, we're allocating memory based on untrusted data
1641 // but in practice, due to limited range of the data type (16 bits),
1642 // the maximum allocation is small.
1643 size = qFromBigEndian(size);
1644 response.resize(size);
1645 if (waitForBytes(response.data(), size)) {
1646 // check if the AD bit is set; we'll trust it over TLS requests
1647 if (size >= 4)
1648 reply->authenticData = response[3] & DnsAuthenticDataBit;
1649 return true;
1650 }
1651 } while (false);
1652
1653 // handle errors
1654 return makeReplyErrorFromSocket(reply, &socket);
1655}
1656#else
1657bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query,
1658 ReplyBuffer &response)
1659{
1660 Q_UNUSED(query)
1661 Q_UNUSED(response)
1662 reply->setError(QDnsLookup::ResolverError, QDnsLookup::tr("SSL/TLS support not present"));
1663 return false;
1664}
1665#endif
1666
1667QT_END_NAMESPACE
1668
1669#include "moc_qdnslookup.cpp"
1670#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.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:177
Combined button and popup list for selecting options.
#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,...)