9#include <qapplicationstatic.h>
10#include <qcoreapplication.h>
13#include <qloggingcategory.h>
19# include <qsslsocket.h>
26using namespace Qt::StringLiterals;
31struct QDnsLookupThreadPool : QThreadPool
33 QDnsLookupThreadPool()
46 return r1.preference() < r2.preference();
50
51
56 if (records.size() <= 1)
60 std::sort(records.begin(), records.end(), qt_qdnsmailexchangerecord_less_than);
63 while (i < records.size()) {
66 QList<QDnsMailExchangeRecord> slice;
67 const quint16 slicePreference = records.at(i).preference();
68 for (
int j = i; j < records.size(); ++j) {
69 if (records.at(j).preference() != slicePreference)
71 slice << records.at(j);
75 while (!slice.isEmpty()) {
76 const unsigned int pos = QRandomGenerator::global()->bounded(slice.size());
77 records[i++] = slice.takeAt(pos);
86 return r1.priority() < r2.priority()
87 || (r1.priority() == r2.priority()
88 && r1.weight() == 0 && r2.weight() > 0);
92
93
98 if (records.size() <= 1)
103 std::sort(records.begin(), records.end(), qt_qdnsservicerecord_less_than);
106 while (i < records.size()) {
109 QList<QDnsServiceRecord> slice;
110 const quint16 slicePriority = records.at(i).priority();
111 unsigned int sliceWeight = 0;
112 for (
int j = i; j < records.size(); ++j) {
113 if (records.at(j).priority() != slicePriority)
115 sliceWeight += records.at(j).weight();
116 slice << records.at(j);
118#ifdef QDNSLOOKUP_DEBUG
119 qDebug(
"qt_qdnsservicerecord_sort() : priority %i (size: %i, total weight: %i)",
120 slicePriority, slice.size(), sliceWeight);
124 while (!slice.isEmpty()) {
125 const unsigned int weightThreshold = QRandomGenerator::global()->bounded(sliceWeight + 1);
126 unsigned int summedWeight = 0;
127 for (
int j = 0; j < slice.size(); ++j) {
128 summedWeight += slice.at(j).weight();
129 if (summedWeight >= weightThreshold) {
130#ifdef QDNSLOOKUP_DEBUG
131 qDebug(
"qt_qdnsservicerecord_sort() : adding %s %i (weight: %i)",
132 qPrintable(slice.at(j).target()), slice.at(j).port(),
133 slice.at(j).weight());
136 sliceWeight -= slice.at(j).weight();
137 records[i++] = slice.takeAt(j);
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
236
237
238
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
267
268
269
270
271
272
273
274
275
276
277
278
279
280
283
284
285
286
287
288
289bool QDnsLookup::isProtocolSupported(Protocol protocol)
291#if QT_CONFIG(libresolv) || defined(Q_OS_WIN)
293 case QDnsLookup::Standard:
295 case QDnsLookup::DnsOverTls:
297 if (QSslSocket::supportsSsl())
309
310
311
312
313
314
315quint16 QDnsLookup::defaultPortForProtocol(Protocol protocol)
noexcept
318 case QDnsLookup::Standard:
320 case QDnsLookup::DnsOverTls:
321 return DnsOverTlsPort;
327
328
329
330
333
334
335
336
337
340
341
342
343
344
347
348
349
350
352QDnsLookup::QDnsLookup(QObject *parent)
353 : QObject(*
new QDnsLookupPrivate, parent)
358
359
360
362QDnsLookup::QDnsLookup(Type type,
const QString &name, QObject *parent)
363 : QObject(*
new QDnsLookupPrivate, parent)
371
372
373
374
375
376
377
379QDnsLookup::QDnsLookup(Type type,
const QString &name,
const QHostAddress &nameserver, QObject *parent)
380 : QDnsLookup(type, name, nameserver, 0, parent)
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400QDnsLookup::QDnsLookup(Type type,
const QString &name,
const QHostAddress &nameserver, quint16 port, QObject *parent)
401 : QObject(*
new QDnsLookupPrivate, parent)
407 d->nameserver = nameserver;
411
412
413
414
415
416
417
418
419
420
421
422QDnsLookup::QDnsLookup(Type type,
const QString &name, Protocol protocol,
423 const QHostAddress &nameserver, quint16 port, QObject *parent)
424 : QObject(*
new QDnsLookupPrivate, parent)
429 d->nameserver = nameserver;
431 d->protocol = protocol;
435
436
437
438
439
441QDnsLookup::~QDnsLookup()
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462bool QDnsLookup::isAuthenticData()
const
464 return d_func()->reply.authenticData;
468
469
470
472QDnsLookup::Error QDnsLookup::error()
const
474 return d_func()->reply.error;
478
479
480
482QString QDnsLookup::errorString()
const
484 return d_func()->reply.errorString;
488
489
491bool QDnsLookup::isFinished()
const
493 return d_func()->isFinished;
497
498
499
500
501
502
503
504
505
506
508QString QDnsLookup::name()
const
510 return d_func()->name;
513void QDnsLookup::setName(
const QString &name)
519QBindable<QString> QDnsLookup::bindableName()
526
527
528
530QDnsLookup::Type QDnsLookup::type()
const
532 return d_func()->type;
535void QDnsLookup::setType(Type type)
541QBindable<QDnsLookup::Type> QDnsLookup::bindableType()
548
549
550
552QHostAddress QDnsLookup::nameserver()
const
554 return d_func()->nameserver;
557void QDnsLookup::setNameserver(
const QHostAddress &nameserver)
560 d->nameserver = nameserver;
563QBindable<QHostAddress> QDnsLookup::bindableNameserver()
566 return &d->nameserver;
570
571
572
573
574
575
576
577
578
580quint16 QDnsLookup::nameserverPort()
const
582 return d_func()->port;
585void QDnsLookup::setNameserverPort(quint16 nameserverPort)
588 d->port = nameserverPort;
591QBindable<quint16> QDnsLookup::bindableNameserverPort()
598
599
600
601
602
603
604QDnsLookup::Protocol QDnsLookup::nameserverProtocol()
const
606 return d_func()->protocol;
609void QDnsLookup::setNameserverProtocol(Protocol protocol)
611 d_func()->protocol = protocol;
614QBindable<QDnsLookup::Protocol> QDnsLookup::bindableNameserverProtocol()
616 return &d_func()->protocol;
620
621
622
623
624
625
626
627
628
630void QDnsLookup::setNameserver(Protocol protocol,
const QHostAddress &nameserver, quint16 port)
632 Qt::beginPropertyUpdateGroup();
633 setNameserver(nameserver);
634 setNameserverPort(port);
635 setNameserverProtocol(protocol);
636 Qt::endPropertyUpdateGroup();
640
641
643QList<QDnsDomainNameRecord> QDnsLookup::canonicalNameRecords()
const
645 return d_func()->reply.canonicalNameRecords;
649
650
652QList<QDnsHostAddressRecord> QDnsLookup::hostAddressRecords()
const
654 return d_func()->reply.hostAddressRecords;
658
659
660
661
662
663
665QList<QDnsMailExchangeRecord> QDnsLookup::mailExchangeRecords()
const
667 return d_func()->reply.mailExchangeRecords;
671
672
674QList<QDnsDomainNameRecord> QDnsLookup::nameServerRecords()
const
676 return d_func()->reply.nameServerRecords;
680
681
683QList<QDnsDomainNameRecord> QDnsLookup::pointerRecords()
const
685 return d_func()->reply.pointerRecords;
689
690
691
692
693
694
696QList<QDnsServiceRecord> QDnsLookup::serviceRecords()
const
698 return d_func()->reply.serviceRecords;
702
703
705QList<QDnsTextRecord> QDnsLookup::textRecords()
const
707 return d_func()->reply.textRecords;
711
712
713
714
715
716
717
718
719
720QList<QDnsTlsAssociationRecord> QDnsLookup::tlsAssociationRecords()
const
722 return d_func()->reply.tlsAssociationRecords;
727
728
729
730
731
732void QDnsLookup::setSslConfiguration(
const QSslConfiguration &sslConfiguration)
735 d->sslConfiguration.emplace(sslConfiguration);
739
740
741
742
743QSslConfiguration QDnsLookup::sslConfiguration()
const
745 const Q_D(QDnsLookup);
746 return d->sslConfiguration.value_or(QSslConfiguration::defaultConfiguration());
751
752
753
754
756void QDnsLookup::abort()
760 d->runnable =
nullptr;
761 d->reply = QDnsLookupReply();
762 d->reply.error = QDnsLookup::OperationCancelledError;
763 d->reply.errorString = tr(
"Operation cancelled");
764 d->isFinished =
true;
770
771
772
773
775void QDnsLookup::lookup()
778 d->isFinished =
false;
779 d->reply = QDnsLookupReply();
780 if (!QCoreApplication::instanceExists()) {
782 qWarning(
"QDnsLookup requires a QCoreApplication");
786 auto l = [
this](
const QDnsLookupReply &reply) {
788 if (d->runnable == sender()) {
789#ifdef QDNSLOOKUP_DEBUG
790 qDebug(
"DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString));
793 d->sslConfiguration = std::move(reply.sslConfiguration);
796 d->runnable =
nullptr;
797 d->isFinished =
true;
802 d->runnable =
new QDnsLookupRunnable(d);
803 connect(d->runnable, &QDnsLookupRunnable::finished,
this, l,
804 Qt::BlockingQueuedConnection);
805 theDnsLookupThreadPool->start(d->runnable);
809
810
811
812
813
814
815
816
817
818
819
820
821
824
825
827QDnsDomainNameRecord::QDnsDomainNameRecord()
828 : d(
new QDnsDomainNameRecordPrivate)
833
834
836QDnsDomainNameRecord::QDnsDomainNameRecord(
const QDnsDomainNameRecord &other)
842
843
845QDnsDomainNameRecord::~QDnsDomainNameRecord()
850
851
853QString QDnsDomainNameRecord::name()
const
859
860
862quint32 QDnsDomainNameRecord::timeToLive()
const
864 return d->timeToLive;
868
869
871QString QDnsDomainNameRecord::value()
const
877
878
879
881QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(
const QDnsDomainNameRecord &other)
888
889
890
893
894
895
896
897
898
899
900
901
902
903
904
905
908
909
911QDnsHostAddressRecord::QDnsHostAddressRecord()
912 : d(
new QDnsHostAddressRecordPrivate)
917
918
920QDnsHostAddressRecord::QDnsHostAddressRecord(
const QDnsHostAddressRecord &other)
926
927
929QDnsHostAddressRecord::~QDnsHostAddressRecord()
934
935
937QString QDnsHostAddressRecord::name()
const
943
944
946quint32 QDnsHostAddressRecord::timeToLive()
const
948 return d->timeToLive;
952
953
955QHostAddress QDnsHostAddressRecord::value()
const
961
962
963
965QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(
const QDnsHostAddressRecord &other)
972
973
974
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
994
995
997QDnsMailExchangeRecord::QDnsMailExchangeRecord()
998 : d(
new QDnsMailExchangeRecordPrivate)
1003
1004
1006QDnsMailExchangeRecord::QDnsMailExchangeRecord(
const QDnsMailExchangeRecord &other)
1012
1013
1015QDnsMailExchangeRecord::~QDnsMailExchangeRecord()
1020
1021
1023QString QDnsMailExchangeRecord::exchange()
const
1029
1030
1032QString QDnsMailExchangeRecord::name()
const
1038
1039
1041quint16 QDnsMailExchangeRecord::preference()
const
1043 return d->preference;
1047
1048
1050quint32 QDnsMailExchangeRecord::timeToLive()
const
1052 return d->timeToLive;
1056
1057
1058
1060QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(
const QDnsMailExchangeRecord &other)
1066
1067
1068
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1088
1089
1091QDnsServiceRecord::QDnsServiceRecord()
1092 : d(
new QDnsServiceRecordPrivate)
1097
1098
1100QDnsServiceRecord::QDnsServiceRecord(
const QDnsServiceRecord &other)
1106
1107
1109QDnsServiceRecord::~QDnsServiceRecord()
1114
1115
1117QString QDnsServiceRecord::name()
const
1123
1124
1126quint16 QDnsServiceRecord::port()
const
1132
1133
1134
1135
1136
1138quint16 QDnsServiceRecord::priority()
const
1144
1145
1147QString QDnsServiceRecord::target()
const
1153
1154
1156quint32 QDnsServiceRecord::timeToLive()
const
1158 return d->timeToLive;
1162
1163
1164
1165
1166
1167
1169quint16 QDnsServiceRecord::weight()
const
1175
1176
1177
1179QDnsServiceRecord &QDnsServiceRecord::operator=(
const QDnsServiceRecord &other)
1185
1186
1187
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1207
1208
1210QDnsTextRecord::QDnsTextRecord()
1211 : d(
new QDnsTextRecordPrivate)
1216
1217
1219QDnsTextRecord::QDnsTextRecord(
const QDnsTextRecord &other)
1225
1226
1228QDnsTextRecord::~QDnsTextRecord()
1233
1234
1236QString QDnsTextRecord::name()
const
1242
1243
1245quint32 QDnsTextRecord::timeToLive()
const
1247 return d->timeToLive;
1251
1252
1254QList<QByteArray> QDnsTextRecord::values()
const
1260
1261
1262
1264QDnsTextRecord &QDnsTextRecord::operator=(
const QDnsTextRecord &other)
1270
1271
1272
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1291QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDnsTlsAssociationRecordPrivate)
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1415
1416
1417QDnsTlsAssociationRecord::QDnsTlsAssociationRecord()
1418 : d(
new QDnsTlsAssociationRecordPrivate)
1423
1424
1428
1429
1434
1435
1439
1440
1447
1448
1451 return d->timeToLive;
1455
1456
1463
1464
1471
1472
1475 return d->matchType;
1479
1480
1481
1482
1483
1484
1485
1493 QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.';
1494 if (label.isEmpty())
1495 return QDnsLookupRunnable::EncodedLabel(1, rootDomain);
1497 QString encodedLabel = qt_ACE_do(label, ToAceOnly, ForbidLeadingDot);
1499 return encodedLabel;
1501 return std::move(encodedLabel).toLatin1();
1513 port = QDnsLookup::defaultPortForProtocol(protocol);
1515 sslConfiguration = d->sslConfiguration;
1524 if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) {
1525 reply.error = QDnsLookup::InvalidRequestError;
1526 reply.errorString = QDnsLookup::tr(
"Invalid domain name");
1532 qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
1533 qt_qdnsservicerecord_sort(reply.serviceRecords);
1536 emit finished(reply);
1539 switch (reply.error) {
1540 case QDnsLookup::NoError:
1541 case QDnsLookup::OperationCancelledError:
1542 case QDnsLookup::NotFoundError:
1543 case QDnsLookup::ServerFailureError:
1544 case QDnsLookup::ServerRefusedError:
1545 case QDnsLookup::TimeoutError:
1548 case QDnsLookup::ResolverError:
1549 case QDnsLookup::InvalidRequestError:
1550 case QDnsLookup::InvalidReplyError:
1552 <<
"DNS lookup failed (" << reply.error <<
"): "
1553 << qUtf16Printable(reply.errorString)
1554 <<
"; request was " <<
this;
1561 d << r->requestName.left(MaxDomainNameLength);
1562 if (r->requestName.size() > MaxDomainNameLength)
1563 d <<
"... (truncated)";
1564 d <<
" type " << r->requestType;
1565 if (!r->nameserver.isNull()) {
1566 d <<
" to nameserver " << qUtf16Printable(r->nameserver.toString())
1567 <<
" port " << (r->port ? r->port : QDnsLookup::defaultPortForProtocol(r->protocol));
1568 switch (r->protocol) {
1569 case QDnsLookup::Standard:
1571 case QDnsLookup::DnsOverTls:
1579static constexpr std::chrono::milliseconds DnsOverTlsConnectTimeout(15'000);
1580static constexpr std::chrono::milliseconds DnsOverTlsTimeout(120'000);
1581static constexpr quint8 DnsAuthenticDataBit = 0x20;
1583static int makeReplyErrorFromSocket(QDnsLookupReply *reply,
const QAbstractSocket *socket)
1585 QDnsLookup::Error error = [&] {
1586 switch (socket->error()) {
1587 case QAbstractSocket::SocketTimeoutError:
1588 case QAbstractSocket::ProxyConnectionTimeoutError:
1589 return QDnsLookup::TimeoutError;
1591 return QDnsLookup::ResolverError;
1594 reply->setError(error, socket->errorString());
1598bool QDnsLookupRunnable::sendDnsOverTls(QDnsLookupReply *reply, QSpan<
unsigned char> query,
1599 ReplyBuffer &response)
1602 socket.setSslConfiguration(sslConfiguration.value_or(QSslConfiguration::defaultConfiguration()));
1604# if QT_CONFIG(networkproxy)
1605 socket.setProtocolTag(
"domain-s"_L1);
1609 query[3] |= DnsAuthenticDataBit;
1612 quint16 size = qToBigEndian<quint16>(query.size());
1613 QDeadlineTimer timeout(DnsOverTlsTimeout);
1615 socket.connectToHostEncrypted(nameserver.toString(), port);
1616 socket.write(
reinterpret_cast<
const char *>(&size),
sizeof(size));
1617 socket.write(
reinterpret_cast<
const char *>(query.data()), query.size());
1618 if (!socket.waitForEncrypted(DnsOverTlsConnectTimeout.count()))
1621 reply->sslConfiguration = socket.sslConfiguration();
1624 auto waitForBytes = [&](
void *buffer,
int count) {
1625 int remaining = timeout.remainingTime();
1626 while (remaining >= 0 && socket.bytesAvailable() < count) {
1627 if (!socket.waitForReadyRead(remaining))
1630 return socket.read(
static_cast<
char *>(buffer), count) == count;
1632 if (!waitForBytes(&size,
sizeof(size)))
1638 size = qFromBigEndian(size);
1639 response.resize(size);
1640 if (waitForBytes(response.data(), size)) {
1643 reply->authenticData = response[3] & DnsAuthenticDataBit;
1649 return makeReplyErrorFromSocket(reply, &socket);
1653 ReplyBuffer &response)
1657 reply->setError(QDnsLookup::ResolverError, QDnsLookup::tr(
"SSL/TLS support not present"));
1664#include "moc_qdnslookup.cpp"
1665#include "moc_qdnslookup_p.cpp"
QDnsLookupRunnable(const QDnsLookupPrivate *d)
void run() override
Implement this pure virtual function in your subclass.
bool sendDnsOverTls(QDnsLookupReply *reply, QSpan< unsigned char > query, ReplyBuffer &response)
The QDnsTlsAssociationRecord class stores information about a DNS TLSA record.
Q_NETWORK_EXPORT ~QDnsTlsAssociationRecord()
Destroys this TLS Association record object.
#define Q_APPLICATION_STATIC(TYPE, NAME,...)
static void qt_qdnsmailexchangerecord_sort(QList< QDnsMailExchangeRecord > &records)
static void qt_qdnsservicerecord_sort(QList< QDnsServiceRecord > &records)
static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2)
static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
#define qCWarning(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)