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#ifndef QDNSLOOKUP_P_H
6#define QDNSLOOKUP_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists for the convenience
13// of the QDnsLookup class. This header file may change from
14// version to version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtNetwork/private/qtnetworkglobal_p.h>
20#include "QtCore/qmutex.h"
21#include "QtCore/qrunnable.h"
22#if QT_CONFIG(thread)
23#include "QtCore/qthreadpool.h"
24#endif
25#include "QtNetwork/qdnslookup.h"
26#include "QtNetwork/qhostaddress.h"
27#include "private/qobject_p.h"
28#include "private/qurl_p.h"
29
30QT_REQUIRE_CONFIG(dnslookup);
31
32QT_BEGIN_NAMESPACE
33
34//#define QDNSLOOKUP_DEBUG
35
36constexpr qsizetype MaxDomainNameLength = 255;
37constexpr quint16 DnsPort = 53;
38
39class QDnsLookupRunnable;
40QDebug operator<<(QDebug &, QDnsLookupRunnable *);
41
42class QDnsLookupReply
43{
44public:
45 QDnsLookup::Error error = QDnsLookup::NoError;
46 QString errorString;
47
48 QList<QDnsDomainNameRecord> canonicalNameRecords;
49 QList<QDnsHostAddressRecord> hostAddressRecords;
50 QList<QDnsMailExchangeRecord> mailExchangeRecords;
51 QList<QDnsDomainNameRecord> nameServerRecords;
52 QList<QDnsDomainNameRecord> pointerRecords;
53 QList<QDnsServiceRecord> serviceRecords;
54 QList<QDnsTextRecord> textRecords;
55
56 // helper methods
57 void setError(QDnsLookup::Error err, QString &&msg)
58 {
59 error = err;
60 errorString = std::move(msg);
61 }
62
63 void makeResolverSystemError(int code = -1)
64 {
65 Q_ASSERT(allAreEmpty());
66 setError(err: QDnsLookup::ResolverError, msg: qt_error_string(errorCode: code));
67 }
68
69 void makeTimeoutError()
70 {
71 Q_ASSERT(allAreEmpty());
72 setError(err: QDnsLookup::TimeoutError, msg: QDnsLookup::tr(s: "Request timed out"));
73 }
74
75 void makeDnsRcodeError(quint8 rcode)
76 {
77 Q_ASSERT(allAreEmpty());
78 switch (rcode) {
79 case 1: // FORMERR
80 error = QDnsLookup::InvalidRequestError;
81 errorString = QDnsLookup::tr(s: "Server could not process query");
82 return;
83 case 2: // SERVFAIL
84 case 4: // NOTIMP
85 error = QDnsLookup::ServerFailureError;
86 errorString = QDnsLookup::tr(s: "Server failure");
87 return;
88 case 3: // NXDOMAIN
89 error = QDnsLookup::NotFoundError;
90 errorString = QDnsLookup::tr(s: "Non existent domain");
91 return;
92 case 5: // REFUSED
93 error = QDnsLookup::ServerRefusedError;
94 errorString = QDnsLookup::tr(s: "Server refused to answer");
95 return;
96 default:
97 error = QDnsLookup::InvalidReplyError;
98 errorString = QDnsLookup::tr(s: "Invalid reply received (rcode %1)")
99 .arg(a: rcode);
100 return;
101 }
102 }
103
104 void makeInvalidReplyError(QString &&msg = QString())
105 {
106 if (msg.isEmpty())
107 msg = QDnsLookup::tr(s: "Invalid reply received");
108 else
109 msg = QDnsLookup::tr(s: "Invalid reply received (%1)").arg(a: std::move(msg));
110 *this = QDnsLookupReply(); // empty our lists
111 setError(err: QDnsLookup::InvalidReplyError, msg: std::move(msg));
112 }
113
114private:
115 bool allAreEmpty() const
116 {
117 return canonicalNameRecords.isEmpty()
118 && hostAddressRecords.isEmpty()
119 && mailExchangeRecords.isEmpty()
120 && nameServerRecords.isEmpty()
121 && pointerRecords.isEmpty()
122 && serviceRecords.isEmpty()
123 && textRecords.isEmpty();
124 }
125};
126
127class QDnsLookupPrivate : public QObjectPrivate
128{
129public:
130 QDnsLookupPrivate()
131 : type(QDnsLookup::A)
132 , port(DnsPort)
133 { }
134
135 void nameChanged()
136 {
137 emit q_func()->nameChanged(name);
138 }
139 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QString, name,
140 &QDnsLookupPrivate::nameChanged);
141
142 void nameserverChanged()
143 {
144 emit q_func()->nameserverChanged(nameserver);
145 }
146 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QHostAddress, nameserver,
147 &QDnsLookupPrivate::nameserverChanged);
148
149 void typeChanged()
150 {
151 emit q_func()->typeChanged(type);
152 }
153
154 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QDnsLookup::Type,
155 type, &QDnsLookupPrivate::typeChanged);
156
157 void nameserverPortChanged()
158 {
159 emit q_func()->nameserverPortChanged(port);
160 }
161
162 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, quint16,
163 port, &QDnsLookupPrivate::nameserverPortChanged);
164
165
166 QDnsLookupReply reply;
167 QDnsLookupRunnable *runnable = nullptr;
168 bool isFinished = false;
169
170 Q_DECLARE_PUBLIC(QDnsLookup)
171};
172
173class QDnsLookupRunnable : public QObject, public QRunnable
174{
175 Q_OBJECT
176
177public:
178#ifdef Q_OS_WIN
179 using EncodedLabel = QString;
180#else
181 using EncodedLabel = QByteArray;
182#endif
183
184 QDnsLookupRunnable(const QDnsLookupPrivate *d);
185 void run() override;
186
187signals:
188 void finished(const QDnsLookupReply &reply);
189
190private:
191 template <typename T> static QString decodeLabel(T encodedLabel)
192 {
193 return qt_ACE_do(encodedLabel.toString(), NormalizeAce, ForbidLeadingDot);
194 }
195 void query(QDnsLookupReply *reply);
196
197 EncodedLabel requestName;
198 QHostAddress nameserver;
199 QDnsLookup::Type requestType;
200 quint16 port;
201 friend QDebug operator<<(QDebug &, QDnsLookupRunnable *);
202};
203
204class QDnsRecordPrivate : public QSharedData
205{
206public:
207 QDnsRecordPrivate()
208 : timeToLive(0)
209 { }
210
211 QString name;
212 quint32 timeToLive;
213};
214
215class QDnsDomainNameRecordPrivate : public QDnsRecordPrivate
216{
217public:
218 QDnsDomainNameRecordPrivate()
219 { }
220
221 QString value;
222};
223
224class QDnsHostAddressRecordPrivate : public QDnsRecordPrivate
225{
226public:
227 QDnsHostAddressRecordPrivate()
228 { }
229
230 QHostAddress value;
231};
232
233class QDnsMailExchangeRecordPrivate : public QDnsRecordPrivate
234{
235public:
236 QDnsMailExchangeRecordPrivate()
237 : preference(0)
238 { }
239
240 QString exchange;
241 quint16 preference;
242};
243
244class QDnsServiceRecordPrivate : public QDnsRecordPrivate
245{
246public:
247 QDnsServiceRecordPrivate()
248 : port(0),
249 priority(0),
250 weight(0)
251 { }
252
253 QString target;
254 quint16 port;
255 quint16 priority;
256 quint16 weight;
257};
258
259class QDnsTextRecordPrivate : public QDnsRecordPrivate
260{
261public:
262 QDnsTextRecordPrivate()
263 { }
264
265 QList<QByteArray> values;
266};
267
268QT_END_NAMESPACE
269
270#endif // QDNSLOOKUP_P_H
271

source code of qtbase/src/network/kernel/qdnslookup_p.h