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 \fn void QDnsDomainNameRecord::swap(QDnsDomainNameRecord &other)
887
888 Swaps this domain-name record instance with \a other. This
889 function is very fast and never fails.
890*/
891
892/*!
893 \class QDnsHostAddressRecord
894 \brief The QDnsHostAddressRecord class stores information about a host
895 address record.
896
897 \inmodule QtNetwork
898 \ingroup network
899 \ingroup shared
900
901 When performing an address lookup, zero or more records will be
902 returned. Each record is represented by a QDnsHostAddressRecord instance.
903
904 \sa QDnsLookup
905*/
906
907/*!
908 Constructs an empty host address record object.
909*/
910
911QDnsHostAddressRecord::QDnsHostAddressRecord()
912 : d(new QDnsHostAddressRecordPrivate)
913{
914}
915
916/*!
917 Constructs a copy of \a other.
918*/
919
920QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other)
921 : d(other.d)
922{
923}
924
925/*!
926 Destroys a host address record.
927*/
928
929QDnsHostAddressRecord::~QDnsHostAddressRecord()
930{
931}
932
933/*!
934 Returns the name for this record.
935*/
936
937QString QDnsHostAddressRecord::name() const
938{
939 return d->name;
940}
941
942/*!
943 Returns the duration in seconds for which this record is valid.
944*/
945
946quint32 QDnsHostAddressRecord::timeToLive() const
947{
948 return d->timeToLive;
949}
950
951/*!
952 Returns the value for this host address record.
953*/
954
955QHostAddress QDnsHostAddressRecord::value() const
956{
957 return d->value;
958}
959
960/*!
961 Assigns the data of the \a other object to this record object,
962 and returns a reference to it.
963*/
964
965QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other)
966{
967 d = other.d;
968 return *this;
969}
970/*!
971 \fn void QDnsHostAddressRecord::swap(QDnsHostAddressRecord &other)
972
973 Swaps this host address record instance with \a other. This
974 function is very fast and never fails.
975*/
976
977/*!
978 \class QDnsMailExchangeRecord
979 \brief The QDnsMailExchangeRecord class stores information about a DNS MX record.
980
981 \inmodule QtNetwork
982 \ingroup network
983 \ingroup shared
984
985 When performing a lookup on a service, zero or more records will be
986 returned. Each record is represented by a QDnsMailExchangeRecord instance.
987
988 The meaning of the fields is defined in
989 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
990
991 \sa QDnsLookup
992*/
993
994/*!
995 Constructs an empty mail exchange record object.
996*/
997
998QDnsMailExchangeRecord::QDnsMailExchangeRecord()
999 : d(new QDnsMailExchangeRecordPrivate)
1000{
1001}
1002
1003/*!
1004 Constructs a copy of \a other.
1005*/
1006
1007QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other)
1008 : d(other.d)
1009{
1010}
1011
1012/*!
1013 Destroys a mail exchange record.
1014*/
1015
1016QDnsMailExchangeRecord::~QDnsMailExchangeRecord()
1017{
1018}
1019
1020/*!
1021 Returns the domain name of the mail exchange for this record.
1022*/
1023
1024QString QDnsMailExchangeRecord::exchange() const
1025{
1026 return d->exchange;
1027}
1028
1029/*!
1030 Returns the name for this record.
1031*/
1032
1033QString QDnsMailExchangeRecord::name() const
1034{
1035 return d->name;
1036}
1037
1038/*!
1039 Returns the preference for this record.
1040*/
1041
1042quint16 QDnsMailExchangeRecord::preference() const
1043{
1044 return d->preference;
1045}
1046
1047/*!
1048 Returns the duration in seconds for which this record is valid.
1049*/
1050
1051quint32 QDnsMailExchangeRecord::timeToLive() const
1052{
1053 return d->timeToLive;
1054}
1055
1056/*!
1057 Assigns the data of the \a other object to this record object,
1058 and returns a reference to it.
1059*/
1060
1061QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other)
1062{
1063 d = other.d;
1064 return *this;
1065}
1066/*!
1067 \fn void QDnsMailExchangeRecord::swap(QDnsMailExchangeRecord &other)
1068
1069 Swaps this mail exchange record with \a other. This function is
1070 very fast and never fails.
1071*/
1072
1073/*!
1074 \class QDnsServiceRecord
1075 \brief The QDnsServiceRecord class stores information about a DNS SRV record.
1076
1077 \inmodule QtNetwork
1078 \ingroup network
1079 \ingroup shared
1080
1081 When performing a lookup on a service, zero or more records will be
1082 returned. Each record is represented by a QDnsServiceRecord instance.
1083
1084 The meaning of the fields is defined in
1085 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}.
1086
1087 \sa QDnsLookup
1088*/
1089
1090/*!
1091 Constructs an empty service record object.
1092*/
1093
1094QDnsServiceRecord::QDnsServiceRecord()
1095 : d(new QDnsServiceRecordPrivate)
1096{
1097}
1098
1099/*!
1100 Constructs a copy of \a other.
1101*/
1102
1103QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other)
1104 : d(other.d)
1105{
1106}
1107
1108/*!
1109 Destroys a service record.
1110*/
1111
1112QDnsServiceRecord::~QDnsServiceRecord()
1113{
1114}
1115
1116/*!
1117 Returns the name for this record.
1118*/
1119
1120QString QDnsServiceRecord::name() const
1121{
1122 return d->name;
1123}
1124
1125/*!
1126 Returns the port on the target host for this service record.
1127*/
1128
1129quint16 QDnsServiceRecord::port() const
1130{
1131 return d->port;
1132}
1133
1134/*!
1135 Returns the priority for this service record.
1136
1137 A client must attempt to contact the target host with the lowest-numbered
1138 priority.
1139*/
1140
1141quint16 QDnsServiceRecord::priority() const
1142{
1143 return d->priority;
1144}
1145
1146/*!
1147 Returns the domain name of the target host for this service record.
1148*/
1149
1150QString QDnsServiceRecord::target() const
1151{
1152 return d->target;
1153}
1154
1155/*!
1156 Returns the duration in seconds for which this record is valid.
1157*/
1158
1159quint32 QDnsServiceRecord::timeToLive() const
1160{
1161 return d->timeToLive;
1162}
1163
1164/*!
1165 Returns the weight for this service record.
1166
1167 The weight field specifies a relative weight for entries with the same
1168 priority. Entries with higher weights should be selected with a higher
1169 probability.
1170*/
1171
1172quint16 QDnsServiceRecord::weight() const
1173{
1174 return d->weight;
1175}
1176
1177/*!
1178 Assigns the data of the \a other object to this record object,
1179 and returns a reference to it.
1180*/
1181
1182QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other)
1183{
1184 d = other.d;
1185 return *this;
1186}
1187/*!
1188 \fn void QDnsServiceRecord::swap(QDnsServiceRecord &other)
1189
1190 Swaps this service record instance with \a other. This function is
1191 very fast and never fails.
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
1277 Swaps this text record instance with \a other. This function is
1278 very fast and never fails.
1279*/
1280
1281/*!
1282 \class QDnsTlsAssociationRecord
1283 \since 6.8
1284 \brief The QDnsTlsAssociationRecord class stores information about a DNS TLSA record.
1285
1286 \inmodule QtNetwork
1287 \ingroup network
1288 \ingroup shared
1289
1290 When performing a text lookup, zero or more records will be returned. Each
1291 record is represented by a QDnsTlsAssociationRecord instance.
1292
1293 The meaning of the fields is defined in \l{RFC 6698}.
1294
1295 \sa QDnsLookup
1296*/
1297
1298QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
1299
1300/*!
1301 \enum QDnsTlsAssociationRecord::CertificateUsage
1302
1303 This enumeration contains valid values for the certificate usage field of
1304 TLS Association queries. The following list is up-to-date with \l{RFC 6698}
1305 section 2.1.1 and RFC 7218 section 2.1. Please refer to those documents for
1306 authoritative instructions on interpreting this enumeration.
1307
1308 \value CertificateAuthorityConstrait
1309 Indicates the record includes an association to a specific Certificate
1310 Authority that must be found in the TLS server's certificate chain and
1311 must pass PKIX validation.
1312
1313 \value ServiceCertificateConstraint
1314 Indicates the record includes an association to a certificate that must
1315 match the end entity certificate provided by the TLS server and must
1316 pass PKIX validation.
1317
1318 \value TrustAnchorAssertion
1319 Indicates the record includes an association to a certificate that MUST
1320 be used as the ultimate trust anchor to validate the TLS server's
1321 certificate and must pass PKIX validation.
1322
1323 \value DomainIssuedCertificate
1324 Indicates the record includes an association to a certificate that must
1325 match the end entity certificate provided by the TLS server. PKIX
1326 validation is not tested.
1327
1328 \value PrivateUse
1329 No standard meaning applied.
1330
1331 \value PKIX_TA
1332 Alias; mnemonic for Public Key Infrastructure Trust Anchor
1333
1334 \value PKIX_EE
1335 Alias; mnemonic for Public Key Infrastructure End Entity
1336
1337 \value DANE_TA
1338 Alias; mnemonic for DNS-based Authentication of Named Entities Trust Anchor
1339
1340 \value DANE_EE
1341 Alias; mnemonic for DNS-based Authentication of Named Entities End Entity
1342
1343 \value PrivCert
1344 Alias
1345
1346 Other values are currently reserved, but may be unreserved by future
1347 standards. This enumeration can be used for those values even if no
1348 enumerator is provided.
1349
1350 \sa usage()
1351*/
1352
1353/*!
1354 \enum QDnsTlsAssociationRecord::Selector
1355
1356 This enumeration contains valid values for the selector field of TLS
1357 Association queries. The following list is up-to-date with \l{RFC 6698}
1358 section 2.1.2 and RFC 7218 section 2.2. Please refer to those documents for
1359 authoritative instructions on interpreting this enumeration.
1360
1361 \value FullCertificate
1362 Indicates this record refers to the full certificate in its binary
1363 structure form.
1364
1365 \value SubjectPublicKeyInfo
1366 Indicates the record refers to the certificate's subject and public
1367 key information, in DER-encoded binary structure form.
1368
1369 \value PrivateUse
1370 No standard meaning applied.
1371
1372 \value Cert
1373 Alias
1374
1375 \value SPKI
1376 Alias
1377
1378 \value PrivSel
1379 Alias
1380
1381 Other values are currently reserved, but may be unreserved by future
1382 standards. This enumeration can be used for those values even if no
1383 enumerator is provided.
1384
1385 \sa selector()
1386*/
1387
1388/*!
1389 \enum QDnsTlsAssociationRecord::MatchingType
1390
1391 This enumeration contains valid values for the matching type field of TLS
1392 Association queries. The following list is up-to-date with \l{RFC 6698}
1393 section 2.1.3 and RFC 7218 section 2.3. Please refer to those documents for
1394 authoritative instructions on interpreting this enumeration.
1395
1396 \value Exact
1397 Indicates this the certificate or SPKI data is stored verbatim in this
1398 record.
1399
1400 \value Sha256
1401 Indicates this a SHA-256 checksum of the the certificate or SPKI data
1402 present in this record.
1403
1404 \value Sha512
1405 Indicates this a SHA-512 checksum of the the certificate or SPKI data
1406 present in this record.
1407
1408 \value PrivateUse
1409 No standard meaning applied.
1410
1411 \value PrivMatch
1412 Alias
1413
1414 Other values are currently reserved, but may be unreserved by future
1415 standards. This enumeration can be used for those values even if no
1416 enumerator is provided.
1417
1418 \sa matchType()
1419*/
1420
1421/*!
1422 Constructs an empty TLS Association record.
1423 */
1424QDnsTlsAssociationRecord::QDnsTlsAssociationRecord()
1425 : d(new QDnsTlsAssociationRecordPrivate)
1426{
1427}
1428
1429/*!
1430 Constructs a copy of \a other.
1431 */
1432QDnsTlsAssociationRecord::QDnsTlsAssociationRecord(const QDnsTlsAssociationRecord &other) = default;
1433
1434/*!
1435 Moves the content of \a other into this object.
1436 */
1437QDnsTlsAssociationRecord &
1438QDnsTlsAssociationRecord::operator=(const QDnsTlsAssociationRecord &other) = default;
1439
1440/*!
1441 Destroys this TLS Association record object.
1442 */
1443QDnsTlsAssociationRecord::~QDnsTlsAssociationRecord() = default;
1444
1445/*!
1446 Returns the name of this record.
1447*/
1448QString QDnsTlsAssociationRecord::name() const
1449{
1450 return d->name;
1451}
1452
1453/*!
1454 Returns the duration in seconds for which this record is valid.
1455*/
1456quint32 QDnsTlsAssociationRecord::timeToLive() const
1457{
1458 return d->timeToLive;
1459}
1460
1461/*!
1462 Returns the certificate usage field for this record.
1463 */
1464QDnsTlsAssociationRecord::CertificateUsage QDnsTlsAssociationRecord::usage() const
1465{
1466 return d->usage;
1467}
1468
1469/*!
1470 Returns the selector field for this record.
1471 */
1472QDnsTlsAssociationRecord::Selector QDnsTlsAssociationRecord::selector() const
1473{
1474 return d->selector;
1475}
1476
1477/*!
1478 Returns the match type field for this record.
1479 */
1480QDnsTlsAssociationRecord::MatchingType QDnsTlsAssociationRecord::matchType() const
1481{
1482 return d->matchType;
1483}
1484
1485/*!
1486 Returns the binary data field for this record. The interpretation of this
1487 binary data depends on the three numeric fields provided by
1488 certificateUsage(), selector(), and matchType().
1489
1490 Do note this is a binary field, even for the checksums, similar to what
1491 QCyrptographicHash::result() returns.
1492 */
1493QByteArray QDnsTlsAssociationRecord::value() const
1494{
1495 return d->value;
1496}
1497
1498static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
1499{
1500 QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.';
1501 if (label.isEmpty())
1502 return QDnsLookupRunnable::EncodedLabel(1, rootDomain);
1503
1504 QString encodedLabel = qt_ACE_do(domain: label, op: ToAceOnly, dot: ForbidLeadingDot);
1505#ifdef Q_OS_WIN
1506 return encodedLabel;
1507#else
1508 return std::move(encodedLabel).toLatin1();
1509#endif
1510}
1511
1512inline QDnsLookupRunnable::QDnsLookupRunnable(const QDnsLookupPrivate *d)
1513 : requestName(encodeLabel(label: d->name)),
1514 nameserver(d->nameserver),
1515 requestType(d->type),
1516 port(d->port),
1517 protocol(d->protocol)
1518{
1519 if (port == 0)
1520 port = QDnsLookup::defaultPortForProtocol(protocol);
1521#if QT_CONFIG(ssl)
1522 sslConfiguration = d->sslConfiguration;
1523#endif
1524}
1525
1526void QDnsLookupRunnable::run()
1527{
1528 QDnsLookupReply reply;
1529
1530 // Validate input.
1531 if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) {
1532 reply.error = QDnsLookup::InvalidRequestError;
1533 reply.errorString = QDnsLookup::tr(s: "Invalid domain name");
1534 } else {
1535 // Perform request.
1536 query(reply: &reply);
1537
1538 // Sort results.
1539 qt_qdnsmailexchangerecord_sort(records&: reply.mailExchangeRecords);
1540 qt_qdnsservicerecord_sort(records&: reply.serviceRecords);
1541 }
1542
1543 emit finished(reply);
1544
1545 // maybe print the lookup error as warning
1546 switch (reply.error) {
1547 case QDnsLookup::NoError:
1548 case QDnsLookup::OperationCancelledError:
1549 case QDnsLookup::NotFoundError:
1550 case QDnsLookup::ServerFailureError:
1551 case QDnsLookup::ServerRefusedError:
1552 case QDnsLookup::TimeoutError:
1553 break; // no warning for these
1554
1555 case QDnsLookup::ResolverError:
1556 case QDnsLookup::InvalidRequestError:
1557 case QDnsLookup::InvalidReplyError:
1558 qCWarning(lcDnsLookup()).nospace()
1559 << "DNS lookup failed (" << reply.error << "): "
1560 << qUtf16Printable(reply.errorString)
1561 << "; request was " << this; // continues below
1562 }
1563}
1564
1565inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
1566{
1567 // continued: print the information about the request
1568 d << r->requestName.left(n: MaxDomainNameLength);
1569 if (r->requestName.size() > MaxDomainNameLength)
1570 d << "... (truncated)";
1571 d << " type " << r->requestType;
1572 if (!r->nameserver.isNull()) {
1573 d << " to nameserver " << qUtf16Printable(r->nameserver.toString())
1574 << " port " << (r->port ? r->port : QDnsLookup::defaultPortForProtocol(protocol: r->protocol));
1575 switch (r->protocol) {
1576 case QDnsLookup::Standard:
1577 break;
1578 case QDnsLookup::DnsOverTls:
1579 d << " (TLS)";
1580 }
1581 }
1582 return d;
1583}
1584
1585#if QT_CONFIG(ssl)
1586static constexpr std::chrono::milliseconds DnsOverTlsConnectTimeout(15'000);
1587static constexpr std::chrono::milliseconds DnsOverTlsTimeout(120'000);
1588static constexpr quint8 DnsAuthenticDataBit = 0x20;
1589
1590static int makeReplyErrorFromSocket(QDnsLookupReply *reply, const QAbstractSocket *socket)
1591{
1592 QDnsLookup::Error error = [&] {
1593 switch (socket->error()) {
1594 case QAbstractSocket::SocketTimeoutError:
1595 case QAbstractSocket::ProxyConnectionTimeoutError:
1596 return QDnsLookup::TimeoutError;
1597 default:
1598 return QDnsLookup::ResolverError;
1599 }
1600 }();
1601 reply->setError(err: error, msg: socket->errorString());
1602 return false;
1603}
1604
1605bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query,
1606 ReplyBuffer &response)
1607{
1608 QSslSocket socket;
1609 socket.setSslConfiguration(sslConfiguration.value_or(u: QSslConfiguration::defaultConfiguration()));
1610
1611# if QT_CONFIG(networkproxy)
1612 socket.setProtocolTag("domain-s"_L1);
1613# endif
1614
1615 // Request the name server attempt to authenticate the reply.
1616 query[3] |= DnsAuthenticDataBit;
1617
1618 do {
1619 quint16 size = qToBigEndian<quint16>(source: query.size());
1620 QDeadlineTimer timeout(DnsOverTlsTimeout);
1621
1622 socket.connectToHostEncrypted(hostName: nameserver.toString(), port);
1623 socket.write(data: reinterpret_cast<const char *>(&size), len: sizeof(size));
1624 socket.write(data: reinterpret_cast<const char *>(query.data()), len: query.size());
1625 if (!socket.waitForEncrypted(msecs: DnsOverTlsConnectTimeout.count()))
1626 break;
1627
1628 reply->sslConfiguration = socket.sslConfiguration();
1629
1630 // accumulate reply
1631 auto waitForBytes = [&](void *buffer, int count) {
1632 int remaining = timeout.remainingTime();
1633 while (remaining >= 0 && socket.bytesAvailable() < count) {
1634 if (!socket.waitForReadyRead(msecs: remaining))
1635 return false;
1636 }
1637 return socket.read(data: static_cast<char *>(buffer), maxlen: count) == count;
1638 };
1639 if (!waitForBytes(&size, sizeof(size)))
1640 break;
1641
1642 // note: strictly speaking, we're allocating memory based on untrusted data
1643 // but in practice, due to limited range of the data type (16 bits),
1644 // the maximum allocation is small.
1645 size = qFromBigEndian(source: size);
1646 response.resize(sz: size);
1647 if (waitForBytes(response.data(), size)) {
1648 // check if the AD bit is set; we'll trust it over TLS requests
1649 if (size >= 4)
1650 reply->authenticData = response[3] & DnsAuthenticDataBit;
1651 return true;
1652 }
1653 } while (false);
1654
1655 // handle errors
1656 return makeReplyErrorFromSocket(reply, socket: &socket);
1657}
1658#else
1659bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query,
1660 ReplyBuffer &response)
1661{
1662 Q_UNUSED(query)
1663 Q_UNUSED(response)
1664 reply->setError(QDnsLookup::ResolverError, QDnsLookup::tr("SSL/TLS support not present"));
1665 return false;
1666}
1667#endif
1668
1669QT_END_NAMESPACE
1670
1671#include "moc_qdnslookup.cpp"
1672#include "moc_qdnslookup_p.cpp"
1673

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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