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 <qendian.h> |
12 | #include <qloggingcategory.h> |
13 | #include <qrandom.h> |
14 | #include <qspan.h> |
15 | #include <qurl.h> |
16 | |
17 | #if QT_CONFIG(ssl) |
18 | # include <qsslsocket.h> |
19 | #endif |
20 | |
21 | #include <algorithm> |
22 | |
23 | QT_BEGIN_NAMESPACE |
24 | |
25 | using namespace Qt::StringLiterals; |
26 | |
27 | static Q_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup", QtCriticalMsg) |
28 | |
29 | namespace { |
30 | struct QDnsLookupThreadPool : QThreadPool |
31 | { |
32 | QDnsLookupThreadPool() |
33 | { |
34 | // Run up to 5 lookups in parallel. |
35 | setMaxThreadCount(5); |
36 | } |
37 | }; |
38 | } |
39 | |
40 | Q_APPLICATION_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool); |
41 | |
42 | static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2) |
43 | { |
44 | // Lower numbers are more preferred than higher ones. |
45 | return r1.preference() < r2.preference(); |
46 | } |
47 | |
48 | /* |
49 | Sorts a list of QDnsMailExchangeRecord objects according to RFC 5321. |
50 | */ |
51 | |
52 | static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &records) |
53 | { |
54 | // If we have no more than one result, we are done. |
55 | if (records.size() <= 1) |
56 | return; |
57 | |
58 | // Order the records by preference. |
59 | std::sort(first: records.begin(), last: records.end(), comp: qt_qdnsmailexchangerecord_less_than); |
60 | |
61 | int i = 0; |
62 | while (i < records.size()) { |
63 | |
64 | // Determine the slice of records with the current preference. |
65 | QList<QDnsMailExchangeRecord> slice; |
66 | const quint16 slicePreference = records.at(i).preference(); |
67 | for (int j = i; j < records.size(); ++j) { |
68 | if (records.at(i: j).preference() != slicePreference) |
69 | break; |
70 | slice << records.at(i: j); |
71 | } |
72 | |
73 | // Randomize the slice of records. |
74 | while (!slice.isEmpty()) { |
75 | const unsigned int pos = QRandomGenerator::global()->bounded(highest: slice.size()); |
76 | records[i++] = slice.takeAt(i: pos); |
77 | } |
78 | } |
79 | } |
80 | |
81 | static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2) |
82 | { |
83 | // Order by priority, or if the priorities are equal, |
84 | // put zero weight records first. |
85 | return r1.priority() < r2.priority() |
86 | || (r1.priority() == r2.priority() |
87 | && r1.weight() == 0 && r2.weight() > 0); |
88 | } |
89 | |
90 | /* |
91 | Sorts a list of QDnsServiceRecord objects according to RFC 2782. |
92 | */ |
93 | |
94 | static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records) |
95 | { |
96 | // If we have no more than one result, we are done. |
97 | if (records.size() <= 1) |
98 | return; |
99 | |
100 | // Order the records by priority, and for records with an equal |
101 | // priority, put records with a zero weight first. |
102 | std::sort(first: records.begin(), last: records.end(), comp: qt_qdnsservicerecord_less_than); |
103 | |
104 | int i = 0; |
105 | while (i < records.size()) { |
106 | |
107 | // Determine the slice of records with the current priority. |
108 | QList<QDnsServiceRecord> slice; |
109 | const quint16 slicePriority = records.at(i).priority(); |
110 | unsigned int sliceWeight = 0; |
111 | for (int j = i; j < records.size(); ++j) { |
112 | if (records.at(i: j).priority() != slicePriority) |
113 | break; |
114 | sliceWeight += records.at(i: j).weight(); |
115 | slice << records.at(i: j); |
116 | } |
117 | #ifdef QDNSLOOKUP_DEBUG |
118 | qDebug("qt_qdnsservicerecord_sort() : priority %i (size: %i, total weight: %i)", |
119 | slicePriority, slice.size(), sliceWeight); |
120 | #endif |
121 | |
122 | // Order the slice of records. |
123 | while (!slice.isEmpty()) { |
124 | const unsigned int weightThreshold = QRandomGenerator::global()->bounded(highest: sliceWeight + 1); |
125 | unsigned int summedWeight = 0; |
126 | for (int j = 0; j < slice.size(); ++j) { |
127 | summedWeight += slice.at(i: j).weight(); |
128 | if (summedWeight >= weightThreshold) { |
129 | #ifdef QDNSLOOKUP_DEBUG |
130 | qDebug("qt_qdnsservicerecord_sort() : adding %s %i (weight: %i)", |
131 | qPrintable(slice.at(j).target()), slice.at(j).port(), |
132 | slice.at(j).weight()); |
133 | #endif |
134 | // Adjust the slice weight and take the current record. |
135 | sliceWeight -= slice.at(i: j).weight(); |
136 | records[i++] = slice.takeAt(i: j); |
137 | break; |
138 | } |
139 | } |
140 | } |
141 | } |
142 | } |
143 | |
144 | /*! |
145 | \class QDnsLookup |
146 | \brief The QDnsLookup class represents a DNS lookup. |
147 | \since 5.0 |
148 | |
149 | \inmodule QtNetwork |
150 | \ingroup network |
151 | |
152 | QDnsLookup uses the mechanisms provided by the operating system to perform |
153 | DNS lookups. To perform a lookup you need to specify a \l name and \l type |
154 | then invoke the \l{QDnsLookup::lookup()}{lookup()} slot. The |
155 | \l{QDnsLookup::finished()}{finished()} signal will be emitted upon |
156 | completion. |
157 | |
158 | For example, you can determine which servers an XMPP chat client should |
159 | connect to for a given domain with: |
160 | |
161 | \snippet code/src_network_kernel_qdnslookup.cpp 0 |
162 | |
163 | Once the request finishes you can handle the results with: |
164 | |
165 | \snippet code/src_network_kernel_qdnslookup.cpp 1 |
166 | |
167 | \note If you simply want to find the IP address(es) associated with a host |
168 | name, or the host name associated with an IP address you should use |
169 | QHostInfo instead. |
170 | |
171 | \section1 DNS-over-TLS and Authentic Data |
172 | |
173 | QDnsLookup supports DNS-over-TLS (DoT, as specified by \l{RFC 7858}) on |
174 | some platforms. That currently includes all Unix platforms where regular |
175 | queries are supported, if \l QSslSocket support is present in Qt. To query |
176 | if support is present at runtime, use isProtocolSupported(). |
177 | |
178 | When using DNS-over-TLS, QDnsLookup only implements the "Opportunistic |
179 | Privacy Profile" method of authentication, as described in \l{RFC 7858} |
180 | section 4.1. In this mode, QDnsLookup (through \l QSslSocket) only |
181 | validates that the server presents a certificate that is valid for the |
182 | server being connected to. Clients may use setSslConfiguration() to impose |
183 | additional restrictions and sslConfiguration() to obtain information after |
184 | the query is complete. |
185 | |
186 | QDnsLookup will request DNS servers queried over TLS to perform |
187 | authentication on the data they return. If they confirm the data is valid, |
188 | the \l authenticData property will be set to true. QDnsLookup does not |
189 | verify the integrity of the data by itself, so applications should only |
190 | trust this property on servers they have confirmed through other means to |
191 | be trustworthy. |
192 | |
193 | \section2 Authentic Data without TLS |
194 | |
195 | QDnsLookup request Authentic Data for any server set with setNameserver(), |
196 | even if TLS encryption is not required. This is useful when querying a |
197 | caching nameserver on the same host as the application or on a trusted |
198 | network. Though similar to the TLS case, the application is responsible for |
199 | determining if the server it chose to use is trustworthy, and if the |
200 | unencrypted connection cannot be tampered with. |
201 | |
202 | QDnsLookup obeys the system configuration to request Authentic Data on the |
203 | default nameserver (that is, if setNameserver() is not called). This is |
204 | currently only supported on Linux systems using glibc 2.31 or later. On any |
205 | other systems, QDnsLookup will ignore the AD bit in the query header. |
206 | */ |
207 | |
208 | /*! |
209 | \enum QDnsLookup::Error |
210 | |
211 | Indicates all possible error conditions found during the |
212 | processing of the DNS lookup. |
213 | |
214 | \value NoError no error condition. |
215 | |
216 | \value ResolverError there was an error initializing the system's |
217 | DNS resolver. |
218 | |
219 | \value OperationCancelledError the lookup was aborted using the abort() |
220 | method. |
221 | |
222 | \value InvalidRequestError the requested DNS lookup was invalid. |
223 | |
224 | \value InvalidReplyError the reply returned by the server was invalid. |
225 | |
226 | \value ServerFailureError the server encountered an internal failure |
227 | while processing the request (SERVFAIL). |
228 | |
229 | \value ServerRefusedError the server refused to process the request for |
230 | security or policy reasons (REFUSED). |
231 | |
232 | \value NotFoundError the requested domain name does not exist |
233 | (NXDOMAIN). |
234 | |
235 | \value TimeoutError the server was not reached or did not reply |
236 | in time (since 6.6). |
237 | */ |
238 | |
239 | /*! |
240 | \enum QDnsLookup::Type |
241 | |
242 | Indicates the type of DNS lookup that was performed. |
243 | |
244 | \value A IPv4 address records. |
245 | |
246 | \value AAAA IPv6 address records. |
247 | |
248 | \value ANY any records. |
249 | |
250 | \value CNAME canonical name records. |
251 | |
252 | \value MX mail exchange records. |
253 | |
254 | \value NS name server records. |
255 | |
256 | \value PTR pointer records. |
257 | |
258 | \value SRV service records. |
259 | |
260 | \value[since 6.8] TLSA TLS association records. |
261 | |
262 | \value TXT text records. |
263 | */ |
264 | |
265 | /*! |
266 | \enum QDnsLookup::Protocol |
267 | |
268 | Indicates the type of DNS server that is being queried. |
269 | |
270 | \value Standard |
271 | Regular, unencrypted DNS, using UDP and falling back to TCP as necessary |
272 | (default port: 53) |
273 | |
274 | \value DnsOverTls |
275 | Encrypted DNS over TLS (DoT, as specified by \l{RFC 7858}), over TCP |
276 | (default port: 853) |
277 | |
278 | \sa isProtocolSupported(), nameserverProtocol, setNameserver() |
279 | */ |
280 | |
281 | /*! |
282 | \since 6.8 |
283 | |
284 | Returns true if DNS queries using \a protocol are supported with QDnsLookup. |
285 | |
286 | \sa nameserverProtocol |
287 | */ |
288 | bool QDnsLookup::isProtocolSupported(Protocol protocol) |
289 | { |
290 | #if QT_CONFIG(libresolv) || defined(Q_OS_WIN) |
291 | switch (protocol) { |
292 | case QDnsLookup::Standard: |
293 | return true; |
294 | case QDnsLookup::DnsOverTls: |
295 | # if QT_CONFIG(ssl) |
296 | if (QSslSocket::supportsSsl()) |
297 | return true; |
298 | # endif |
299 | return false; |
300 | } |
301 | #else |
302 | Q_UNUSED(protocol) |
303 | #endif |
304 | return false; |
305 | } |
306 | |
307 | /*! |
308 | \since 6.8 |
309 | |
310 | Returns the standard (default) port number for the protocol \a protocol. |
311 | |
312 | \sa isProtocolSupported() |
313 | */ |
314 | quint16 QDnsLookup::defaultPortForProtocol(Protocol protocol) noexcept |
315 | { |
316 | switch (protocol) { |
317 | case QDnsLookup::Standard: |
318 | return DnsPort; |
319 | case QDnsLookup::DnsOverTls: |
320 | return DnsOverTlsPort; |
321 | } |
322 | return 0; // will probably fail somewhere |
323 | } |
324 | |
325 | /*! |
326 | \fn void QDnsLookup::finished() |
327 | |
328 | This signal is emitted when the reply has finished processing. |
329 | */ |
330 | |
331 | /*! |
332 | \fn void QDnsLookup::nameChanged(const QString &name) |
333 | |
334 | This signal is emitted when the lookup \l name changes. |
335 | \a name is the new lookup name. |
336 | */ |
337 | |
338 | /*! |
339 | \fn void QDnsLookup::typeChanged(QDnsLookup::Type type) |
340 | |
341 | This signal is emitted when the lookup \l type changes. |
342 | \a type is the new lookup type. |
343 | */ |
344 | |
345 | /*! |
346 | Constructs a QDnsLookup object and sets \a parent as the parent object. |
347 | |
348 | The \l type property will default to QDnsLookup::A. |
349 | */ |
350 | |
351 | QDnsLookup::QDnsLookup(QObject *parent) |
352 | : QObject(*new QDnsLookupPrivate, parent) |
353 | { |
354 | } |
355 | |
356 | /*! |
357 | Constructs a QDnsLookup object for the given \a type and \a name and sets |
358 | \a parent as the parent object. |
359 | */ |
360 | |
361 | QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent) |
362 | : QObject(*new QDnsLookupPrivate, parent) |
363 | { |
364 | Q_D(QDnsLookup); |
365 | d->name = name; |
366 | d->type = type; |
367 | } |
368 | |
369 | /*! |
370 | \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent) |
371 | \since 5.4 |
372 | |
373 | Constructs a QDnsLookup object to issue a query for \a name of record type |
374 | \a type, using the DNS server \a nameserver running on the default DNS port, |
375 | and sets \a parent as the parent object. |
376 | */ |
377 | |
378 | QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent) |
379 | : QDnsLookup(type, name, nameserver, 0, parent) |
380 | { |
381 | } |
382 | |
383 | /*! |
384 | \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent) |
385 | \since 6.6 |
386 | |
387 | Constructs a QDnsLookup object to issue a query for \a name of record type |
388 | \a type, using the DNS server \a nameserver running on port \a port, and |
389 | sets \a parent as the parent object. |
390 | |
391 | //! [nameserver-port] |
392 | \note Setting the port number to any value other than the default (53) can |
393 | cause the name resolution to fail, depending on the operating system |
394 | limitations and firewalls, if the nameserverProtocol() to be used |
395 | QDnsLookup::Standard. Notably, the Windows API used by QDnsLookup is unable |
396 | to handle alternate port numbers. |
397 | //! [nameserver-port] |
398 | */ |
399 | QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent) |
400 | : QObject(*new QDnsLookupPrivate, parent) |
401 | { |
402 | Q_D(QDnsLookup); |
403 | d->name = name; |
404 | d->type = type; |
405 | d->port = port; |
406 | d->nameserver = nameserver; |
407 | } |
408 | |
409 | /*! |
410 | \since 6.8 |
411 | |
412 | Constructs a QDnsLookup object to issue a query for \a name of record type |
413 | \a type, using the DNS server \a nameserver running on port \a port, and |
414 | sets \a parent as the parent object. |
415 | |
416 | The query will be sent using \a protocol, if supported. Use |
417 | isProtocolSupported() to check if it is supported. |
418 | |
419 | \include qdnslookup.cpp nameserver-port |
420 | */ |
421 | QDnsLookup::QDnsLookup(Type type, const QString &name, Protocol protocol, |
422 | const QHostAddress &nameserver, quint16 port, QObject *parent) |
423 | : QObject(*new QDnsLookupPrivate, parent) |
424 | { |
425 | Q_D(QDnsLookup); |
426 | d->name = name; |
427 | d->type = type; |
428 | d->nameserver = nameserver; |
429 | d->port = port; |
430 | d->protocol = protocol; |
431 | } |
432 | |
433 | /*! |
434 | Destroys the QDnsLookup object. |
435 | |
436 | It is safe to delete a QDnsLookup object even if it is not finished, you |
437 | will simply never receive its results. |
438 | */ |
439 | |
440 | QDnsLookup::~QDnsLookup() |
441 | { |
442 | } |
443 | |
444 | /*! |
445 | \since 6.8 |
446 | \property QDnsLookup::authenticData |
447 | \brief whether the reply was authenticated by the resolver. |
448 | |
449 | QDnsLookup does not perform the authentication itself. Instead, it trusts |
450 | the name server that was queried to perform the authentication and report |
451 | it. The application is responsible for determining if any servers it |
452 | configured with setNameserver() are trustworthy; if no server was set, |
453 | QDnsLookup obeys system configuration on whether responses should be |
454 | trusted. |
455 | |
456 | This property may be set even if error() indicates a resolver error |
457 | occurred. |
458 | |
459 | \sa setNameserver(), nameserverProtocol() |
460 | */ |
461 | bool QDnsLookup::isAuthenticData() const |
462 | { |
463 | return d_func()->reply.authenticData; |
464 | } |
465 | |
466 | /*! |
467 | \property QDnsLookup::error |
468 | \brief the type of error that occurred if the DNS lookup failed, or NoError. |
469 | */ |
470 | |
471 | QDnsLookup::Error QDnsLookup::error() const |
472 | { |
473 | return d_func()->reply.error; |
474 | } |
475 | |
476 | /*! |
477 | \property QDnsLookup::errorString |
478 | \brief a human-readable description of the error if the DNS lookup failed. |
479 | */ |
480 | |
481 | QString QDnsLookup::errorString() const |
482 | { |
483 | return d_func()->reply.errorString; |
484 | } |
485 | |
486 | /*! |
487 | Returns whether the reply has finished or was aborted. |
488 | */ |
489 | |
490 | bool QDnsLookup::isFinished() const |
491 | { |
492 | return d_func()->isFinished; |
493 | } |
494 | |
495 | /*! |
496 | \property QDnsLookup::name |
497 | \brief the name to lookup. |
498 | |
499 | If the name to look up is empty, QDnsLookup will attempt to resolve the |
500 | root domain of DNS. That query is usually performed with QDnsLookup::type |
501 | set to \l{QDnsLookup::Type}{NS}. |
502 | |
503 | \note The name will be encoded using IDNA, which means it's unsuitable for |
504 | querying SRV records compatible with the DNS-SD specification. |
505 | */ |
506 | |
507 | QString QDnsLookup::name() const |
508 | { |
509 | return d_func()->name; |
510 | } |
511 | |
512 | void QDnsLookup::setName(const QString &name) |
513 | { |
514 | Q_D(QDnsLookup); |
515 | d->name = name; |
516 | } |
517 | |
518 | QBindable<QString> QDnsLookup::bindableName() |
519 | { |
520 | Q_D(QDnsLookup); |
521 | return &d->name; |
522 | } |
523 | |
524 | /*! |
525 | \property QDnsLookup::type |
526 | \brief the type of DNS lookup. |
527 | */ |
528 | |
529 | QDnsLookup::Type QDnsLookup::type() const |
530 | { |
531 | return d_func()->type; |
532 | } |
533 | |
534 | void QDnsLookup::setType(Type type) |
535 | { |
536 | Q_D(QDnsLookup); |
537 | d->type = type; |
538 | } |
539 | |
540 | QBindable<QDnsLookup::Type> QDnsLookup::bindableType() |
541 | { |
542 | Q_D(QDnsLookup); |
543 | return &d->type; |
544 | } |
545 | |
546 | /*! |
547 | \property QDnsLookup::nameserver |
548 | \brief the nameserver to use for DNS lookup. |
549 | */ |
550 | |
551 | QHostAddress QDnsLookup::nameserver() const |
552 | { |
553 | return d_func()->nameserver; |
554 | } |
555 | |
556 | void QDnsLookup::setNameserver(const QHostAddress &nameserver) |
557 | { |
558 | Q_D(QDnsLookup); |
559 | d->nameserver = nameserver; |
560 | } |
561 | |
562 | QBindable<QHostAddress> QDnsLookup::bindableNameserver() |
563 | { |
564 | Q_D(QDnsLookup); |
565 | return &d->nameserver; |
566 | } |
567 | |
568 | /*! |
569 | \property QDnsLookup::nameserverPort |
570 | \since 6.6 |
571 | \brief the port number of nameserver to use for DNS lookup. |
572 | |
573 | The value of 0 indicates that QDnsLookup should use the default port for |
574 | the nameserverProtocol(). |
575 | |
576 | \include qdnslookup.cpp nameserver-port |
577 | */ |
578 | |
579 | quint16 QDnsLookup::nameserverPort() const |
580 | { |
581 | return d_func()->port; |
582 | } |
583 | |
584 | void QDnsLookup::setNameserverPort(quint16 nameserverPort) |
585 | { |
586 | Q_D(QDnsLookup); |
587 | d->port = nameserverPort; |
588 | } |
589 | |
590 | QBindable<quint16> QDnsLookup::bindableNameserverPort() |
591 | { |
592 | Q_D(QDnsLookup); |
593 | return &d->port; |
594 | } |
595 | |
596 | /*! |
597 | \property QDnsLookup::nameserverProtocol |
598 | \since 6.8 |
599 | \brief the protocol to use when sending the DNS query |
600 | |
601 | \sa isProtocolSupported() |
602 | */ |
603 | QDnsLookup::Protocol QDnsLookup::nameserverProtocol() const |
604 | { |
605 | return d_func()->protocol; |
606 | } |
607 | |
608 | void QDnsLookup::setNameserverProtocol(Protocol protocol) |
609 | { |
610 | d_func()->protocol = protocol; |
611 | } |
612 | |
613 | QBindable<QDnsLookup::Protocol> QDnsLookup::bindableNameserverProtocol() |
614 | { |
615 | return &d_func()->protocol; |
616 | } |
617 | |
618 | /*! |
619 | \fn void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port) |
620 | \since 6.6 |
621 | |
622 | Sets the nameserver to \a nameserver and the port to \a port. |
623 | |
624 | \include qdnslookup.cpp nameserver-port |
625 | |
626 | \sa QDnsLookup::nameserver, QDnsLookup::nameserverPort |
627 | */ |
628 | |
629 | void QDnsLookup::setNameserver(Protocol protocol, const QHostAddress &nameserver, quint16 port) |
630 | { |
631 | Qt::beginPropertyUpdateGroup(); |
632 | setNameserver(nameserver); |
633 | setNameserverPort(port); |
634 | setNameserverProtocol(protocol); |
635 | Qt::endPropertyUpdateGroup(); |
636 | } |
637 | |
638 | /*! |
639 | Returns the list of canonical name records associated with this lookup. |
640 | */ |
641 | |
642 | QList<QDnsDomainNameRecord> QDnsLookup::canonicalNameRecords() const |
643 | { |
644 | return d_func()->reply.canonicalNameRecords; |
645 | } |
646 | |
647 | /*! |
648 | Returns the list of host address records associated with this lookup. |
649 | */ |
650 | |
651 | QList<QDnsHostAddressRecord> QDnsLookup::hostAddressRecords() const |
652 | { |
653 | return d_func()->reply.hostAddressRecords; |
654 | } |
655 | |
656 | /*! |
657 | Returns the list of mail exchange records associated with this lookup. |
658 | |
659 | The records are sorted according to |
660 | \l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them |
661 | to connect to servers, you should try them in the order they are listed. |
662 | */ |
663 | |
664 | QList<QDnsMailExchangeRecord> QDnsLookup::mailExchangeRecords() const |
665 | { |
666 | return d_func()->reply.mailExchangeRecords; |
667 | } |
668 | |
669 | /*! |
670 | Returns the list of name server records associated with this lookup. |
671 | */ |
672 | |
673 | QList<QDnsDomainNameRecord> QDnsLookup::nameServerRecords() const |
674 | { |
675 | return d_func()->reply.nameServerRecords; |
676 | } |
677 | |
678 | /*! |
679 | Returns the list of pointer records associated with this lookup. |
680 | */ |
681 | |
682 | QList<QDnsDomainNameRecord> QDnsLookup::pointerRecords() const |
683 | { |
684 | return d_func()->reply.pointerRecords; |
685 | } |
686 | |
687 | /*! |
688 | Returns the list of service records associated with this lookup. |
689 | |
690 | The records are sorted according to |
691 | \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them |
692 | to connect to servers, you should try them in the order they are listed. |
693 | */ |
694 | |
695 | QList<QDnsServiceRecord> QDnsLookup::serviceRecords() const |
696 | { |
697 | return d_func()->reply.serviceRecords; |
698 | } |
699 | |
700 | /*! |
701 | Returns the list of text records associated with this lookup. |
702 | */ |
703 | |
704 | QList<QDnsTextRecord> QDnsLookup::textRecords() const |
705 | { |
706 | return d_func()->reply.textRecords; |
707 | } |
708 | |
709 | /*! |
710 | \since 6.8 |
711 | Returns the list of TLS association records associated with this lookup. |
712 | |
713 | According to the standards relating to DNS-based Authentication of Named |
714 | Entities (DANE), this field should be ignored and must not be used for |
715 | verifying the authentity of a given server if the authenticity of the DNS |
716 | reply cannot itself be confirmed. See isAuthenticData() for more |
717 | information. |
718 | */ |
719 | QList<QDnsTlsAssociationRecord> QDnsLookup::tlsAssociationRecords() const |
720 | { |
721 | return d_func()->reply.tlsAssociationRecords; |
722 | } |
723 | |
724 | #if QT_CONFIG(ssl) |
725 | /*! |
726 | \since 6.8 |
727 | Sets the \a sslConfiguration to use for outgoing DNS-over-TLS connections. |
728 | |
729 | \sa sslConfiguration(), QSslSocket::setSslConfiguration() |
730 | */ |
731 | void QDnsLookup::setSslConfiguration(const QSslConfiguration &sslConfiguration) |
732 | { |
733 | Q_D(QDnsLookup); |
734 | d->sslConfiguration.emplace(args: sslConfiguration); |
735 | } |
736 | |
737 | /*! |
738 | Returns the current SSL configuration. |
739 | |
740 | \sa setSslConfiguration() |
741 | */ |
742 | QSslConfiguration QDnsLookup::sslConfiguration() const |
743 | { |
744 | const Q_D(QDnsLookup); |
745 | return d->sslConfiguration.value_or(u: QSslConfiguration::defaultConfiguration()); |
746 | } |
747 | #endif |
748 | |
749 | /*! |
750 | Aborts the DNS lookup operation. |
751 | |
752 | If the lookup is already finished, does nothing. |
753 | */ |
754 | |
755 | void QDnsLookup::abort() |
756 | { |
757 | Q_D(QDnsLookup); |
758 | if (d->runnable) { |
759 | d->runnable = nullptr; |
760 | d->reply = QDnsLookupReply(); |
761 | d->reply.error = QDnsLookup::OperationCancelledError; |
762 | d->reply.errorString = tr(s: "Operation cancelled"); |
763 | d->isFinished = true; |
764 | emit finished(); |
765 | } |
766 | } |
767 | |
768 | /*! |
769 | Performs the DNS lookup. |
770 | |
771 | The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion. |
772 | */ |
773 | |
774 | void QDnsLookup::lookup() |
775 | { |
776 | Q_D(QDnsLookup); |
777 | d->isFinished = false; |
778 | d->reply = QDnsLookupReply(); |
779 | if (!QCoreApplication::instance()) { |
780 | // NOT qCWarning because this isn't a result of the lookup |
781 | qWarning(msg: "QDnsLookup requires a QCoreApplication"); |
782 | return; |
783 | } |
784 | |
785 | auto l = [this](const QDnsLookupReply &reply) { |
786 | Q_D(QDnsLookup); |
787 | if (d->runnable == sender()) { |
788 | #ifdef QDNSLOOKUP_DEBUG |
789 | qDebug("DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString)); |
790 | #endif |
791 | #if QT_CONFIG(ssl) |
792 | d->sslConfiguration = std::move(reply.sslConfiguration); |
793 | #endif |
794 | d->reply = reply; |
795 | d->runnable = nullptr; |
796 | d->isFinished = true; |
797 | emit finished(); |
798 | } |
799 | }; |
800 | |
801 | d->runnable = new QDnsLookupRunnable(d); |
802 | connect(sender: d->runnable, signal: &QDnsLookupRunnable::finished, context: this, slot&: l, |
803 | type: Qt::BlockingQueuedConnection); |
804 | theDnsLookupThreadPool->start(runnable: d->runnable); |
805 | } |
806 | |
807 | /*! |
808 | \class QDnsDomainNameRecord |
809 | \brief The QDnsDomainNameRecord class stores information about a domain |
810 | name record. |
811 | |
812 | \inmodule QtNetwork |
813 | \ingroup network |
814 | \ingroup shared |
815 | |
816 | When performing a name server lookup, zero or more records will be returned. |
817 | Each record is represented by a QDnsDomainNameRecord instance. |
818 | |
819 | \sa QDnsLookup |
820 | */ |
821 | |
822 | /*! |
823 | Constructs an empty domain name record object. |
824 | */ |
825 | |
826 | QDnsDomainNameRecord::QDnsDomainNameRecord() |
827 | : d(new QDnsDomainNameRecordPrivate) |
828 | { |
829 | } |
830 | |
831 | /*! |
832 | Constructs a copy of \a other. |
833 | */ |
834 | |
835 | QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other) |
836 | : d(other.d) |
837 | { |
838 | } |
839 | |
840 | /*! |
841 | Destroys a domain name record. |
842 | */ |
843 | |
844 | QDnsDomainNameRecord::~QDnsDomainNameRecord() |
845 | { |
846 | } |
847 | |
848 | /*! |
849 | Returns the name for this record. |
850 | */ |
851 | |
852 | QString QDnsDomainNameRecord::name() const |
853 | { |
854 | return d->name; |
855 | } |
856 | |
857 | /*! |
858 | Returns the duration in seconds for which this record is valid. |
859 | */ |
860 | |
861 | quint32 QDnsDomainNameRecord::timeToLive() const |
862 | { |
863 | return d->timeToLive; |
864 | } |
865 | |
866 | /*! |
867 | Returns the value for this domain name record. |
868 | */ |
869 | |
870 | QString QDnsDomainNameRecord::value() const |
871 | { |
872 | return d->value; |
873 | } |
874 | |
875 | /*! |
876 | Assigns the data of the \a other object to this record object, |
877 | and returns a reference to it. |
878 | */ |
879 | |
880 | QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other) |
881 | { |
882 | d = other.d; |
883 | return *this; |
884 | } |
885 | /*! |
886 | \fn void QDnsDomainNameRecord::swap(QDnsDomainNameRecord &other) |
887 | |
888 | Swaps this domain-name record instance with \a other. This |
889 | function is very fast and never fails. |
890 | */ |
891 | |
892 | /*! |
893 | \class QDnsHostAddressRecord |
894 | \brief The QDnsHostAddressRecord class stores information about a host |
895 | address record. |
896 | |
897 | \inmodule QtNetwork |
898 | \ingroup network |
899 | \ingroup shared |
900 | |
901 | When performing an address lookup, zero or more records will be |
902 | returned. Each record is represented by a QDnsHostAddressRecord instance. |
903 | |
904 | \sa QDnsLookup |
905 | */ |
906 | |
907 | /*! |
908 | Constructs an empty host address record object. |
909 | */ |
910 | |
911 | QDnsHostAddressRecord::QDnsHostAddressRecord() |
912 | : d(new QDnsHostAddressRecordPrivate) |
913 | { |
914 | } |
915 | |
916 | /*! |
917 | Constructs a copy of \a other. |
918 | */ |
919 | |
920 | QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other) |
921 | : d(other.d) |
922 | { |
923 | } |
924 | |
925 | /*! |
926 | Destroys a host address record. |
927 | */ |
928 | |
929 | QDnsHostAddressRecord::~QDnsHostAddressRecord() |
930 | { |
931 | } |
932 | |
933 | /*! |
934 | Returns the name for this record. |
935 | */ |
936 | |
937 | QString QDnsHostAddressRecord::name() const |
938 | { |
939 | return d->name; |
940 | } |
941 | |
942 | /*! |
943 | Returns the duration in seconds for which this record is valid. |
944 | */ |
945 | |
946 | quint32 QDnsHostAddressRecord::timeToLive() const |
947 | { |
948 | return d->timeToLive; |
949 | } |
950 | |
951 | /*! |
952 | Returns the value for this host address record. |
953 | */ |
954 | |
955 | QHostAddress QDnsHostAddressRecord::value() const |
956 | { |
957 | return d->value; |
958 | } |
959 | |
960 | /*! |
961 | Assigns the data of the \a other object to this record object, |
962 | and returns a reference to it. |
963 | */ |
964 | |
965 | QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other) |
966 | { |
967 | d = other.d; |
968 | return *this; |
969 | } |
970 | /*! |
971 | \fn void QDnsHostAddressRecord::swap(QDnsHostAddressRecord &other) |
972 | |
973 | Swaps this host address record instance with \a other. This |
974 | function is very fast and never fails. |
975 | */ |
976 | |
977 | /*! |
978 | \class QDnsMailExchangeRecord |
979 | \brief The QDnsMailExchangeRecord class stores information about a DNS MX record. |
980 | |
981 | \inmodule QtNetwork |
982 | \ingroup network |
983 | \ingroup shared |
984 | |
985 | When performing a lookup on a service, zero or more records will be |
986 | returned. Each record is represented by a QDnsMailExchangeRecord instance. |
987 | |
988 | The meaning of the fields is defined in |
989 | \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}. |
990 | |
991 | \sa QDnsLookup |
992 | */ |
993 | |
994 | /*! |
995 | Constructs an empty mail exchange record object. |
996 | */ |
997 | |
998 | QDnsMailExchangeRecord::QDnsMailExchangeRecord() |
999 | : d(new QDnsMailExchangeRecordPrivate) |
1000 | { |
1001 | } |
1002 | |
1003 | /*! |
1004 | Constructs a copy of \a other. |
1005 | */ |
1006 | |
1007 | QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other) |
1008 | : d(other.d) |
1009 | { |
1010 | } |
1011 | |
1012 | /*! |
1013 | Destroys a mail exchange record. |
1014 | */ |
1015 | |
1016 | QDnsMailExchangeRecord::~QDnsMailExchangeRecord() |
1017 | { |
1018 | } |
1019 | |
1020 | /*! |
1021 | Returns the domain name of the mail exchange for this record. |
1022 | */ |
1023 | |
1024 | QString QDnsMailExchangeRecord::exchange() const |
1025 | { |
1026 | return d->exchange; |
1027 | } |
1028 | |
1029 | /*! |
1030 | Returns the name for this record. |
1031 | */ |
1032 | |
1033 | QString QDnsMailExchangeRecord::name() const |
1034 | { |
1035 | return d->name; |
1036 | } |
1037 | |
1038 | /*! |
1039 | Returns the preference for this record. |
1040 | */ |
1041 | |
1042 | quint16 QDnsMailExchangeRecord::preference() const |
1043 | { |
1044 | return d->preference; |
1045 | } |
1046 | |
1047 | /*! |
1048 | Returns the duration in seconds for which this record is valid. |
1049 | */ |
1050 | |
1051 | quint32 QDnsMailExchangeRecord::timeToLive() const |
1052 | { |
1053 | return d->timeToLive; |
1054 | } |
1055 | |
1056 | /*! |
1057 | Assigns the data of the \a other object to this record object, |
1058 | and returns a reference to it. |
1059 | */ |
1060 | |
1061 | QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other) |
1062 | { |
1063 | d = other.d; |
1064 | return *this; |
1065 | } |
1066 | /*! |
1067 | \fn void QDnsMailExchangeRecord::swap(QDnsMailExchangeRecord &other) |
1068 | |
1069 | Swaps this mail exchange record with \a other. This function is |
1070 | very fast and never fails. |
1071 | */ |
1072 | |
1073 | /*! |
1074 | \class QDnsServiceRecord |
1075 | \brief The QDnsServiceRecord class stores information about a DNS SRV record. |
1076 | |
1077 | \inmodule QtNetwork |
1078 | \ingroup network |
1079 | \ingroup shared |
1080 | |
1081 | When performing a lookup on a service, zero or more records will be |
1082 | returned. Each record is represented by a QDnsServiceRecord instance. |
1083 | |
1084 | The meaning of the fields is defined in |
1085 | \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}. |
1086 | |
1087 | \sa QDnsLookup |
1088 | */ |
1089 | |
1090 | /*! |
1091 | Constructs an empty service record object. |
1092 | */ |
1093 | |
1094 | QDnsServiceRecord::QDnsServiceRecord() |
1095 | : d(new QDnsServiceRecordPrivate) |
1096 | { |
1097 | } |
1098 | |
1099 | /*! |
1100 | Constructs a copy of \a other. |
1101 | */ |
1102 | |
1103 | QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other) |
1104 | : d(other.d) |
1105 | { |
1106 | } |
1107 | |
1108 | /*! |
1109 | Destroys a service record. |
1110 | */ |
1111 | |
1112 | QDnsServiceRecord::~QDnsServiceRecord() |
1113 | { |
1114 | } |
1115 | |
1116 | /*! |
1117 | Returns the name for this record. |
1118 | */ |
1119 | |
1120 | QString QDnsServiceRecord::name() const |
1121 | { |
1122 | return d->name; |
1123 | } |
1124 | |
1125 | /*! |
1126 | Returns the port on the target host for this service record. |
1127 | */ |
1128 | |
1129 | quint16 QDnsServiceRecord::port() const |
1130 | { |
1131 | return d->port; |
1132 | } |
1133 | |
1134 | /*! |
1135 | Returns the priority for this service record. |
1136 | |
1137 | A client must attempt to contact the target host with the lowest-numbered |
1138 | priority. |
1139 | */ |
1140 | |
1141 | quint16 QDnsServiceRecord::priority() const |
1142 | { |
1143 | return d->priority; |
1144 | } |
1145 | |
1146 | /*! |
1147 | Returns the domain name of the target host for this service record. |
1148 | */ |
1149 | |
1150 | QString QDnsServiceRecord::target() const |
1151 | { |
1152 | return d->target; |
1153 | } |
1154 | |
1155 | /*! |
1156 | Returns the duration in seconds for which this record is valid. |
1157 | */ |
1158 | |
1159 | quint32 QDnsServiceRecord::timeToLive() const |
1160 | { |
1161 | return d->timeToLive; |
1162 | } |
1163 | |
1164 | /*! |
1165 | Returns the weight for this service record. |
1166 | |
1167 | The weight field specifies a relative weight for entries with the same |
1168 | priority. Entries with higher weights should be selected with a higher |
1169 | probability. |
1170 | */ |
1171 | |
1172 | quint16 QDnsServiceRecord::weight() const |
1173 | { |
1174 | return d->weight; |
1175 | } |
1176 | |
1177 | /*! |
1178 | Assigns the data of the \a other object to this record object, |
1179 | and returns a reference to it. |
1180 | */ |
1181 | |
1182 | QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other) |
1183 | { |
1184 | d = other.d; |
1185 | return *this; |
1186 | } |
1187 | /*! |
1188 | \fn void QDnsServiceRecord::swap(QDnsServiceRecord &other) |
1189 | |
1190 | Swaps this service record instance with \a other. This function is |
1191 | very fast and never fails. |
1192 | */ |
1193 | |
1194 | /*! |
1195 | \class QDnsTextRecord |
1196 | \brief The QDnsTextRecord class stores information about a DNS TXT record. |
1197 | |
1198 | \inmodule QtNetwork |
1199 | \ingroup network |
1200 | \ingroup shared |
1201 | |
1202 | When performing a text lookup, zero or more records will be |
1203 | returned. Each record is represented by a QDnsTextRecord instance. |
1204 | |
1205 | The meaning of the fields is defined in |
1206 | \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}. |
1207 | |
1208 | \sa QDnsLookup |
1209 | */ |
1210 | |
1211 | /*! |
1212 | Constructs an empty text record object. |
1213 | */ |
1214 | |
1215 | QDnsTextRecord::QDnsTextRecord() |
1216 | : d(new QDnsTextRecordPrivate) |
1217 | { |
1218 | } |
1219 | |
1220 | /*! |
1221 | Constructs a copy of \a other. |
1222 | */ |
1223 | |
1224 | QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other) |
1225 | : d(other.d) |
1226 | { |
1227 | } |
1228 | |
1229 | /*! |
1230 | Destroys a text record. |
1231 | */ |
1232 | |
1233 | QDnsTextRecord::~QDnsTextRecord() |
1234 | { |
1235 | } |
1236 | |
1237 | /*! |
1238 | Returns the name for this text record. |
1239 | */ |
1240 | |
1241 | QString QDnsTextRecord::name() const |
1242 | { |
1243 | return d->name; |
1244 | } |
1245 | |
1246 | /*! |
1247 | Returns the duration in seconds for which this record is valid. |
1248 | */ |
1249 | |
1250 | quint32 QDnsTextRecord::timeToLive() const |
1251 | { |
1252 | return d->timeToLive; |
1253 | } |
1254 | |
1255 | /*! |
1256 | Returns the values for this text record. |
1257 | */ |
1258 | |
1259 | QList<QByteArray> QDnsTextRecord::values() const |
1260 | { |
1261 | return d->values; |
1262 | } |
1263 | |
1264 | /*! |
1265 | Assigns the data of the \a other object to this record object, |
1266 | and returns a reference to it. |
1267 | */ |
1268 | |
1269 | QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other) |
1270 | { |
1271 | d = other.d; |
1272 | return *this; |
1273 | } |
1274 | /*! |
1275 | \fn void QDnsTextRecord::swap(QDnsTextRecord &other) |
1276 | |
1277 | Swaps this text record instance with \a other. This function is |
1278 | very fast and never fails. |
1279 | */ |
1280 | |
1281 | /*! |
1282 | \class QDnsTlsAssociationRecord |
1283 | \since 6.8 |
1284 | \brief The QDnsTlsAssociationRecord class stores information about a DNS TLSA record. |
1285 | |
1286 | \inmodule QtNetwork |
1287 | \ingroup network |
1288 | \ingroup shared |
1289 | |
1290 | When performing a text lookup, zero or more records will be returned. Each |
1291 | record is represented by a QDnsTlsAssociationRecord instance. |
1292 | |
1293 | The meaning of the fields is defined in \l{RFC 6698}. |
1294 | |
1295 | \sa QDnsLookup |
1296 | */ |
1297 | |
1298 | QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate) |
1299 | |
1300 | /*! |
1301 | \enum QDnsTlsAssociationRecord::CertificateUsage |
1302 | |
1303 | This enumeration contains valid values for the certificate usage field of |
1304 | TLS Association queries. The following list is up-to-date with \l{RFC 6698} |
1305 | section 2.1.1 and RFC 7218 section 2.1. Please refer to those documents for |
1306 | authoritative instructions on interpreting this enumeration. |
1307 | |
1308 | \value CertificateAuthorityConstrait |
1309 | Indicates the record includes an association to a specific Certificate |
1310 | Authority that must be found in the TLS server's certificate chain and |
1311 | must pass PKIX validation. |
1312 | |
1313 | \value ServiceCertificateConstraint |
1314 | Indicates the record includes an association to a certificate that must |
1315 | match the end entity certificate provided by the TLS server and must |
1316 | pass PKIX validation. |
1317 | |
1318 | \value TrustAnchorAssertion |
1319 | Indicates the record includes an association to a certificate that MUST |
1320 | be used as the ultimate trust anchor to validate the TLS server's |
1321 | certificate and must pass PKIX validation. |
1322 | |
1323 | \value DomainIssuedCertificate |
1324 | Indicates the record includes an association to a certificate that must |
1325 | match the end entity certificate provided by the TLS server. PKIX |
1326 | validation is not tested. |
1327 | |
1328 | \value PrivateUse |
1329 | No standard meaning applied. |
1330 | |
1331 | \value PKIX_TA |
1332 | Alias; mnemonic for Public Key Infrastructure Trust Anchor |
1333 | |
1334 | \value PKIX_EE |
1335 | Alias; mnemonic for Public Key Infrastructure End Entity |
1336 | |
1337 | \value DANE_TA |
1338 | Alias; mnemonic for DNS-based Authentication of Named Entities Trust Anchor |
1339 | |
1340 | \value DANE_EE |
1341 | Alias; mnemonic for DNS-based Authentication of Named Entities End Entity |
1342 | |
1343 | \value PrivCert |
1344 | Alias |
1345 | |
1346 | Other values are currently reserved, but may be unreserved by future |
1347 | standards. This enumeration can be used for those values even if no |
1348 | enumerator is provided. |
1349 | |
1350 | \sa usage() |
1351 | */ |
1352 | |
1353 | /*! |
1354 | \enum QDnsTlsAssociationRecord::Selector |
1355 | |
1356 | This enumeration contains valid values for the selector field of TLS |
1357 | Association queries. The following list is up-to-date with \l{RFC 6698} |
1358 | section 2.1.2 and RFC 7218 section 2.2. Please refer to those documents for |
1359 | authoritative instructions on interpreting this enumeration. |
1360 | |
1361 | \value FullCertificate |
1362 | Indicates this record refers to the full certificate in its binary |
1363 | structure form. |
1364 | |
1365 | \value SubjectPublicKeyInfo |
1366 | Indicates the record refers to the certificate's subject and public |
1367 | key information, in DER-encoded binary structure form. |
1368 | |
1369 | \value PrivateUse |
1370 | No standard meaning applied. |
1371 | |
1372 | \value Cert |
1373 | Alias |
1374 | |
1375 | \value SPKI |
1376 | Alias |
1377 | |
1378 | \value PrivSel |
1379 | Alias |
1380 | |
1381 | Other values are currently reserved, but may be unreserved by future |
1382 | standards. This enumeration can be used for those values even if no |
1383 | enumerator is provided. |
1384 | |
1385 | \sa selector() |
1386 | */ |
1387 | |
1388 | /*! |
1389 | \enum QDnsTlsAssociationRecord::MatchingType |
1390 | |
1391 | This enumeration contains valid values for the matching type field of TLS |
1392 | Association queries. The following list is up-to-date with \l{RFC 6698} |
1393 | section 2.1.3 and RFC 7218 section 2.3. Please refer to those documents for |
1394 | authoritative instructions on interpreting this enumeration. |
1395 | |
1396 | \value Exact |
1397 | Indicates this the certificate or SPKI data is stored verbatim in this |
1398 | record. |
1399 | |
1400 | \value Sha256 |
1401 | Indicates this a SHA-256 checksum of the the certificate or SPKI data |
1402 | present in this record. |
1403 | |
1404 | \value Sha512 |
1405 | Indicates this a SHA-512 checksum of the the certificate or SPKI data |
1406 | present in this record. |
1407 | |
1408 | \value PrivateUse |
1409 | No standard meaning applied. |
1410 | |
1411 | \value PrivMatch |
1412 | Alias |
1413 | |
1414 | Other values are currently reserved, but may be unreserved by future |
1415 | standards. This enumeration can be used for those values even if no |
1416 | enumerator is provided. |
1417 | |
1418 | \sa matchType() |
1419 | */ |
1420 | |
1421 | /*! |
1422 | Constructs an empty TLS Association record. |
1423 | */ |
1424 | QDnsTlsAssociationRecord::QDnsTlsAssociationRecord() |
1425 | : d(new QDnsTlsAssociationRecordPrivate) |
1426 | { |
1427 | } |
1428 | |
1429 | /*! |
1430 | Constructs a copy of \a other. |
1431 | */ |
1432 | QDnsTlsAssociationRecord::QDnsTlsAssociationRecord(const QDnsTlsAssociationRecord &other) = default; |
1433 | |
1434 | /*! |
1435 | Moves the content of \a other into this object. |
1436 | */ |
1437 | QDnsTlsAssociationRecord & |
1438 | QDnsTlsAssociationRecord::operator=(const QDnsTlsAssociationRecord &other) = default; |
1439 | |
1440 | /*! |
1441 | Destroys this TLS Association record object. |
1442 | */ |
1443 | QDnsTlsAssociationRecord::~QDnsTlsAssociationRecord() = default; |
1444 | |
1445 | /*! |
1446 | Returns the name of this record. |
1447 | */ |
1448 | QString QDnsTlsAssociationRecord::name() const |
1449 | { |
1450 | return d->name; |
1451 | } |
1452 | |
1453 | /*! |
1454 | Returns the duration in seconds for which this record is valid. |
1455 | */ |
1456 | quint32 QDnsTlsAssociationRecord::timeToLive() const |
1457 | { |
1458 | return d->timeToLive; |
1459 | } |
1460 | |
1461 | /*! |
1462 | Returns the certificate usage field for this record. |
1463 | */ |
1464 | QDnsTlsAssociationRecord::CertificateUsage QDnsTlsAssociationRecord::usage() const |
1465 | { |
1466 | return d->usage; |
1467 | } |
1468 | |
1469 | /*! |
1470 | Returns the selector field for this record. |
1471 | */ |
1472 | QDnsTlsAssociationRecord::Selector QDnsTlsAssociationRecord::selector() const |
1473 | { |
1474 | return d->selector; |
1475 | } |
1476 | |
1477 | /*! |
1478 | Returns the match type field for this record. |
1479 | */ |
1480 | QDnsTlsAssociationRecord::MatchingType QDnsTlsAssociationRecord::matchType() const |
1481 | { |
1482 | return d->matchType; |
1483 | } |
1484 | |
1485 | /*! |
1486 | Returns the binary data field for this record. The interpretation of this |
1487 | binary data depends on the three numeric fields provided by |
1488 | certificateUsage(), selector(), and matchType(). |
1489 | |
1490 | Do note this is a binary field, even for the checksums, similar to what |
1491 | QCyrptographicHash::result() returns. |
1492 | */ |
1493 | QByteArray QDnsTlsAssociationRecord::value() const |
1494 | { |
1495 | return d->value; |
1496 | } |
1497 | |
1498 | static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label) |
1499 | { |
1500 | QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.'; |
1501 | if (label.isEmpty()) |
1502 | return QDnsLookupRunnable::EncodedLabel(1, rootDomain); |
1503 | |
1504 | QString encodedLabel = qt_ACE_do(domain: label, op: ToAceOnly, dot: ForbidLeadingDot); |
1505 | #ifdef Q_OS_WIN |
1506 | return encodedLabel; |
1507 | #else |
1508 | return std::move(encodedLabel).toLatin1(); |
1509 | #endif |
1510 | } |
1511 | |
1512 | inline QDnsLookupRunnable::QDnsLookupRunnable(const QDnsLookupPrivate *d) |
1513 | : requestName(encodeLabel(label: d->name)), |
1514 | nameserver(d->nameserver), |
1515 | requestType(d->type), |
1516 | port(d->port), |
1517 | protocol(d->protocol) |
1518 | { |
1519 | if (port == 0) |
1520 | port = QDnsLookup::defaultPortForProtocol(protocol); |
1521 | #if QT_CONFIG(ssl) |
1522 | sslConfiguration = d->sslConfiguration; |
1523 | #endif |
1524 | } |
1525 | |
1526 | void QDnsLookupRunnable::run() |
1527 | { |
1528 | QDnsLookupReply reply; |
1529 | |
1530 | // Validate input. |
1531 | if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) { |
1532 | reply.error = QDnsLookup::InvalidRequestError; |
1533 | reply.errorString = QDnsLookup::tr(s: "Invalid domain name"); |
1534 | } else { |
1535 | // Perform request. |
1536 | query(reply: &reply); |
1537 | |
1538 | // Sort results. |
1539 | qt_qdnsmailexchangerecord_sort(records&: reply.mailExchangeRecords); |
1540 | qt_qdnsservicerecord_sort(records&: reply.serviceRecords); |
1541 | } |
1542 | |
1543 | emit finished(reply); |
1544 | |
1545 | // maybe print the lookup error as warning |
1546 | switch (reply.error) { |
1547 | case QDnsLookup::NoError: |
1548 | case QDnsLookup::OperationCancelledError: |
1549 | case QDnsLookup::NotFoundError: |
1550 | case QDnsLookup::ServerFailureError: |
1551 | case QDnsLookup::ServerRefusedError: |
1552 | case QDnsLookup::TimeoutError: |
1553 | break; // no warning for these |
1554 | |
1555 | case QDnsLookup::ResolverError: |
1556 | case QDnsLookup::InvalidRequestError: |
1557 | case QDnsLookup::InvalidReplyError: |
1558 | qCWarning(lcDnsLookup()).nospace() |
1559 | << "DNS lookup failed ("<< reply.error << "): " |
1560 | << qUtf16Printable(reply.errorString) |
1561 | << "; request was "<< this; // continues below |
1562 | } |
1563 | } |
1564 | |
1565 | inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r) |
1566 | { |
1567 | // continued: print the information about the request |
1568 | d << r->requestName.left(n: MaxDomainNameLength); |
1569 | if (r->requestName.size() > MaxDomainNameLength) |
1570 | d << "... (truncated)"; |
1571 | d << " type "<< r->requestType; |
1572 | if (!r->nameserver.isNull()) { |
1573 | d << " to nameserver "<< qUtf16Printable(r->nameserver.toString()) |
1574 | << " port "<< (r->port ? r->port : QDnsLookup::defaultPortForProtocol(protocol: r->protocol)); |
1575 | switch (r->protocol) { |
1576 | case QDnsLookup::Standard: |
1577 | break; |
1578 | case QDnsLookup::DnsOverTls: |
1579 | d << " (TLS)"; |
1580 | } |
1581 | } |
1582 | return d; |
1583 | } |
1584 | |
1585 | #if QT_CONFIG(ssl) |
1586 | static constexpr std::chrono::milliseconds DnsOverTlsConnectTimeout(15'000); |
1587 | static constexpr std::chrono::milliseconds DnsOverTlsTimeout(120'000); |
1588 | static constexpr quint8 DnsAuthenticDataBit = 0x20; |
1589 | |
1590 | static int makeReplyErrorFromSocket(QDnsLookupReply *reply, const QAbstractSocket *socket) |
1591 | { |
1592 | QDnsLookup::Error error = [&] { |
1593 | switch (socket->error()) { |
1594 | case QAbstractSocket::SocketTimeoutError: |
1595 | case QAbstractSocket::ProxyConnectionTimeoutError: |
1596 | return QDnsLookup::TimeoutError; |
1597 | default: |
1598 | return QDnsLookup::ResolverError; |
1599 | } |
1600 | }(); |
1601 | reply->setError(err: error, msg: socket->errorString()); |
1602 | return false; |
1603 | } |
1604 | |
1605 | bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query, |
1606 | ReplyBuffer &response) |
1607 | { |
1608 | QSslSocket socket; |
1609 | socket.setSslConfiguration(sslConfiguration.value_or(u: QSslConfiguration::defaultConfiguration())); |
1610 | |
1611 | # if QT_CONFIG(networkproxy) |
1612 | socket.setProtocolTag("domain-s"_L1); |
1613 | # endif |
1614 | |
1615 | // Request the name server attempt to authenticate the reply. |
1616 | query[3] |= DnsAuthenticDataBit; |
1617 | |
1618 | do { |
1619 | quint16 size = qToBigEndian<quint16>(source: query.size()); |
1620 | QDeadlineTimer timeout(DnsOverTlsTimeout); |
1621 | |
1622 | socket.connectToHostEncrypted(hostName: nameserver.toString(), port); |
1623 | socket.write(data: reinterpret_cast<const char *>(&size), len: sizeof(size)); |
1624 | socket.write(data: reinterpret_cast<const char *>(query.data()), len: query.size()); |
1625 | if (!socket.waitForEncrypted(msecs: DnsOverTlsConnectTimeout.count())) |
1626 | break; |
1627 | |
1628 | reply->sslConfiguration = socket.sslConfiguration(); |
1629 | |
1630 | // accumulate reply |
1631 | auto waitForBytes = [&](void *buffer, int count) { |
1632 | int remaining = timeout.remainingTime(); |
1633 | while (remaining >= 0 && socket.bytesAvailable() < count) { |
1634 | if (!socket.waitForReadyRead(msecs: remaining)) |
1635 | return false; |
1636 | } |
1637 | return socket.read(data: static_cast<char *>(buffer), maxlen: count) == count; |
1638 | }; |
1639 | if (!waitForBytes(&size, sizeof(size))) |
1640 | break; |
1641 | |
1642 | // note: strictly speaking, we're allocating memory based on untrusted data |
1643 | // but in practice, due to limited range of the data type (16 bits), |
1644 | // the maximum allocation is small. |
1645 | size = qFromBigEndian(source: size); |
1646 | response.resize(sz: size); |
1647 | if (waitForBytes(response.data(), size)) { |
1648 | // check if the AD bit is set; we'll trust it over TLS requests |
1649 | if (size >= 4) |
1650 | reply->authenticData = response[3] & DnsAuthenticDataBit; |
1651 | return true; |
1652 | } |
1653 | } while (false); |
1654 | |
1655 | // handle errors |
1656 | return makeReplyErrorFromSocket(reply, socket: &socket); |
1657 | } |
1658 | #else |
1659 | bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<unsigned char> query, |
1660 | ReplyBuffer &response) |
1661 | { |
1662 | Q_UNUSED(query) |
1663 | Q_UNUSED(response) |
1664 | reply->setError(QDnsLookup::ResolverError, QDnsLookup::tr("SSL/TLS support not present")); |
1665 | return false; |
1666 | } |
1667 | #endif |
1668 | |
1669 | QT_END_NAMESPACE |
1670 | |
1671 | #include "moc_qdnslookup.cpp" |
1672 | #include "moc_qdnslookup_p.cpp" |
1673 |
Definitions
- lcDnsLookup
- QDnsLookupThreadPool
- QDnsLookupThreadPool
- theDnsLookupThreadPool
- qt_qdnsmailexchangerecord_less_than
- qt_qdnsmailexchangerecord_sort
- qt_qdnsservicerecord_less_than
- qt_qdnsservicerecord_sort
- isProtocolSupported
- defaultPortForProtocol
- QDnsLookup
- QDnsLookup
- QDnsLookup
- QDnsLookup
- QDnsLookup
- ~QDnsLookup
- isAuthenticData
- error
- errorString
- isFinished
- name
- setName
- bindableName
- type
- setType
- bindableType
- nameserver
- setNameserver
- bindableNameserver
- nameserverPort
- setNameserverPort
- bindableNameserverPort
- nameserverProtocol
- setNameserverProtocol
- bindableNameserverProtocol
- setNameserver
- canonicalNameRecords
- hostAddressRecords
- mailExchangeRecords
- nameServerRecords
- pointerRecords
- serviceRecords
- textRecords
- tlsAssociationRecords
- setSslConfiguration
- sslConfiguration
- abort
- lookup
- QDnsDomainNameRecord
- QDnsDomainNameRecord
- ~QDnsDomainNameRecord
- name
- timeToLive
- value
- operator=
- QDnsHostAddressRecord
- QDnsHostAddressRecord
- ~QDnsHostAddressRecord
- name
- timeToLive
- value
- operator=
- QDnsMailExchangeRecord
- QDnsMailExchangeRecord
- ~QDnsMailExchangeRecord
- exchange
- name
- preference
- timeToLive
- operator=
- QDnsServiceRecord
- QDnsServiceRecord
- ~QDnsServiceRecord
- name
- port
- priority
- target
- timeToLive
- weight
- operator=
- QDnsTextRecord
- QDnsTextRecord
- ~QDnsTextRecord
- name
- timeToLive
- values
- operator=
- QDnsTlsAssociationRecord
- QDnsTlsAssociationRecord
- operator=
- ~QDnsTlsAssociationRecord
- name
- timeToLive
- usage
- selector
- matchType
- value
- encodeLabel
- QDnsLookupRunnable
- run
- operator<<
- DnsOverTlsConnectTimeout
- DnsOverTlsTimeout
- DnsAuthenticDataBit
- makeReplyErrorFromSocket
Learn to use CMake with our Intro Training
Find out more