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#if QT_CONFIG(ssl)
31# include "qsslconfiguration.h"
32#endif
33
34QT_REQUIRE_CONFIG(dnslookup);
35
36QT_BEGIN_NAMESPACE
37
38//#define QDNSLOOKUP_DEBUG
39
40constexpr qsizetype MaxDomainNameLength = 255;
41constexpr quint16 DnsPort = 53;
42constexpr quint16 DnsOverTlsPort = 853;
43
44class QDnsLookupRunnable;
45QDebug operator<<(QDebug &, QDnsLookupRunnable *);
46
47class QDnsLookupReply
48{
49public:
50 QDnsLookup::Error error = QDnsLookup::NoError;
51 bool authenticData = false;
52 QString errorString;
53
54 QList<QDnsDomainNameRecord> canonicalNameRecords;
55 QList<QDnsHostAddressRecord> hostAddressRecords;
56 QList<QDnsMailExchangeRecord> mailExchangeRecords;
57 QList<QDnsDomainNameRecord> nameServerRecords;
58 QList<QDnsDomainNameRecord> pointerRecords;
59 QList<QDnsServiceRecord> serviceRecords;
60 QList<QDnsTlsAssociationRecord> tlsAssociationRecords;
61 QList<QDnsTextRecord> textRecords;
62
63#if QT_CONFIG(ssl)
64 std::optional<QSslConfiguration> sslConfiguration;
65#endif
66
67 // helper methods
68 void setError(QDnsLookup::Error err, QString &&msg)
69 {
70 error = err;
71 errorString = std::move(msg);
72 }
73
74 void makeResolverSystemError(int code = -1)
75 {
76 Q_ASSERT(allAreEmpty());
77 setError(err: QDnsLookup::ResolverError, msg: qt_error_string(errorCode: code));
78 }
79
80 void makeTimeoutError()
81 {
82 Q_ASSERT(allAreEmpty());
83 setError(err: QDnsLookup::TimeoutError, msg: QDnsLookup::tr(s: "Request timed out"));
84 }
85
86 void makeDnsRcodeError(quint8 rcode)
87 {
88 Q_ASSERT(allAreEmpty());
89 switch (rcode) {
90 case 1: // FORMERR
91 error = QDnsLookup::InvalidRequestError;
92 errorString = QDnsLookup::tr(s: "Server could not process query");
93 return;
94 case 2: // SERVFAIL
95 case 4: // NOTIMP
96 error = QDnsLookup::ServerFailureError;
97 errorString = QDnsLookup::tr(s: "Server failure");
98 return;
99 case 3: // NXDOMAIN
100 error = QDnsLookup::NotFoundError;
101 errorString = QDnsLookup::tr(s: "Non existent domain");
102 return;
103 case 5: // REFUSED
104 error = QDnsLookup::ServerRefusedError;
105 errorString = QDnsLookup::tr(s: "Server refused to answer");
106 return;
107 default:
108 error = QDnsLookup::InvalidReplyError;
109 errorString = QDnsLookup::tr(s: "Invalid reply received (rcode %1)")
110 .arg(a: rcode);
111 return;
112 }
113 }
114
115 void makeInvalidReplyError(QString &&msg = QString())
116 {
117 if (msg.isEmpty())
118 msg = QDnsLookup::tr(s: "Invalid reply received");
119 else
120 msg = QDnsLookup::tr(s: "Invalid reply received (%1)").arg(a: std::move(msg));
121 *this = QDnsLookupReply(); // empty our lists
122 setError(err: QDnsLookup::InvalidReplyError, msg: std::move(msg));
123 }
124
125private:
126 bool allAreEmpty() const
127 {
128 return canonicalNameRecords.isEmpty()
129 && hostAddressRecords.isEmpty()
130 && mailExchangeRecords.isEmpty()
131 && nameServerRecords.isEmpty()
132 && pointerRecords.isEmpty()
133 && serviceRecords.isEmpty()
134 && tlsAssociationRecords.isEmpty()
135 && textRecords.isEmpty();
136 }
137};
138
139class QDnsLookupPrivate : public QObjectPrivate
140{
141public:
142 QDnsLookupPrivate()
143 : type(QDnsLookup::A)
144 , port(0)
145 , protocol(QDnsLookup::Standard)
146 { }
147
148 void nameChanged()
149 {
150 emit q_func()->nameChanged(name);
151 }
152 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QString, name,
153 &QDnsLookupPrivate::nameChanged);
154
155 void nameserverChanged()
156 {
157 emit q_func()->nameserverChanged(nameserver);
158 }
159 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QHostAddress, nameserver,
160 &QDnsLookupPrivate::nameserverChanged);
161
162 void typeChanged()
163 {
164 emit q_func()->typeChanged(type);
165 }
166
167 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QDnsLookup::Type,
168 type, &QDnsLookupPrivate::typeChanged);
169
170 void nameserverPortChanged()
171 {
172 emit q_func()->nameserverPortChanged(port);
173 }
174
175 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, quint16,
176 port, &QDnsLookupPrivate::nameserverPortChanged);
177
178 void nameserverProtocolChanged()
179 {
180 emit q_func()->nameserverProtocolChanged(protocol);
181 }
182
183 Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QDnsLookup::Protocol,
184 protocol, &QDnsLookupPrivate::nameserverProtocolChanged);
185
186 QDnsLookupReply reply;
187 QDnsLookupRunnable *runnable = nullptr;
188 bool isFinished = false;
189
190#if QT_CONFIG(ssl)
191 std::optional<QSslConfiguration> sslConfiguration;
192#endif
193
194 Q_DECLARE_PUBLIC(QDnsLookup)
195};
196
197class QDnsLookupRunnable : public QObject, public QRunnable
198{
199 Q_OBJECT
200
201public:
202#ifdef Q_OS_WIN
203 using EncodedLabel = QString;
204#else
205 using EncodedLabel = QByteArray;
206#endif
207 // minimum IPv6 MTU (1280) minus the IPv6 (40) and UDP headers (8)
208 static constexpr qsizetype ReplyBufferSize = 1280 - 40 - 8;
209 using ReplyBuffer = QVarLengthArray<unsigned char, ReplyBufferSize>;
210
211 QDnsLookupRunnable(const QDnsLookupPrivate *d);
212 void run() override;
213 bool sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query, ReplyBuffer &response);
214
215signals:
216 void finished(const QDnsLookupReply &reply);
217
218private:
219 template <typename T> static QString decodeLabel(T encodedLabel)
220 {
221 return qt_ACE_do(encodedLabel.toString(), NormalizeAce, ForbidLeadingDot);
222 }
223 void query(QDnsLookupReply *reply);
224
225 EncodedLabel requestName;
226 QHostAddress nameserver;
227 QDnsLookup::Type requestType;
228 quint16 port;
229 QDnsLookup::Protocol protocol;
230
231#if QT_CONFIG(ssl)
232 std::optional<QSslConfiguration> sslConfiguration;
233#endif
234 friend QDebug operator<<(QDebug &, QDnsLookupRunnable *);
235};
236
237class QDnsRecordPrivate : public QSharedData
238{
239public:
240 QDnsRecordPrivate()
241 : timeToLive(0)
242 { }
243
244 QString name;
245 quint32 timeToLive;
246};
247
248class QDnsDomainNameRecordPrivate : public QDnsRecordPrivate
249{
250public:
251 QDnsDomainNameRecordPrivate()
252 { }
253
254 QString value;
255};
256
257class QDnsHostAddressRecordPrivate : public QDnsRecordPrivate
258{
259public:
260 QDnsHostAddressRecordPrivate()
261 { }
262
263 QHostAddress value;
264};
265
266class QDnsMailExchangeRecordPrivate : public QDnsRecordPrivate
267{
268public:
269 QDnsMailExchangeRecordPrivate()
270 : preference(0)
271 { }
272
273 QString exchange;
274 quint16 preference;
275};
276
277class QDnsServiceRecordPrivate : public QDnsRecordPrivate
278{
279public:
280 QDnsServiceRecordPrivate()
281 : port(0),
282 priority(0),
283 weight(0)
284 { }
285
286 QString target;
287 quint16 port;
288 quint16 priority;
289 quint16 weight;
290};
291
292class QDnsTextRecordPrivate : public QDnsRecordPrivate
293{
294public:
295 QDnsTextRecordPrivate()
296 { }
297
298 QList<QByteArray> values;
299};
300
301class QDnsTlsAssociationRecordPrivate : public QDnsRecordPrivate
302{
303public:
304 QDnsTlsAssociationRecord::CertificateUsage usage;
305 QDnsTlsAssociationRecord::Selector selector;
306 QDnsTlsAssociationRecord::MatchingType matchType;
307 QByteArray value;
308};
309
310QT_END_NAMESPACE
311
312#endif // QDNSLOOKUP_P_H
313

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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