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 <qloggingcategory.h> |
12 | #include <qrandom.h> |
13 | #include <qurl.h> |
14 | |
15 | #include <algorithm> |
16 | |
17 | QT_BEGIN_NAMESPACE |
18 | |
19 | static Q_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup" , QtCriticalMsg) |
20 | |
21 | namespace { |
22 | struct QDnsLookupThreadPool : QThreadPool |
23 | { |
24 | QDnsLookupThreadPool() |
25 | { |
26 | // Run up to 5 lookups in parallel. |
27 | setMaxThreadCount(5); |
28 | } |
29 | }; |
30 | } |
31 | |
32 | Q_APPLICATION_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool); |
33 | |
34 | static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2) |
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 | |
44 | static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &records) |
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(first: records.begin(), last: records.end(), comp: 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. |
57 | QList<QDnsMailExchangeRecord> slice; |
58 | const quint16 slicePreference = records.at(i).preference(); |
59 | for (int j = i; j < records.size(); ++j) { |
60 | if (records.at(i: j).preference() != slicePreference) |
61 | break; |
62 | slice << records.at(i: j); |
63 | } |
64 | |
65 | // Randomize the slice of records. |
66 | while (!slice.isEmpty()) { |
67 | const unsigned int pos = QRandomGenerator::global()->bounded(highest: slice.size()); |
68 | records[i++] = slice.takeAt(i: pos); |
69 | } |
70 | } |
71 | } |
72 | |
73 | static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2) |
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 | |
86 | static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records) |
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(first: records.begin(), last: records.end(), comp: 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. |
100 | QList<QDnsServiceRecord> slice; |
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(i: j).priority() != slicePriority) |
105 | break; |
106 | sliceWeight += records.at(i: j).weight(); |
107 | slice << records.at(i: 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(highest: sliceWeight + 1); |
117 | unsigned int summedWeight = 0; |
118 | for (int j = 0; j < slice.size(); ++j) { |
119 | summedWeight += slice.at(i: 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(i: j).weight(); |
128 | records[i++] = slice.takeAt(i: j); |
129 | break; |
130 | } |
131 | } |
132 | } |
133 | } |
134 | } |
135 | |
136 | /*! |
137 | \class QDnsLookup |
138 | \brief The QDnsLookup class represents a DNS lookup. |
139 | \since 5.0 |
140 | |
141 | \inmodule QtNetwork |
142 | \ingroup network |
143 | |
144 | QDnsLookup uses the mechanisms provided by the operating system to perform |
145 | DNS lookups. To perform a lookup you need to specify a \l name and \l type |
146 | then invoke the \l{QDnsLookup::lookup()}{lookup()} slot. The |
147 | \l{QDnsLookup::finished()}{finished()} signal will be emitted upon |
148 | completion. |
149 | |
150 | For example, you can determine which servers an XMPP chat client should |
151 | connect to for a given domain with: |
152 | |
153 | \snippet code/src_network_kernel_qdnslookup.cpp 0 |
154 | |
155 | Once the request finishes you can handle the results with: |
156 | |
157 | \snippet code/src_network_kernel_qdnslookup.cpp 1 |
158 | |
159 | \note If you simply want to find the IP address(es) associated with a host |
160 | name, or the host name associated with an IP address you should use |
161 | QHostInfo instead. |
162 | */ |
163 | |
164 | /*! |
165 | \enum QDnsLookup::Error |
166 | |
167 | Indicates all possible error conditions found during the |
168 | processing of the DNS lookup. |
169 | |
170 | \value NoError no error condition. |
171 | |
172 | \value ResolverError there was an error initializing the system's |
173 | DNS resolver. |
174 | |
175 | \value OperationCancelledError the lookup was aborted using the abort() |
176 | method. |
177 | |
178 | \value InvalidRequestError the requested DNS lookup was invalid. |
179 | |
180 | \value InvalidReplyError the reply returned by the server was invalid. |
181 | |
182 | \value ServerFailureError the server encountered an internal failure |
183 | while processing the request (SERVFAIL). |
184 | |
185 | \value ServerRefusedError the server refused to process the request for |
186 | security or policy reasons (REFUSED). |
187 | |
188 | \value NotFoundError the requested domain name does not exist |
189 | (NXDOMAIN). |
190 | |
191 | \value TimeoutError the server was not reached or did not reply |
192 | in time (since 6.6). |
193 | */ |
194 | |
195 | /*! |
196 | \enum QDnsLookup::Type |
197 | |
198 | Indicates the type of DNS lookup that was performed. |
199 | |
200 | \value A IPv4 address records. |
201 | |
202 | \value AAAA IPv6 address records. |
203 | |
204 | \value ANY any records. |
205 | |
206 | \value CNAME canonical name records. |
207 | |
208 | \value MX mail exchange records. |
209 | |
210 | \value NS name server records. |
211 | |
212 | \value PTR pointer records. |
213 | |
214 | \value SRV service records. |
215 | |
216 | \value TXT text records. |
217 | */ |
218 | |
219 | /*! |
220 | \fn void QDnsLookup::finished() |
221 | |
222 | This signal is emitted when the reply has finished processing. |
223 | */ |
224 | |
225 | /*! |
226 | \fn void QDnsLookup::nameChanged(const QString &name) |
227 | |
228 | This signal is emitted when the lookup \l name changes. |
229 | \a name is the new lookup name. |
230 | */ |
231 | |
232 | /*! |
233 | \fn void QDnsLookup::typeChanged(Type type) |
234 | |
235 | This signal is emitted when the lookup \l type changes. |
236 | \a type is the new lookup type. |
237 | */ |
238 | |
239 | /*! |
240 | Constructs a QDnsLookup object and sets \a parent as the parent object. |
241 | |
242 | The \l type property will default to QDnsLookup::A. |
243 | */ |
244 | |
245 | QDnsLookup::QDnsLookup(QObject *parent) |
246 | : QObject(*new QDnsLookupPrivate, parent) |
247 | { |
248 | } |
249 | |
250 | /*! |
251 | Constructs a QDnsLookup object for the given \a type and \a name and sets |
252 | \a parent as the parent object. |
253 | */ |
254 | |
255 | QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent) |
256 | : QObject(*new QDnsLookupPrivate, parent) |
257 | { |
258 | Q_D(QDnsLookup); |
259 | d->name = name; |
260 | d->type = type; |
261 | } |
262 | |
263 | /*! |
264 | \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent) |
265 | \since 5.4 |
266 | |
267 | Constructs a QDnsLookup object to issue a query for \a name of record type |
268 | \a type, using the DNS server \a nameserver running on the default DNS port, |
269 | and sets \a parent as the parent object. |
270 | */ |
271 | |
272 | QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent) |
273 | : QDnsLookup(type, name, nameserver, DnsPort, parent) |
274 | { |
275 | } |
276 | |
277 | /*! |
278 | \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent) |
279 | \since 6.6 |
280 | |
281 | Constructs a QDnsLookup object to issue a query for \a name of record type |
282 | \a type, using the DNS server \a nameserver running on port \a port, and |
283 | sets \a parent as the parent object. |
284 | |
285 | //! [nameserver-port] |
286 | \note Setting the port number to any value other than the default (53) can |
287 | cause the name resolution to fail, depending on the operating system |
288 | limitations and firewalls. Notably, the Windows API used by QDnsLookup is |
289 | unable to handle alternate port numbers. |
290 | //! [nameserver-port] |
291 | */ |
292 | QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent) |
293 | : QObject(*new QDnsLookupPrivate, parent) |
294 | { |
295 | Q_D(QDnsLookup); |
296 | d->name = name; |
297 | d->type = type; |
298 | d->port = port; |
299 | d->nameserver = nameserver; |
300 | } |
301 | |
302 | /*! |
303 | Destroys the QDnsLookup object. |
304 | |
305 | It is safe to delete a QDnsLookup object even if it is not finished, you |
306 | will simply never receive its results. |
307 | */ |
308 | |
309 | QDnsLookup::~QDnsLookup() |
310 | { |
311 | } |
312 | |
313 | /*! |
314 | \property QDnsLookup::error |
315 | \brief the type of error that occurred if the DNS lookup failed, or NoError. |
316 | */ |
317 | |
318 | QDnsLookup::Error QDnsLookup::error() const |
319 | { |
320 | return d_func()->reply.error; |
321 | } |
322 | |
323 | /*! |
324 | \property QDnsLookup::errorString |
325 | \brief a human-readable description of the error if the DNS lookup failed. |
326 | */ |
327 | |
328 | QString QDnsLookup::errorString() const |
329 | { |
330 | return d_func()->reply.errorString; |
331 | } |
332 | |
333 | /*! |
334 | Returns whether the reply has finished or was aborted. |
335 | */ |
336 | |
337 | bool QDnsLookup::isFinished() const |
338 | { |
339 | return d_func()->isFinished; |
340 | } |
341 | |
342 | /*! |
343 | \property QDnsLookup::name |
344 | \brief the name to lookup. |
345 | |
346 | If the name to look up is empty, QDnsLookup will attempt to resolve the |
347 | root domain of DNS. That query is usually performed with QDnsLookup::type |
348 | set to \l{QDnsLookup::Type}{NS}. |
349 | |
350 | \note The name will be encoded using IDNA, which means it's unsuitable for |
351 | querying SRV records compatible with the DNS-SD specification. |
352 | */ |
353 | |
354 | QString QDnsLookup::name() const |
355 | { |
356 | return d_func()->name; |
357 | } |
358 | |
359 | void QDnsLookup::setName(const QString &name) |
360 | { |
361 | Q_D(QDnsLookup); |
362 | d->name = name; |
363 | } |
364 | |
365 | QBindable<QString> QDnsLookup::bindableName() |
366 | { |
367 | Q_D(QDnsLookup); |
368 | return &d->name; |
369 | } |
370 | |
371 | /*! |
372 | \property QDnsLookup::type |
373 | \brief the type of DNS lookup. |
374 | */ |
375 | |
376 | QDnsLookup::Type QDnsLookup::type() const |
377 | { |
378 | return d_func()->type; |
379 | } |
380 | |
381 | void QDnsLookup::setType(Type type) |
382 | { |
383 | Q_D(QDnsLookup); |
384 | d->type = type; |
385 | } |
386 | |
387 | QBindable<QDnsLookup::Type> QDnsLookup::bindableType() |
388 | { |
389 | Q_D(QDnsLookup); |
390 | return &d->type; |
391 | } |
392 | |
393 | /*! |
394 | \property QDnsLookup::nameserver |
395 | \brief the nameserver to use for DNS lookup. |
396 | */ |
397 | |
398 | QHostAddress QDnsLookup::nameserver() const |
399 | { |
400 | return d_func()->nameserver; |
401 | } |
402 | |
403 | void QDnsLookup::setNameserver(const QHostAddress &nameserver) |
404 | { |
405 | Q_D(QDnsLookup); |
406 | d->nameserver = nameserver; |
407 | } |
408 | |
409 | QBindable<QHostAddress> QDnsLookup::bindableNameserver() |
410 | { |
411 | Q_D(QDnsLookup); |
412 | return &d->nameserver; |
413 | } |
414 | |
415 | /*! |
416 | \property QDnsLookup::nameserverPort |
417 | \since 6.6 |
418 | \brief the port number of nameserver to use for DNS lookup. |
419 | \include qdnslookup.cpp nameserver-port |
420 | */ |
421 | |
422 | quint16 QDnsLookup::nameserverPort() const |
423 | { |
424 | return d_func()->port; |
425 | } |
426 | |
427 | void QDnsLookup::setNameserverPort(quint16 nameserverPort) |
428 | { |
429 | Q_D(QDnsLookup); |
430 | d->port = nameserverPort; |
431 | } |
432 | |
433 | QBindable<quint16> QDnsLookup::bindableNameserverPort() |
434 | { |
435 | Q_D(QDnsLookup); |
436 | return &d->port; |
437 | } |
438 | |
439 | /*! |
440 | \since 6.6 |
441 | Sets the nameserver to \a nameserver and the port to \a port. |
442 | |
443 | \include qdnslookup.cpp nameserver-port |
444 | |
445 | \sa QDnsLookup::nameserver, QDnsLookup::nameserverPort |
446 | */ |
447 | void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port) |
448 | { |
449 | Qt::beginPropertyUpdateGroup(); |
450 | setNameserver(nameserver); |
451 | setNameserverPort(port); |
452 | Qt::endPropertyUpdateGroup(); |
453 | } |
454 | |
455 | /*! |
456 | Returns the list of canonical name records associated with this lookup. |
457 | */ |
458 | |
459 | QList<QDnsDomainNameRecord> QDnsLookup::canonicalNameRecords() const |
460 | { |
461 | return d_func()->reply.canonicalNameRecords; |
462 | } |
463 | |
464 | /*! |
465 | Returns the list of host address records associated with this lookup. |
466 | */ |
467 | |
468 | QList<QDnsHostAddressRecord> QDnsLookup::hostAddressRecords() const |
469 | { |
470 | return d_func()->reply.hostAddressRecords; |
471 | } |
472 | |
473 | /*! |
474 | Returns the list of mail exchange records associated with this lookup. |
475 | |
476 | The records are sorted according to |
477 | \l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them |
478 | to connect to servers, you should try them in the order they are listed. |
479 | */ |
480 | |
481 | QList<QDnsMailExchangeRecord> QDnsLookup::mailExchangeRecords() const |
482 | { |
483 | return d_func()->reply.mailExchangeRecords; |
484 | } |
485 | |
486 | /*! |
487 | Returns the list of name server records associated with this lookup. |
488 | */ |
489 | |
490 | QList<QDnsDomainNameRecord> QDnsLookup::nameServerRecords() const |
491 | { |
492 | return d_func()->reply.nameServerRecords; |
493 | } |
494 | |
495 | /*! |
496 | Returns the list of pointer records associated with this lookup. |
497 | */ |
498 | |
499 | QList<QDnsDomainNameRecord> QDnsLookup::pointerRecords() const |
500 | { |
501 | return d_func()->reply.pointerRecords; |
502 | } |
503 | |
504 | /*! |
505 | Returns the list of service records associated with this lookup. |
506 | |
507 | The records are sorted according to |
508 | \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them |
509 | to connect to servers, you should try them in the order they are listed. |
510 | */ |
511 | |
512 | QList<QDnsServiceRecord> QDnsLookup::serviceRecords() const |
513 | { |
514 | return d_func()->reply.serviceRecords; |
515 | } |
516 | |
517 | /*! |
518 | Returns the list of text records associated with this lookup. |
519 | */ |
520 | |
521 | QList<QDnsTextRecord> QDnsLookup::textRecords() const |
522 | { |
523 | return d_func()->reply.textRecords; |
524 | } |
525 | |
526 | /*! |
527 | Aborts the DNS lookup operation. |
528 | |
529 | If the lookup is already finished, does nothing. |
530 | */ |
531 | |
532 | void QDnsLookup::abort() |
533 | { |
534 | Q_D(QDnsLookup); |
535 | if (d->runnable) { |
536 | d->runnable = nullptr; |
537 | d->reply = QDnsLookupReply(); |
538 | d->reply.error = QDnsLookup::OperationCancelledError; |
539 | d->reply.errorString = tr(s: "Operation cancelled" ); |
540 | d->isFinished = true; |
541 | emit finished(); |
542 | } |
543 | } |
544 | |
545 | /*! |
546 | Performs the DNS lookup. |
547 | |
548 | The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion. |
549 | */ |
550 | |
551 | void QDnsLookup::lookup() |
552 | { |
553 | Q_D(QDnsLookup); |
554 | d->isFinished = false; |
555 | d->reply = QDnsLookupReply(); |
556 | if (!QCoreApplication::instance()) { |
557 | // NOT qCWarning because this isn't a result of the lookup |
558 | qWarning(msg: "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(sender: d->runnable, signal: &QDnsLookupRunnable::finished, context: this, slot&: l, |
577 | type: Qt::BlockingQueuedConnection); |
578 | theDnsLookupThreadPool->start(runnable: d->runnable); |
579 | } |
580 | |
581 | /*! |
582 | \class QDnsDomainNameRecord |
583 | \brief The QDnsDomainNameRecord class stores information about a domain |
584 | name record. |
585 | |
586 | \inmodule QtNetwork |
587 | \ingroup network |
588 | \ingroup shared |
589 | |
590 | When performing a name server lookup, zero or more records will be returned. |
591 | Each record is represented by a QDnsDomainNameRecord instance. |
592 | |
593 | \sa QDnsLookup |
594 | */ |
595 | |
596 | /*! |
597 | Constructs an empty domain name record object. |
598 | */ |
599 | |
600 | QDnsDomainNameRecord::QDnsDomainNameRecord() |
601 | : d(new QDnsDomainNameRecordPrivate) |
602 | { |
603 | } |
604 | |
605 | /*! |
606 | Constructs a copy of \a other. |
607 | */ |
608 | |
609 | QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other) |
610 | : d(other.d) |
611 | { |
612 | } |
613 | |
614 | /*! |
615 | Destroys a domain name record. |
616 | */ |
617 | |
618 | QDnsDomainNameRecord::~QDnsDomainNameRecord() |
619 | { |
620 | } |
621 | |
622 | /*! |
623 | Returns the name for this record. |
624 | */ |
625 | |
626 | QString QDnsDomainNameRecord::name() const |
627 | { |
628 | return d->name; |
629 | } |
630 | |
631 | /*! |
632 | Returns the duration in seconds for which this record is valid. |
633 | */ |
634 | |
635 | quint32 QDnsDomainNameRecord::timeToLive() const |
636 | { |
637 | return d->timeToLive; |
638 | } |
639 | |
640 | /*! |
641 | Returns the value for this domain name record. |
642 | */ |
643 | |
644 | QString QDnsDomainNameRecord::value() const |
645 | { |
646 | return d->value; |
647 | } |
648 | |
649 | /*! |
650 | Assigns the data of the \a other object to this record object, |
651 | and returns a reference to it. |
652 | */ |
653 | |
654 | QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other) |
655 | { |
656 | d = other.d; |
657 | return *this; |
658 | } |
659 | /*! |
660 | \fn void QDnsDomainNameRecord::swap(QDnsDomainNameRecord &other) |
661 | |
662 | Swaps this domain-name record instance with \a other. This |
663 | function is very fast and never fails. |
664 | */ |
665 | |
666 | /*! |
667 | \class QDnsHostAddressRecord |
668 | \brief The QDnsHostAddressRecord class stores information about a host |
669 | address record. |
670 | |
671 | \inmodule QtNetwork |
672 | \ingroup network |
673 | \ingroup shared |
674 | |
675 | When performing an address lookup, zero or more records will be |
676 | returned. Each record is represented by a QDnsHostAddressRecord instance. |
677 | |
678 | \sa QDnsLookup |
679 | */ |
680 | |
681 | /*! |
682 | Constructs an empty host address record object. |
683 | */ |
684 | |
685 | QDnsHostAddressRecord::QDnsHostAddressRecord() |
686 | : d(new QDnsHostAddressRecordPrivate) |
687 | { |
688 | } |
689 | |
690 | /*! |
691 | Constructs a copy of \a other. |
692 | */ |
693 | |
694 | QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other) |
695 | : d(other.d) |
696 | { |
697 | } |
698 | |
699 | /*! |
700 | Destroys a host address record. |
701 | */ |
702 | |
703 | QDnsHostAddressRecord::~QDnsHostAddressRecord() |
704 | { |
705 | } |
706 | |
707 | /*! |
708 | Returns the name for this record. |
709 | */ |
710 | |
711 | QString QDnsHostAddressRecord::name() const |
712 | { |
713 | return d->name; |
714 | } |
715 | |
716 | /*! |
717 | Returns the duration in seconds for which this record is valid. |
718 | */ |
719 | |
720 | quint32 QDnsHostAddressRecord::timeToLive() const |
721 | { |
722 | return d->timeToLive; |
723 | } |
724 | |
725 | /*! |
726 | Returns the value for this host address record. |
727 | */ |
728 | |
729 | QHostAddress QDnsHostAddressRecord::value() const |
730 | { |
731 | return d->value; |
732 | } |
733 | |
734 | /*! |
735 | Assigns the data of the \a other object to this record object, |
736 | and returns a reference to it. |
737 | */ |
738 | |
739 | QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other) |
740 | { |
741 | d = other.d; |
742 | return *this; |
743 | } |
744 | /*! |
745 | \fn void QDnsHostAddressRecord::swap(QDnsHostAddressRecord &other) |
746 | |
747 | Swaps this host address record instance with \a other. This |
748 | function is very fast and never fails. |
749 | */ |
750 | |
751 | /*! |
752 | \class QDnsMailExchangeRecord |
753 | \brief The QDnsMailExchangeRecord class stores information about a DNS MX record. |
754 | |
755 | \inmodule QtNetwork |
756 | \ingroup network |
757 | \ingroup shared |
758 | |
759 | When performing a lookup on a service, zero or more records will be |
760 | returned. Each record is represented by a QDnsMailExchangeRecord instance. |
761 | |
762 | The meaning of the fields is defined in |
763 | \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}. |
764 | |
765 | \sa QDnsLookup |
766 | */ |
767 | |
768 | /*! |
769 | Constructs an empty mail exchange record object. |
770 | */ |
771 | |
772 | QDnsMailExchangeRecord::QDnsMailExchangeRecord() |
773 | : d(new QDnsMailExchangeRecordPrivate) |
774 | { |
775 | } |
776 | |
777 | /*! |
778 | Constructs a copy of \a other. |
779 | */ |
780 | |
781 | QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other) |
782 | : d(other.d) |
783 | { |
784 | } |
785 | |
786 | /*! |
787 | Destroys a mail exchange record. |
788 | */ |
789 | |
790 | QDnsMailExchangeRecord::~QDnsMailExchangeRecord() |
791 | { |
792 | } |
793 | |
794 | /*! |
795 | Returns the domain name of the mail exchange for this record. |
796 | */ |
797 | |
798 | QString QDnsMailExchangeRecord::exchange() const |
799 | { |
800 | return d->exchange; |
801 | } |
802 | |
803 | /*! |
804 | Returns the name for this record. |
805 | */ |
806 | |
807 | QString QDnsMailExchangeRecord::name() const |
808 | { |
809 | return d->name; |
810 | } |
811 | |
812 | /*! |
813 | Returns the preference for this record. |
814 | */ |
815 | |
816 | quint16 QDnsMailExchangeRecord::preference() const |
817 | { |
818 | return d->preference; |
819 | } |
820 | |
821 | /*! |
822 | Returns the duration in seconds for which this record is valid. |
823 | */ |
824 | |
825 | quint32 QDnsMailExchangeRecord::timeToLive() const |
826 | { |
827 | return d->timeToLive; |
828 | } |
829 | |
830 | /*! |
831 | Assigns the data of the \a other object to this record object, |
832 | and returns a reference to it. |
833 | */ |
834 | |
835 | QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other) |
836 | { |
837 | d = other.d; |
838 | return *this; |
839 | } |
840 | /*! |
841 | \fn void QDnsMailExchangeRecord::swap(QDnsMailExchangeRecord &other) |
842 | |
843 | Swaps this mail exchange record with \a other. This function is |
844 | very fast and never fails. |
845 | */ |
846 | |
847 | /*! |
848 | \class QDnsServiceRecord |
849 | \brief The QDnsServiceRecord class stores information about a DNS SRV record. |
850 | |
851 | \inmodule QtNetwork |
852 | \ingroup network |
853 | \ingroup shared |
854 | |
855 | When performing a lookup on a service, zero or more records will be |
856 | returned. Each record is represented by a QDnsServiceRecord instance. |
857 | |
858 | The meaning of the fields is defined in |
859 | \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}. |
860 | |
861 | \sa QDnsLookup |
862 | */ |
863 | |
864 | /*! |
865 | Constructs an empty service record object. |
866 | */ |
867 | |
868 | QDnsServiceRecord::QDnsServiceRecord() |
869 | : d(new QDnsServiceRecordPrivate) |
870 | { |
871 | } |
872 | |
873 | /*! |
874 | Constructs a copy of \a other. |
875 | */ |
876 | |
877 | QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other) |
878 | : d(other.d) |
879 | { |
880 | } |
881 | |
882 | /*! |
883 | Destroys a service record. |
884 | */ |
885 | |
886 | QDnsServiceRecord::~QDnsServiceRecord() |
887 | { |
888 | } |
889 | |
890 | /*! |
891 | Returns the name for this record. |
892 | */ |
893 | |
894 | QString QDnsServiceRecord::name() const |
895 | { |
896 | return d->name; |
897 | } |
898 | |
899 | /*! |
900 | Returns the port on the target host for this service record. |
901 | */ |
902 | |
903 | quint16 QDnsServiceRecord::port() const |
904 | { |
905 | return d->port; |
906 | } |
907 | |
908 | /*! |
909 | Returns the priority for this service record. |
910 | |
911 | A client must attempt to contact the target host with the lowest-numbered |
912 | priority. |
913 | */ |
914 | |
915 | quint16 QDnsServiceRecord::priority() const |
916 | { |
917 | return d->priority; |
918 | } |
919 | |
920 | /*! |
921 | Returns the domain name of the target host for this service record. |
922 | */ |
923 | |
924 | QString QDnsServiceRecord::target() const |
925 | { |
926 | return d->target; |
927 | } |
928 | |
929 | /*! |
930 | Returns the duration in seconds for which this record is valid. |
931 | */ |
932 | |
933 | quint32 QDnsServiceRecord::timeToLive() const |
934 | { |
935 | return d->timeToLive; |
936 | } |
937 | |
938 | /*! |
939 | Returns the weight for this service record. |
940 | |
941 | The weight field specifies a relative weight for entries with the same |
942 | priority. Entries with higher weights should be selected with a higher |
943 | probability. |
944 | */ |
945 | |
946 | quint16 QDnsServiceRecord::weight() const |
947 | { |
948 | return d->weight; |
949 | } |
950 | |
951 | /*! |
952 | Assigns the data of the \a other object to this record object, |
953 | and returns a reference to it. |
954 | */ |
955 | |
956 | QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other) |
957 | { |
958 | d = other.d; |
959 | return *this; |
960 | } |
961 | /*! |
962 | \fn void QDnsServiceRecord::swap(QDnsServiceRecord &other) |
963 | |
964 | Swaps this service record instance with \a other. This function is |
965 | very fast and never fails. |
966 | */ |
967 | |
968 | /*! |
969 | \class QDnsTextRecord |
970 | \brief The QDnsTextRecord class stores information about a DNS TXT record. |
971 | |
972 | \inmodule QtNetwork |
973 | \ingroup network |
974 | \ingroup shared |
975 | |
976 | When performing a text lookup, zero or more records will be |
977 | returned. Each record is represented by a QDnsTextRecord instance. |
978 | |
979 | The meaning of the fields is defined in |
980 | \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}. |
981 | |
982 | \sa QDnsLookup |
983 | */ |
984 | |
985 | /*! |
986 | Constructs an empty text record object. |
987 | */ |
988 | |
989 | QDnsTextRecord::QDnsTextRecord() |
990 | : d(new QDnsTextRecordPrivate) |
991 | { |
992 | } |
993 | |
994 | /*! |
995 | Constructs a copy of \a other. |
996 | */ |
997 | |
998 | QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other) |
999 | : d(other.d) |
1000 | { |
1001 | } |
1002 | |
1003 | /*! |
1004 | Destroys a text record. |
1005 | */ |
1006 | |
1007 | QDnsTextRecord::~QDnsTextRecord() |
1008 | { |
1009 | } |
1010 | |
1011 | /*! |
1012 | Returns the name for this text record. |
1013 | */ |
1014 | |
1015 | QString QDnsTextRecord::name() const |
1016 | { |
1017 | return d->name; |
1018 | } |
1019 | |
1020 | /*! |
1021 | Returns the duration in seconds for which this record is valid. |
1022 | */ |
1023 | |
1024 | quint32 QDnsTextRecord::timeToLive() const |
1025 | { |
1026 | return d->timeToLive; |
1027 | } |
1028 | |
1029 | /*! |
1030 | Returns the values for this text record. |
1031 | */ |
1032 | |
1033 | QList<QByteArray> QDnsTextRecord::values() const |
1034 | { |
1035 | return d->values; |
1036 | } |
1037 | |
1038 | /*! |
1039 | Assigns the data of the \a other object to this record object, |
1040 | and returns a reference to it. |
1041 | */ |
1042 | |
1043 | QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other) |
1044 | { |
1045 | d = other.d; |
1046 | return *this; |
1047 | } |
1048 | /*! |
1049 | \fn void QDnsTextRecord::swap(QDnsTextRecord &other) |
1050 | |
1051 | Swaps this text record instance with \a other. This function is |
1052 | very fast and never fails. |
1053 | */ |
1054 | |
1055 | static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label) |
1056 | { |
1057 | QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.'; |
1058 | if (label.isEmpty()) |
1059 | return QDnsLookupRunnable::EncodedLabel(1, rootDomain); |
1060 | |
1061 | QString encodedLabel = qt_ACE_do(domain: label, op: ToAceOnly, dot: ForbidLeadingDot); |
1062 | #ifdef Q_OS_WIN |
1063 | return encodedLabel; |
1064 | #else |
1065 | return std::move(encodedLabel).toLatin1(); |
1066 | #endif |
1067 | } |
1068 | |
1069 | inline QDnsLookupRunnable::QDnsLookupRunnable(const QDnsLookupPrivate *d) |
1070 | : requestName(encodeLabel(label: d->name)), |
1071 | nameserver(d->nameserver), |
1072 | requestType(d->type), |
1073 | port(d->port) |
1074 | { |
1075 | } |
1076 | |
1077 | void QDnsLookupRunnable::run() |
1078 | { |
1079 | QDnsLookupReply reply; |
1080 | |
1081 | // Validate input. |
1082 | if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) { |
1083 | reply.error = QDnsLookup::InvalidRequestError; |
1084 | reply.errorString = QDnsLookup::tr(s: "Invalid domain name" ); |
1085 | } else { |
1086 | // Perform request. |
1087 | query(reply: &reply); |
1088 | |
1089 | // Sort results. |
1090 | qt_qdnsmailexchangerecord_sort(records&: reply.mailExchangeRecords); |
1091 | qt_qdnsservicerecord_sort(records&: reply.serviceRecords); |
1092 | } |
1093 | |
1094 | emit finished(reply); |
1095 | |
1096 | // maybe print the lookup error as warning |
1097 | switch (reply.error) { |
1098 | case QDnsLookup::NoError: |
1099 | case QDnsLookup::OperationCancelledError: |
1100 | case QDnsLookup::NotFoundError: |
1101 | case QDnsLookup::ServerFailureError: |
1102 | case QDnsLookup::ServerRefusedError: |
1103 | case QDnsLookup::TimeoutError: |
1104 | break; // no warning for these |
1105 | |
1106 | case QDnsLookup::ResolverError: |
1107 | case QDnsLookup::InvalidRequestError: |
1108 | case QDnsLookup::InvalidReplyError: |
1109 | qCWarning(lcDnsLookup()).nospace() |
1110 | << "DNS lookup failed (" << reply.error << "): " |
1111 | << qUtf16Printable(reply.errorString) |
1112 | << "; request was " << this; // continues below |
1113 | } |
1114 | } |
1115 | |
1116 | inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r) |
1117 | { |
1118 | // continued: print the information about the request |
1119 | d << r->requestName.left(len: 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 | |
1129 | QT_END_NAMESPACE |
1130 | |
1131 | #include "moc_qdnslookup.cpp" |
1132 | #include "moc_qdnslookup_p.cpp" |
1133 | |