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