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 <qloggingcategory.h>
12#include <qrandom.h>
13#include <qurl.h>
14
15#include <algorithm>
16
17QT_BEGIN_NAMESPACE
18
19static Q_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup", QtCriticalMsg)
20
21namespace {
22struct QDnsLookupThreadPool : QThreadPool
23{
24 QDnsLookupThreadPool()
25 {
26 // Run up to 5 lookups in parallel.
27 setMaxThreadCount(5);
28 }
29};
30}
31
32Q_APPLICATION_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
33
34static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
35{
36 // Lower numbers are more preferred than higher ones.
37 return r1.preference() < r2.preference();
38}
39
40/*
41 Sorts a list of QDnsMailExchangeRecord objects according to RFC 5321.
42*/
43
44static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &records)
45{
46 // If we have no more than one result, we are done.
47 if (records.size() <= 1)
48 return;
49
50 // Order the records by preference.
51 std::sort(first: records.begin(), last: records.end(), comp: qt_qdnsmailexchangerecord_less_than);
52
53 int i = 0;
54 while (i < records.size()) {
55
56 // Determine the slice of records with the current preference.
57 QList<QDnsMailExchangeRecord> slice;
58 const quint16 slicePreference = records.at(i).preference();
59 for (int j = i; j < records.size(); ++j) {
60 if (records.at(i: j).preference() != slicePreference)
61 break;
62 slice << records.at(i: j);
63 }
64
65 // Randomize the slice of records.
66 while (!slice.isEmpty()) {
67 const unsigned int pos = QRandomGenerator::global()->bounded(highest: slice.size());
68 records[i++] = slice.takeAt(i: pos);
69 }
70 }
71}
72
73static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2)
74{
75 // Order by priority, or if the priorities are equal,
76 // put zero weight records first.
77 return r1.priority() < r2.priority()
78 || (r1.priority() == r2.priority()
79 && r1.weight() == 0 && r2.weight() > 0);
80}
81
82/*
83 Sorts a list of QDnsServiceRecord objects according to RFC 2782.
84*/
85
86static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
87{
88 // If we have no more than one result, we are done.
89 if (records.size() <= 1)
90 return;
91
92 // Order the records by priority, and for records with an equal
93 // priority, put records with a zero weight first.
94 std::sort(first: records.begin(), last: records.end(), comp: qt_qdnsservicerecord_less_than);
95
96 int i = 0;
97 while (i < records.size()) {
98
99 // Determine the slice of records with the current priority.
100 QList<QDnsServiceRecord> slice;
101 const quint16 slicePriority = records.at(i).priority();
102 unsigned int sliceWeight = 0;
103 for (int j = i; j < records.size(); ++j) {
104 if (records.at(i: j).priority() != slicePriority)
105 break;
106 sliceWeight += records.at(i: j).weight();
107 slice << records.at(i: j);
108 }
109#ifdef QDNSLOOKUP_DEBUG
110 qDebug("qt_qdnsservicerecord_sort() : priority %i (size: %i, total weight: %i)",
111 slicePriority, slice.size(), sliceWeight);
112#endif
113
114 // Order the slice of records.
115 while (!slice.isEmpty()) {
116 const unsigned int weightThreshold = QRandomGenerator::global()->bounded(highest: sliceWeight + 1);
117 unsigned int summedWeight = 0;
118 for (int j = 0; j < slice.size(); ++j) {
119 summedWeight += slice.at(i: j).weight();
120 if (summedWeight >= weightThreshold) {
121#ifdef QDNSLOOKUP_DEBUG
122 qDebug("qt_qdnsservicerecord_sort() : adding %s %i (weight: %i)",
123 qPrintable(slice.at(j).target()), slice.at(j).port(),
124 slice.at(j).weight());
125#endif
126 // Adjust the slice weight and take the current record.
127 sliceWeight -= slice.at(i: j).weight();
128 records[i++] = slice.takeAt(i: j);
129 break;
130 }
131 }
132 }
133 }
134}
135
136/*!
137 \class QDnsLookup
138 \brief The QDnsLookup class represents a DNS lookup.
139 \since 5.0
140
141 \inmodule QtNetwork
142 \ingroup network
143
144 QDnsLookup uses the mechanisms provided by the operating system to perform
145 DNS lookups. To perform a lookup you need to specify a \l name and \l type
146 then invoke the \l{QDnsLookup::lookup()}{lookup()} slot. The
147 \l{QDnsLookup::finished()}{finished()} signal will be emitted upon
148 completion.
149
150 For example, you can determine which servers an XMPP chat client should
151 connect to for a given domain with:
152
153 \snippet code/src_network_kernel_qdnslookup.cpp 0
154
155 Once the request finishes you can handle the results with:
156
157 \snippet code/src_network_kernel_qdnslookup.cpp 1
158
159 \note If you simply want to find the IP address(es) associated with a host
160 name, or the host name associated with an IP address you should use
161 QHostInfo instead.
162*/
163
164/*!
165 \enum QDnsLookup::Error
166
167 Indicates all possible error conditions found during the
168 processing of the DNS lookup.
169
170 \value NoError no error condition.
171
172 \value ResolverError there was an error initializing the system's
173 DNS resolver.
174
175 \value OperationCancelledError the lookup was aborted using the abort()
176 method.
177
178 \value InvalidRequestError the requested DNS lookup was invalid.
179
180 \value InvalidReplyError the reply returned by the server was invalid.
181
182 \value ServerFailureError the server encountered an internal failure
183 while processing the request (SERVFAIL).
184
185 \value ServerRefusedError the server refused to process the request for
186 security or policy reasons (REFUSED).
187
188 \value NotFoundError the requested domain name does not exist
189 (NXDOMAIN).
190
191 \value TimeoutError the server was not reached or did not reply
192 in time (since 6.6).
193*/
194
195/*!
196 \enum QDnsLookup::Type
197
198 Indicates the type of DNS lookup that was performed.
199
200 \value A IPv4 address records.
201
202 \value AAAA IPv6 address records.
203
204 \value ANY any records.
205
206 \value CNAME canonical name records.
207
208 \value MX mail exchange records.
209
210 \value NS name server records.
211
212 \value PTR pointer records.
213
214 \value SRV service records.
215
216 \value TXT text records.
217*/
218
219/*!
220 \fn void QDnsLookup::finished()
221
222 This signal is emitted when the reply has finished processing.
223*/
224
225/*!
226 \fn void QDnsLookup::nameChanged(const QString &name)
227
228 This signal is emitted when the lookup \l name changes.
229 \a name is the new lookup name.
230*/
231
232/*!
233 \fn void QDnsLookup::typeChanged(Type type)
234
235 This signal is emitted when the lookup \l type changes.
236 \a type is the new lookup type.
237*/
238
239/*!
240 Constructs a QDnsLookup object and sets \a parent as the parent object.
241
242 The \l type property will default to QDnsLookup::A.
243*/
244
245QDnsLookup::QDnsLookup(QObject *parent)
246 : QObject(*new QDnsLookupPrivate, parent)
247{
248}
249
250/*!
251 Constructs a QDnsLookup object for the given \a type and \a name and sets
252 \a parent as the parent object.
253*/
254
255QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
256 : QObject(*new QDnsLookupPrivate, parent)
257{
258 Q_D(QDnsLookup);
259 d->name = name;
260 d->type = type;
261}
262
263/*!
264 \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
265 \since 5.4
266
267 Constructs a QDnsLookup object to issue a query for \a name of record type
268 \a type, using the DNS server \a nameserver running on the default DNS port,
269 and sets \a parent as the parent object.
270*/
271
272QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
273 : QDnsLookup(type, name, nameserver, DnsPort, parent)
274{
275}
276
277/*!
278 \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
279 \since 6.6
280
281 Constructs a QDnsLookup object to issue a query for \a name of record type
282 \a type, using the DNS server \a nameserver running on port \a port, and
283 sets \a parent as the parent object.
284
285//! [nameserver-port]
286 \note Setting the port number to any value other than the default (53) can
287 cause the name resolution to fail, depending on the operating system
288 limitations and firewalls. Notably, the Windows API used by QDnsLookup is
289 unable to handle alternate port numbers.
290//! [nameserver-port]
291*/
292QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
293 : QObject(*new QDnsLookupPrivate, parent)
294{
295 Q_D(QDnsLookup);
296 d->name = name;
297 d->type = type;
298 d->port = port;
299 d->nameserver = nameserver;
300}
301
302/*!
303 Destroys the QDnsLookup object.
304
305 It is safe to delete a QDnsLookup object even if it is not finished, you
306 will simply never receive its results.
307*/
308
309QDnsLookup::~QDnsLookup()
310{
311}
312
313/*!
314 \property QDnsLookup::error
315 \brief the type of error that occurred if the DNS lookup failed, or NoError.
316*/
317
318QDnsLookup::Error QDnsLookup::error() const
319{
320 return d_func()->reply.error;
321}
322
323/*!
324 \property QDnsLookup::errorString
325 \brief a human-readable description of the error if the DNS lookup failed.
326*/
327
328QString QDnsLookup::errorString() const
329{
330 return d_func()->reply.errorString;
331}
332
333/*!
334 Returns whether the reply has finished or was aborted.
335*/
336
337bool QDnsLookup::isFinished() const
338{
339 return d_func()->isFinished;
340}
341
342/*!
343 \property QDnsLookup::name
344 \brief the name to lookup.
345
346 If the name to look up is empty, QDnsLookup will attempt to resolve the
347 root domain of DNS. That query is usually performed with QDnsLookup::type
348 set to \l{QDnsLookup::Type}{NS}.
349
350 \note The name will be encoded using IDNA, which means it's unsuitable for
351 querying SRV records compatible with the DNS-SD specification.
352*/
353
354QString QDnsLookup::name() const
355{
356 return d_func()->name;
357}
358
359void QDnsLookup::setName(const QString &name)
360{
361 Q_D(QDnsLookup);
362 d->name = name;
363}
364
365QBindable<QString> QDnsLookup::bindableName()
366{
367 Q_D(QDnsLookup);
368 return &d->name;
369}
370
371/*!
372 \property QDnsLookup::type
373 \brief the type of DNS lookup.
374*/
375
376QDnsLookup::Type QDnsLookup::type() const
377{
378 return d_func()->type;
379}
380
381void QDnsLookup::setType(Type type)
382{
383 Q_D(QDnsLookup);
384 d->type = type;
385}
386
387QBindable<QDnsLookup::Type> QDnsLookup::bindableType()
388{
389 Q_D(QDnsLookup);
390 return &d->type;
391}
392
393/*!
394 \property QDnsLookup::nameserver
395 \brief the nameserver to use for DNS lookup.
396*/
397
398QHostAddress QDnsLookup::nameserver() const
399{
400 return d_func()->nameserver;
401}
402
403void QDnsLookup::setNameserver(const QHostAddress &nameserver)
404{
405 Q_D(QDnsLookup);
406 d->nameserver = nameserver;
407}
408
409QBindable<QHostAddress> QDnsLookup::bindableNameserver()
410{
411 Q_D(QDnsLookup);
412 return &d->nameserver;
413}
414
415/*!
416 \property QDnsLookup::nameserverPort
417 \since 6.6
418 \brief the port number of nameserver to use for DNS lookup.
419 \include qdnslookup.cpp nameserver-port
420*/
421
422quint16 QDnsLookup::nameserverPort() const
423{
424 return d_func()->port;
425}
426
427void QDnsLookup::setNameserverPort(quint16 nameserverPort)
428{
429 Q_D(QDnsLookup);
430 d->port = nameserverPort;
431}
432
433QBindable<quint16> QDnsLookup::bindableNameserverPort()
434{
435 Q_D(QDnsLookup);
436 return &d->port;
437}
438
439/*!
440 \since 6.6
441 Sets the nameserver to \a nameserver and the port to \a port.
442
443 \include qdnslookup.cpp nameserver-port
444
445 \sa QDnsLookup::nameserver, QDnsLookup::nameserverPort
446*/
447void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
448{
449 Qt::beginPropertyUpdateGroup();
450 setNameserver(nameserver);
451 setNameserverPort(port);
452 Qt::endPropertyUpdateGroup();
453}
454
455/*!
456 Returns the list of canonical name records associated with this lookup.
457*/
458
459QList<QDnsDomainNameRecord> QDnsLookup::canonicalNameRecords() const
460{
461 return d_func()->reply.canonicalNameRecords;
462}
463
464/*!
465 Returns the list of host address records associated with this lookup.
466*/
467
468QList<QDnsHostAddressRecord> QDnsLookup::hostAddressRecords() const
469{
470 return d_func()->reply.hostAddressRecords;
471}
472
473/*!
474 Returns the list of mail exchange records associated with this lookup.
475
476 The records are sorted according to
477 \l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them
478 to connect to servers, you should try them in the order they are listed.
479*/
480
481QList<QDnsMailExchangeRecord> QDnsLookup::mailExchangeRecords() const
482{
483 return d_func()->reply.mailExchangeRecords;
484}
485
486/*!
487 Returns the list of name server records associated with this lookup.
488*/
489
490QList<QDnsDomainNameRecord> QDnsLookup::nameServerRecords() const
491{
492 return d_func()->reply.nameServerRecords;
493}
494
495/*!
496 Returns the list of pointer records associated with this lookup.
497*/
498
499QList<QDnsDomainNameRecord> QDnsLookup::pointerRecords() const
500{
501 return d_func()->reply.pointerRecords;
502}
503
504/*!
505 Returns the list of service records associated with this lookup.
506
507 The records are sorted according to
508 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them
509 to connect to servers, you should try them in the order they are listed.
510*/
511
512QList<QDnsServiceRecord> QDnsLookup::serviceRecords() const
513{
514 return d_func()->reply.serviceRecords;
515}
516
517/*!
518 Returns the list of text records associated with this lookup.
519*/
520
521QList<QDnsTextRecord> QDnsLookup::textRecords() const
522{
523 return d_func()->reply.textRecords;
524}
525
526/*!
527 Aborts the DNS lookup operation.
528
529 If the lookup is already finished, does nothing.
530*/
531
532void QDnsLookup::abort()
533{
534 Q_D(QDnsLookup);
535 if (d->runnable) {
536 d->runnable = nullptr;
537 d->reply = QDnsLookupReply();
538 d->reply.error = QDnsLookup::OperationCancelledError;
539 d->reply.errorString = tr(s: "Operation cancelled");
540 d->isFinished = true;
541 emit finished();
542 }
543}
544
545/*!
546 Performs the DNS lookup.
547
548 The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion.
549*/
550
551void QDnsLookup::lookup()
552{
553 Q_D(QDnsLookup);
554 d->isFinished = false;
555 d->reply = QDnsLookupReply();
556 if (!QCoreApplication::instance()) {
557 // NOT qCWarning because this isn't a result of the lookup
558 qWarning(msg: "QDnsLookup requires a QCoreApplication");
559 return;
560 }
561
562 auto l = [this](const QDnsLookupReply &reply) {
563 Q_D(QDnsLookup);
564 if (d->runnable == sender()) {
565#ifdef QDNSLOOKUP_DEBUG
566 qDebug("DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString));
567#endif
568 d->reply = reply;
569 d->runnable = nullptr;
570 d->isFinished = true;
571 emit finished();
572 }
573 };
574
575 d->runnable = new QDnsLookupRunnable(d);
576 connect(sender: d->runnable, signal: &QDnsLookupRunnable::finished, context: this, slot&: l,
577 type: Qt::BlockingQueuedConnection);
578 theDnsLookupThreadPool->start(runnable: d->runnable);
579}
580
581/*!
582 \class QDnsDomainNameRecord
583 \brief The QDnsDomainNameRecord class stores information about a domain
584 name record.
585
586 \inmodule QtNetwork
587 \ingroup network
588 \ingroup shared
589
590 When performing a name server lookup, zero or more records will be returned.
591 Each record is represented by a QDnsDomainNameRecord instance.
592
593 \sa QDnsLookup
594*/
595
596/*!
597 Constructs an empty domain name record object.
598*/
599
600QDnsDomainNameRecord::QDnsDomainNameRecord()
601 : d(new QDnsDomainNameRecordPrivate)
602{
603}
604
605/*!
606 Constructs a copy of \a other.
607*/
608
609QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other)
610 : d(other.d)
611{
612}
613
614/*!
615 Destroys a domain name record.
616*/
617
618QDnsDomainNameRecord::~QDnsDomainNameRecord()
619{
620}
621
622/*!
623 Returns the name for this record.
624*/
625
626QString QDnsDomainNameRecord::name() const
627{
628 return d->name;
629}
630
631/*!
632 Returns the duration in seconds for which this record is valid.
633*/
634
635quint32 QDnsDomainNameRecord::timeToLive() const
636{
637 return d->timeToLive;
638}
639
640/*!
641 Returns the value for this domain name record.
642*/
643
644QString QDnsDomainNameRecord::value() const
645{
646 return d->value;
647}
648
649/*!
650 Assigns the data of the \a other object to this record object,
651 and returns a reference to it.
652*/
653
654QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other)
655{
656 d = other.d;
657 return *this;
658}
659/*!
660 \fn void QDnsDomainNameRecord::swap(QDnsDomainNameRecord &other)
661
662 Swaps this domain-name record instance with \a other. This
663 function is very fast and never fails.
664*/
665
666/*!
667 \class QDnsHostAddressRecord
668 \brief The QDnsHostAddressRecord class stores information about a host
669 address record.
670
671 \inmodule QtNetwork
672 \ingroup network
673 \ingroup shared
674
675 When performing an address lookup, zero or more records will be
676 returned. Each record is represented by a QDnsHostAddressRecord instance.
677
678 \sa QDnsLookup
679*/
680
681/*!
682 Constructs an empty host address record object.
683*/
684
685QDnsHostAddressRecord::QDnsHostAddressRecord()
686 : d(new QDnsHostAddressRecordPrivate)
687{
688}
689
690/*!
691 Constructs a copy of \a other.
692*/
693
694QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other)
695 : d(other.d)
696{
697}
698
699/*!
700 Destroys a host address record.
701*/
702
703QDnsHostAddressRecord::~QDnsHostAddressRecord()
704{
705}
706
707/*!
708 Returns the name for this record.
709*/
710
711QString QDnsHostAddressRecord::name() const
712{
713 return d->name;
714}
715
716/*!
717 Returns the duration in seconds for which this record is valid.
718*/
719
720quint32 QDnsHostAddressRecord::timeToLive() const
721{
722 return d->timeToLive;
723}
724
725/*!
726 Returns the value for this host address record.
727*/
728
729QHostAddress QDnsHostAddressRecord::value() const
730{
731 return d->value;
732}
733
734/*!
735 Assigns the data of the \a other object to this record object,
736 and returns a reference to it.
737*/
738
739QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other)
740{
741 d = other.d;
742 return *this;
743}
744/*!
745 \fn void QDnsHostAddressRecord::swap(QDnsHostAddressRecord &other)
746
747 Swaps this host address record instance with \a other. This
748 function is very fast and never fails.
749*/
750
751/*!
752 \class QDnsMailExchangeRecord
753 \brief The QDnsMailExchangeRecord class stores information about a DNS MX record.
754
755 \inmodule QtNetwork
756 \ingroup network
757 \ingroup shared
758
759 When performing a lookup on a service, zero or more records will be
760 returned. Each record is represented by a QDnsMailExchangeRecord instance.
761
762 The meaning of the fields is defined in
763 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
764
765 \sa QDnsLookup
766*/
767
768/*!
769 Constructs an empty mail exchange record object.
770*/
771
772QDnsMailExchangeRecord::QDnsMailExchangeRecord()
773 : d(new QDnsMailExchangeRecordPrivate)
774{
775}
776
777/*!
778 Constructs a copy of \a other.
779*/
780
781QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other)
782 : d(other.d)
783{
784}
785
786/*!
787 Destroys a mail exchange record.
788*/
789
790QDnsMailExchangeRecord::~QDnsMailExchangeRecord()
791{
792}
793
794/*!
795 Returns the domain name of the mail exchange for this record.
796*/
797
798QString QDnsMailExchangeRecord::exchange() const
799{
800 return d->exchange;
801}
802
803/*!
804 Returns the name for this record.
805*/
806
807QString QDnsMailExchangeRecord::name() const
808{
809 return d->name;
810}
811
812/*!
813 Returns the preference for this record.
814*/
815
816quint16 QDnsMailExchangeRecord::preference() const
817{
818 return d->preference;
819}
820
821/*!
822 Returns the duration in seconds for which this record is valid.
823*/
824
825quint32 QDnsMailExchangeRecord::timeToLive() const
826{
827 return d->timeToLive;
828}
829
830/*!
831 Assigns the data of the \a other object to this record object,
832 and returns a reference to it.
833*/
834
835QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other)
836{
837 d = other.d;
838 return *this;
839}
840/*!
841 \fn void QDnsMailExchangeRecord::swap(QDnsMailExchangeRecord &other)
842
843 Swaps this mail exchange record with \a other. This function is
844 very fast and never fails.
845*/
846
847/*!
848 \class QDnsServiceRecord
849 \brief The QDnsServiceRecord class stores information about a DNS SRV record.
850
851 \inmodule QtNetwork
852 \ingroup network
853 \ingroup shared
854
855 When performing a lookup on a service, zero or more records will be
856 returned. Each record is represented by a QDnsServiceRecord instance.
857
858 The meaning of the fields is defined in
859 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}.
860
861 \sa QDnsLookup
862*/
863
864/*!
865 Constructs an empty service record object.
866*/
867
868QDnsServiceRecord::QDnsServiceRecord()
869 : d(new QDnsServiceRecordPrivate)
870{
871}
872
873/*!
874 Constructs a copy of \a other.
875*/
876
877QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other)
878 : d(other.d)
879{
880}
881
882/*!
883 Destroys a service record.
884*/
885
886QDnsServiceRecord::~QDnsServiceRecord()
887{
888}
889
890/*!
891 Returns the name for this record.
892*/
893
894QString QDnsServiceRecord::name() const
895{
896 return d->name;
897}
898
899/*!
900 Returns the port on the target host for this service record.
901*/
902
903quint16 QDnsServiceRecord::port() const
904{
905 return d->port;
906}
907
908/*!
909 Returns the priority for this service record.
910
911 A client must attempt to contact the target host with the lowest-numbered
912 priority.
913*/
914
915quint16 QDnsServiceRecord::priority() const
916{
917 return d->priority;
918}
919
920/*!
921 Returns the domain name of the target host for this service record.
922*/
923
924QString QDnsServiceRecord::target() const
925{
926 return d->target;
927}
928
929/*!
930 Returns the duration in seconds for which this record is valid.
931*/
932
933quint32 QDnsServiceRecord::timeToLive() const
934{
935 return d->timeToLive;
936}
937
938/*!
939 Returns the weight for this service record.
940
941 The weight field specifies a relative weight for entries with the same
942 priority. Entries with higher weights should be selected with a higher
943 probability.
944*/
945
946quint16 QDnsServiceRecord::weight() const
947{
948 return d->weight;
949}
950
951/*!
952 Assigns the data of the \a other object to this record object,
953 and returns a reference to it.
954*/
955
956QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other)
957{
958 d = other.d;
959 return *this;
960}
961/*!
962 \fn void QDnsServiceRecord::swap(QDnsServiceRecord &other)
963
964 Swaps this service record instance with \a other. This function is
965 very fast and never fails.
966*/
967
968/*!
969 \class QDnsTextRecord
970 \brief The QDnsTextRecord class stores information about a DNS TXT record.
971
972 \inmodule QtNetwork
973 \ingroup network
974 \ingroup shared
975
976 When performing a text lookup, zero or more records will be
977 returned. Each record is represented by a QDnsTextRecord instance.
978
979 The meaning of the fields is defined in
980 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
981
982 \sa QDnsLookup
983*/
984
985/*!
986 Constructs an empty text record object.
987*/
988
989QDnsTextRecord::QDnsTextRecord()
990 : d(new QDnsTextRecordPrivate)
991{
992}
993
994/*!
995 Constructs a copy of \a other.
996*/
997
998QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other)
999 : d(other.d)
1000{
1001}
1002
1003/*!
1004 Destroys a text record.
1005*/
1006
1007QDnsTextRecord::~QDnsTextRecord()
1008{
1009}
1010
1011/*!
1012 Returns the name for this text record.
1013*/
1014
1015QString QDnsTextRecord::name() const
1016{
1017 return d->name;
1018}
1019
1020/*!
1021 Returns the duration in seconds for which this record is valid.
1022*/
1023
1024quint32 QDnsTextRecord::timeToLive() const
1025{
1026 return d->timeToLive;
1027}
1028
1029/*!
1030 Returns the values for this text record.
1031*/
1032
1033QList<QByteArray> QDnsTextRecord::values() const
1034{
1035 return d->values;
1036}
1037
1038/*!
1039 Assigns the data of the \a other object to this record object,
1040 and returns a reference to it.
1041*/
1042
1043QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
1044{
1045 d = other.d;
1046 return *this;
1047}
1048/*!
1049 \fn void QDnsTextRecord::swap(QDnsTextRecord &other)
1050
1051 Swaps this text record instance with \a other. This function is
1052 very fast and never fails.
1053*/
1054
1055static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
1056{
1057 QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.';
1058 if (label.isEmpty())
1059 return QDnsLookupRunnable::EncodedLabel(1, rootDomain);
1060
1061 QString encodedLabel = qt_ACE_do(domain: label, op: ToAceOnly, dot: ForbidLeadingDot);
1062#ifdef Q_OS_WIN
1063 return encodedLabel;
1064#else
1065 return std::move(encodedLabel).toLatin1();
1066#endif
1067}
1068
1069inline QDnsLookupRunnable::QDnsLookupRunnable(const QDnsLookupPrivate *d)
1070 : requestName(encodeLabel(label: d->name)),
1071 nameserver(d->nameserver),
1072 requestType(d->type),
1073 port(d->port)
1074{
1075}
1076
1077void QDnsLookupRunnable::run()
1078{
1079 QDnsLookupReply reply;
1080
1081 // Validate input.
1082 if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) {
1083 reply.error = QDnsLookup::InvalidRequestError;
1084 reply.errorString = QDnsLookup::tr(s: "Invalid domain name");
1085 } else {
1086 // Perform request.
1087 query(reply: &reply);
1088
1089 // Sort results.
1090 qt_qdnsmailexchangerecord_sort(records&: reply.mailExchangeRecords);
1091 qt_qdnsservicerecord_sort(records&: reply.serviceRecords);
1092 }
1093
1094 emit finished(reply);
1095
1096 // maybe print the lookup error as warning
1097 switch (reply.error) {
1098 case QDnsLookup::NoError:
1099 case QDnsLookup::OperationCancelledError:
1100 case QDnsLookup::NotFoundError:
1101 case QDnsLookup::ServerFailureError:
1102 case QDnsLookup::ServerRefusedError:
1103 case QDnsLookup::TimeoutError:
1104 break; // no warning for these
1105
1106 case QDnsLookup::ResolverError:
1107 case QDnsLookup::InvalidRequestError:
1108 case QDnsLookup::InvalidReplyError:
1109 qCWarning(lcDnsLookup()).nospace()
1110 << "DNS lookup failed (" << reply.error << "): "
1111 << qUtf16Printable(reply.errorString)
1112 << "; request was " << this; // continues below
1113 }
1114}
1115
1116inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
1117{
1118 // continued: print the information about the request
1119 d << r->requestName.left(len: MaxDomainNameLength);
1120 if (r->requestName.size() > MaxDomainNameLength)
1121 d << "... (truncated)";
1122 d << " type " << r->requestType;
1123 if (!r->nameserver.isNull())
1124 d << " to nameserver " << qUtf16Printable(r->nameserver.toString())
1125 << " port " << (r->port ? r->port : DnsPort);
1126 return d;
1127}
1128
1129QT_END_NAMESPACE
1130
1131#include "moc_qdnslookup.cpp"
1132#include "moc_qdnslookup_p.cpp"
1133

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