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 | |
30 | QT_REQUIRE_CONFIG(dnslookup); |
31 | |
32 | QT_BEGIN_NAMESPACE |
33 | |
34 | //#define QDNSLOOKUP_DEBUG |
35 | |
36 | constexpr qsizetype MaxDomainNameLength = 255; |
37 | constexpr quint16 DnsPort = 53; |
38 | |
39 | class QDnsLookupRunnable; |
40 | QDebug operator<<(QDebug &, QDnsLookupRunnable *); |
41 | |
42 | class QDnsLookupReply |
43 | { |
44 | public: |
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 | |
114 | private: |
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 | |
127 | class QDnsLookupPrivate : public QObjectPrivate |
128 | { |
129 | public: |
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 | |
173 | class QDnsLookupRunnable : public QObject, public QRunnable |
174 | { |
175 | Q_OBJECT |
176 | |
177 | public: |
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 | |
187 | signals: |
188 | void finished(const QDnsLookupReply &reply); |
189 | |
190 | private: |
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 | |
204 | class QDnsRecordPrivate : public QSharedData |
205 | { |
206 | public: |
207 | QDnsRecordPrivate() |
208 | : timeToLive(0) |
209 | { } |
210 | |
211 | QString name; |
212 | quint32 timeToLive; |
213 | }; |
214 | |
215 | class QDnsDomainNameRecordPrivate : public QDnsRecordPrivate |
216 | { |
217 | public: |
218 | QDnsDomainNameRecordPrivate() |
219 | { } |
220 | |
221 | QString value; |
222 | }; |
223 | |
224 | class QDnsHostAddressRecordPrivate : public QDnsRecordPrivate |
225 | { |
226 | public: |
227 | QDnsHostAddressRecordPrivate() |
228 | { } |
229 | |
230 | QHostAddress value; |
231 | }; |
232 | |
233 | class QDnsMailExchangeRecordPrivate : public QDnsRecordPrivate |
234 | { |
235 | public: |
236 | QDnsMailExchangeRecordPrivate() |
237 | : preference(0) |
238 | { } |
239 | |
240 | QString exchange; |
241 | quint16 preference; |
242 | }; |
243 | |
244 | class QDnsServiceRecordPrivate : public QDnsRecordPrivate |
245 | { |
246 | public: |
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 | |
259 | class QDnsTextRecordPrivate : public QDnsRecordPrivate |
260 | { |
261 | public: |
262 | QDnsTextRecordPrivate() |
263 | { } |
264 | |
265 | QList<QByteArray> values; |
266 | }; |
267 | |
268 | QT_END_NAMESPACE |
269 | |
270 | #endif // QDNSLOOKUP_P_H |
271 | |