Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qdnslookup.cpp
Go to the documentation of this file.
1// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
2// Copyright (C) 2023 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qdnslookup.h"
6#include "qdnslookup_p.h"
7
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
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.
28 }
29};
30}
31
32Q_APPLICATION_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
33
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
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(records.begin(), records.end(), 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.
58 const quint16 slicePreference = records.at(i).preference();
59 for (int j = i; j < records.size(); ++j) {
60 if (records.at(j).preference() != slicePreference)
61 break;
62 slice << records.at(j);
63 }
64
65 // Randomize the slice of records.
66 while (!slice.isEmpty()) {
67 const unsigned int pos = QRandomGenerator::global()->bounded(slice.size());
68 records[i++] = slice.takeAt(pos);
69 }
70 }
71}
72
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
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(records.begin(), records.end(), 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.
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(j).priority() != slicePriority)
105 break;
106 sliceWeight += records.at(j).weight();
107 slice << records.at(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(sliceWeight + 1);
117 unsigned int summedWeight = 0;
118 for (int j = 0; j < slice.size(); ++j) {
119 summedWeight += slice.at(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(j).weight();
128 records[i++] = slice.takeAt(j);
129 break;
130 }
131 }
132 }
133 }
134}
135
247{
248}
249
257{
258 Q_D(QDnsLookup);
259 d->name = name;
260 d->type = type;
261}
262
273 : QDnsLookup(type, name, nameserver, DnsPort, parent)
274{
275}
276
286
291
294{
295 Q_D(QDnsLookup);
296 d->name = name;
297 d->type = type;
298 d->port = port;
299 d->nameserver = nameserver;
300}
301
310{
311}
312
319{
320 return d_func()->reply.error;
321}
322
329{
330 return d_func()->reply.errorString;
331}
332
338{
339 return d_func()->isFinished;
340}
341
355{
356 return d_func()->name;
357}
358
360{
361 Q_D(QDnsLookup);
362 d->name = name;
363}
364
366{
367 Q_D(QDnsLookup);
368 return &d->name;
369}
370
377{
378 return d_func()->type;
379}
380
382{
383 Q_D(QDnsLookup);
384 d->type = type;
385}
386
388{
389 Q_D(QDnsLookup);
390 return &d->type;
391}
392
399{
400 return d_func()->nameserver;
401}
402
404{
405 Q_D(QDnsLookup);
406 d->nameserver = nameserver;
407}
408
410{
411 Q_D(QDnsLookup);
412 return &d->nameserver;
413}
414
423{
424 return d_func()->port;
425}
426
428{
429 Q_D(QDnsLookup);
430 d->port = nameserverPort;
431}
432
434{
435 Q_D(QDnsLookup);
436 return &d->port;
437}
438
448{
453}
454
460{
461 return d_func()->reply.canonicalNameRecords;
462}
463
469{
470 return d_func()->reply.hostAddressRecords;
471}
472
482{
483 return d_func()->reply.mailExchangeRecords;
484}
485
491{
492 return d_func()->reply.nameServerRecords;
493}
494
500{
501 return d_func()->reply.pointerRecords;
502}
503
513{
514 return d_func()->reply.serviceRecords;
515}
516
522{
523 return d_func()->reply.textRecords;
524}
525
533{
534 Q_D(QDnsLookup);
535 if (d->runnable) {
536 d->runnable = nullptr;
537 d->reply = QDnsLookupReply();
539 d->reply.errorString = tr("Operation cancelled");
540 d->isFinished = true;
541 emit finished();
542 }
543}
544
552{
553 Q_D(QDnsLookup);
554 d->isFinished = false;
555 d->reply = QDnsLookupReply();
557 // NOT qCWarning because this isn't a result of the lookup
558 qWarning("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(d->runnable, &QDnsLookupRunnable::finished, this, l,
578 theDnsLookupThreadPool->start(d->runnable);
579}
580
602{
603}
604
610 : d(other.d)
611{
612}
613
619{
620}
621
627{
628 return d->name;
629}
630
636{
637 return d->timeToLive;
638}
639
645{
646 return d->value;
647}
648
655{
656 d = other.d;
657 return *this;
658}
687{
688}
689
695 : d(other.d)
696{
697}
698
704{
705}
706
712{
713 return d->name;
714}
715
721{
722 return d->timeToLive;
723}
724
730{
731 return d->value;
732}
733
740{
741 d = other.d;
742 return *this;
743}
774{
775}
776
782 : d(other.d)
783{
784}
785
791{
792}
793
799{
800 return d->exchange;
801}
802
808{
809 return d->name;
810}
811
817{
818 return d->preference;
819}
820
826{
827 return d->timeToLive;
828}
829
836{
837 d = other.d;
838 return *this;
839}
870{
871}
872
878 : d(other.d)
879{
880}
881
887{
888}
889
895{
896 return d->name;
897}
898
904{
905 return d->port;
906}
907
916{
917 return d->priority;
918}
919
925{
926 return d->target;
927}
928
934{
935 return d->timeToLive;
936}
937
947{
948 return d->weight;
949}
950
957{
958 d = other.d;
959 return *this;
960}
991{
992}
993
999 : d(other.d)
1000{
1001}
1002
1008{
1009}
1010
1016{
1017 return d->name;
1018}
1019
1025{
1026 return d->timeToLive;
1027}
1028
1034{
1035 return d->values;
1036}
1037
1044{
1045 d = other.d;
1046 return *this;
1047}
1056{
1058 if (label.isEmpty())
1059 return QDnsLookupRunnable::EncodedLabel(1, rootDomain);
1060
1062#ifdef Q_OS_WIN
1063 return encodedLabel;
1064#else
1065 return std::move(encodedLabel).toLatin1();
1066#endif
1067}
1068
1070 : requestName(encodeLabel(d->name)),
1071 nameserver(d->nameserver),
1072 requestType(d->type),
1073 port(d->port)
1074{
1075}
1076
1078{
1080
1081 // Validate input.
1082 if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) {
1084 reply.errorString = QDnsLookup::tr("Invalid domain name");
1085 } else {
1086 // Perform request.
1087 query(&reply);
1088
1089 // Sort results.
1090 qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
1091 qt_qdnsservicerecord_sort(reply.serviceRecords);
1092 }
1093
1095
1096 // maybe print the lookup error as warning
1097 switch (reply.error) {
1104 break; // no warning for these
1105
1109 qCWarning(lcDnsLookup()).nospace()
1110 << "DNS lookup failed (" << reply.error << "): "
1112 << "; request was " << this; // continues below
1113 }
1114}
1115
1117{
1118 // continued: print the information about the request
1119 d << r->requestName.left(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
1130
1131#include "moc_qdnslookup.cpp"
1132#include "moc_qdnslookup_p.cpp"
\inmodule QtCore
Definition qproperty.h:809
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
char value_type
Definition qbytearray.h:450
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
\inmodule QtCore
The QDnsDomainNameRecord class stores information about a domain name record.
Definition qdnslookup.h:27
QString name() const
Returns the name for this record.
QString value() const
Returns the value for this domain name record.
QDnsDomainNameRecord & operator=(QDnsDomainNameRecord &&other) noexcept
Definition qdnslookup.h:31
QDnsDomainNameRecord()
Constructs an empty domain name record object.
quint32 timeToLive() const
Returns the duration in seconds for which this record is valid.
~QDnsDomainNameRecord()
Destroys a domain name record.
The QDnsHostAddressRecord class stores information about a host address record.
Definition qdnslookup.h:49
QHostAddress value() const
Returns the value for this host address record.
~QDnsHostAddressRecord()
Destroys a host address record.
QDnsHostAddressRecord()
Constructs an empty host address record object.
quint32 timeToLive() const
Returns the duration in seconds for which this record is valid.
QDnsHostAddressRecord & operator=(QDnsHostAddressRecord &&other) noexcept
Definition qdnslookup.h:53
QString name() const
Returns the name for this record.
void finished(const QDnsLookupReply &reply)
QDnsLookupRunnable(const QDnsLookupPrivate *d)
void run() override
Implement this pure virtual function in your subclass.
QByteArray EncodedLabel
The QDnsLookup class represents a DNS lookup.
Definition qdnslookup.h:141
quint16 nameserverPort
the port number of nameserver to use for DNS lookup.
Definition qdnslookup.h:150
Type
Indicates the type of DNS lookup that was performed.
Definition qdnslookup.h:168
QBindable< QString > bindableName()
QString errorString
a human-readable description of the error if the DNS lookup failed.
Definition qdnslookup.h:144
QHostAddress nameserver
the nameserver to use for DNS lookup.
Definition qdnslookup.h:148
QList< QDnsServiceRecord > serviceRecords() const
Returns the list of service records associated with this lookup.
bool isFinished() const
Returns whether the reply has finished or was aborted.
QList< QDnsMailExchangeRecord > mailExchangeRecords() const
Returns the list of mail exchange records associated with this lookup.
void setName(const QString &name)
QList< QDnsDomainNameRecord > nameServerRecords() const
Returns the list of name server records associated with this lookup.
Error
Indicates all possible error conditions found during the processing of the DNS lookup.
Definition qdnslookup.h:154
@ InvalidReplyError
Definition qdnslookup.h:159
@ OperationCancelledError
Definition qdnslookup.h:157
@ ServerRefusedError
Definition qdnslookup.h:161
@ ServerFailureError
Definition qdnslookup.h:160
@ InvalidRequestError
Definition qdnslookup.h:158
void abort()
Aborts the DNS lookup operation.
QBindable< quint16 > bindableNameserverPort()
void finished()
This signal is emitted when the reply has finished processing.
Error error
the type of error that occurred if the DNS lookup failed, or NoError.
Definition qdnslookup.h:143
void setType(QDnsLookup::Type)
QDnsLookup(QObject *parent=nullptr)
Constructs a QDnsLookup object and sets parent as the parent object.
QList< QDnsDomainNameRecord > canonicalNameRecords() const
Returns the list of canonical name records associated with this lookup.
void lookup()
Performs the DNS lookup.
void setNameserver(const QHostAddress &nameserver)
~QDnsLookup()
Destroys the QDnsLookup object.
QBindable< QHostAddress > bindableNameserver()
QList< QDnsDomainNameRecord > pointerRecords() const
Returns the list of pointer records associated with this lookup.
QBindable< Type > bindableType()
void setNameserverPort(quint16 port)
QList< QDnsHostAddressRecord > hostAddressRecords() const
Returns the list of host address records associated with this lookup.
Type type
the type of DNS lookup.
Definition qdnslookup.h:146
QString name
the name to lookup.
Definition qdnslookup.h:145
QList< QDnsTextRecord > textRecords() const
Returns the list of text records associated with this lookup.
The QDnsMailExchangeRecord class stores information about a DNS MX record.
Definition qdnslookup.h:71
~QDnsMailExchangeRecord()
Destroys a mail exchange record.
quint16 preference() const
Returns the preference for this record.
quint32 timeToLive() const
Returns the duration in seconds for which this record is valid.
QString name() const
Returns the name for this record.
QDnsMailExchangeRecord()
Constructs an empty mail exchange record object.
QDnsMailExchangeRecord & operator=(QDnsMailExchangeRecord &&other) noexcept
Definition qdnslookup.h:75
QString exchange() const
Returns the domain name of the mail exchange for this record.
The QDnsServiceRecord class stores information about a DNS SRV record.
Definition qdnslookup.h:94
QString target() const
Returns the domain name of the target host for this service record.
QDnsServiceRecord & operator=(QDnsServiceRecord &&other) noexcept
Definition qdnslookup.h:98
quint16 weight() const
Returns the weight for this service record.
quint32 timeToLive() const
Returns the duration in seconds for which this record is valid.
~QDnsServiceRecord()
Destroys a service record.
quint16 priority() const
Returns the priority for this service record.
QString name() const
Returns the name for this record.
quint16 port() const
Returns the port on the target host for this service record.
QDnsServiceRecord()
Constructs an empty service record object.
QList< QByteArray > values
The QDnsTextRecord class stores information about a DNS TXT record.
Definition qdnslookup.h:119
quint32 timeToLive() const
Returns the duration in seconds for which this record is valid.
QDnsTextRecord & operator=(QDnsTextRecord &&other) noexcept
Definition qdnslookup.h:123
QDnsTextRecord()
Constructs an empty text record object.
~QDnsTextRecord()
Destroys a text record.
QList< QByteArray > values() const
Returns the values for this text record.
QString name() const
Returns the name for this text record.
The QHostAddress class provides an IP address.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
iterator end()
Definition qlist.h:609
T takeAt(qsizetype i)
Definition qlist.h:592
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
iterator begin()
Definition qlist.h:608
NetworkError error() const
Returns the error that was found during the processing of this request.
\inmodule QtCore
Definition qobject.h:90
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2521
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
Definition qrandom.h:275
double bounded(double highest)
Generates one random double in the range between 0 (inclusive) and highest (exclusive).
Definition qrandom.h:72
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QByteArray toLatin1() const &
Definition qstring.h:559
\inmodule QtCore
Definition qthreadpool.h:20
void setMaxThreadCount(int maxThreadCount)
Combined button and popup list for selecting options.
Q_CORE_EXPORT void beginPropertyUpdateGroup()
@ BlockingQueuedConnection
Q_CORE_EXPORT void endPropertyUpdateGroup()
#define Q_APPLICATION_STATIC(TYPE, NAME,...)
static void qt_qdnsmailexchangerecord_sort(QList< QDnsMailExchangeRecord > &records)
static void qt_qdnsservicerecord_sort(QList< QDnsServiceRecord > &records)
QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2)
static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
constexpr quint16 DnsPort
QT_BEGIN_NAMESPACE constexpr qsizetype MaxDomainNameLength
EGLOutputPortEXT port
#define qDebug
[1]
Definition qlogging.h:160
@ QtCriticalMsg
Definition qlogging.h:32
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
GLboolean r
[2]
GLenum type
GLuint GLsizei const GLchar * label
[43]
GLuint name
GLfloat n
GLenum query
#define qPrintable(string)
Definition qstring.h:1391
#define qUtf16Printable(string)
Definition qstring.h:1403
#define tr(X)
#define emit
unsigned int quint32
Definition qtypes.h:45
unsigned short quint16
Definition qtypes.h:43
ptrdiff_t qsizetype
Definition qtypes.h:70
@ ForbidLeadingDot
Definition qurl_p.h:30
QString Q_CORE_EXPORT qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot, QUrl::AceProcessingOptions options={})
Definition qurlidna.cpp:889
@ ToAceOnly
Definition qurl_p.h:31
QRect r1(100, 200, 11, 16)
[0]
QRect r2(QPoint(100, 200), QSize(11, 16))
QSharedPointer< T > other(t)
[5]
QNetworkReply * reply
Definition moc.h:24
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent