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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/network/kernel/qdnslookup.cpp