diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2023-05-08 18:52:00 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2023-05-14 21:44:19 -0700 |
commit | eb9f88a07812608c77d28777ba2e911431f59990 (patch) | |
tree | 2e3b8e8c99bf13e8ef49c4cd22c2a442b1f1b512 /tests/manual/qdnslookup/main.cpp | |
parent | df2131426ecc9711b5ac67a45fde7d760c8f2df2 (diff) |
QDnsLookup/Unix: modernize the setting of IPv6 server addresses
Instead of using #if, this now uses SFINAE to detect the presence of the
glibc extensions to set IPv6 nameserver addresses. It's also possible
that this fixes some bugs that have always been there, but never checked
because we don't have a way to unit-test explicit name servers.
To that effect, this commit adds a manual unit test that mimics the BIND
tool "dig". When running:
./qdnslookup qt-project.org any @dns.google
it printed for me:
; <<>> QDnsLookup 6.6.0
;; status: NoError
;; QUESTION:
;qt-project.org IN ANY
;; ANSWER:
qt-project.org 3600 IN MX 10 mx.qt-project.org
qt-project.org 3600 IN NS ns14.cloudns.net
qt-project.org 3600 IN NS ns11.cloudns.net
qt-project.org 3600 IN NS ns12.cloudns.net
qt-project.org 3600 IN NS ns13.cloudns.net
qt-project.org 3600 IN A 52.18.144.254
qt-project.org 3600 IN TXT "v=spf1 mx ip4:193.209.87.4 include:spf.protection.outlook.com ~all"
;; Query time: 241 ms
;; SERVER: 2001:4860:4860::8844#53
strace confirms the DNS queries were sent to the correct address.
Change-Id: I3e3bfef633af4130a03afffd175d56a92371ed16
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'tests/manual/qdnslookup/main.cpp')
-rw-r--r-- | tests/manual/qdnslookup/main.cpp | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/tests/manual/qdnslookup/main.cpp b/tests/manual/qdnslookup/main.cpp new file mode 100644 index 0000000000..3ddf84063e --- /dev/null +++ b/tests/manual/qdnslookup/main.cpp @@ -0,0 +1,165 @@ +// Copyright (C) 2023 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> +#include <QtCore/QElapsedTimer> +#include <QtCore/QMetaEnum> +#include <QtCore/QTimer> +#include <QtNetwork/QHostAddress> +#include <QtNetwork/QHostInfo> +#include <QtNetwork/QDnsLookup> + +#include <stdlib.h> +#include <stdio.h> + +#include <chrono> + +using namespace Qt::StringLiterals; +using namespace std::chrono; +using namespace std::chrono_literals; + +static QDnsLookup::Type typeFromString(QString str) +{ + // we can use the meta object + QMetaEnum me = QMetaEnum::fromType<QDnsLookup::Type>(); + + bool ok; + int value = me.keyToValue(str.toUpper().toLatin1(), &ok); + if (!ok) + return QDnsLookup::Type(0); + return QDnsLookup::Type(value); +} + +static int showHelp(const char *argv0, int exitcode) +{ + // like dig + printf("%s [@global-server] [domain] [query-type]\n", argv0); + return exitcode; +} + +static void printAnswers(const QDnsLookup &lookup) +{ + printf("\n;; ANSWER:\n"); + static auto printRecordCommon = [](const auto &rr, const char *rrtype) { + printf("%-23s %6d IN %s\t", qPrintable(rr.name()), rr.timeToLive(), rrtype); + }; + auto printNameRecords = [](const char *rrtype, const QList<QDnsDomainNameRecord> list) { + for (const QDnsDomainNameRecord &rr : list) { + printRecordCommon(rr, rrtype); + printf("%s\n", qPrintable(rr.value())); + } + }; + + for (const QDnsMailExchangeRecord &rr : lookup.mailExchangeRecords()) { + printRecordCommon(rr, "MX"); + printf("%d %s\n", rr.preference(), qPrintable(rr.exchange())); + } + for (const QDnsServiceRecord &rr : lookup.serviceRecords()) { + printRecordCommon(rr, "SRV"); + printf("%d %d %d %s\n", rr.priority(), rr.weight(), rr.port(), + qPrintable(rr.target())); + } + printNameRecords("NS", lookup.nameServerRecords()); + printNameRecords("PTR", lookup.pointerRecords()); + printNameRecords("CNAME", lookup.canonicalNameRecords()); + + for (const QDnsHostAddressRecord &rr : lookup.hostAddressRecords()) { + QHostAddress addr = rr.value(); + printRecordCommon(rr, addr.protocol() == QHostAddress::IPv6Protocol ? "AAAA" : "A"); + printf("%s\n", qPrintable(addr.toString())); + } + + for (const QDnsTextRecord &rr : lookup.textRecords()) { + printRecordCommon(rr, "TXT"); + for (const QByteArray &data : rr.values()) + printf("%s ", qPrintable(QDebug::toString(data))); + puts(""); + } +} + +static void printResults(const QDnsLookup &lookup, QElapsedTimer::Duration duration) +{ + if (QDnsLookup::Error error = lookup.error()) + printf(";; status: %s (%s)\n", QMetaEnum::fromType<QDnsLookup::Error>().valueToKey(error), + qPrintable(lookup.errorString())); + else + printf(";; status: NoError\n"); + + QMetaEnum me = QMetaEnum::fromType<QDnsLookup::Type>(); + printf(";; QUESTION:\n"); + printf(";%-30s IN %s\n", qPrintable(lookup.name()), + me.valueToKey(lookup.type())); + + if (lookup.error() == QDnsLookup::NoError) + printAnswers(lookup); + + printf("\n;; Query time: %lld ms\n", qint64(duration_cast<milliseconds>(duration).count())); + if (QHostAddress server = lookup.nameserver(); !server.isNull()) + printf(";; SERVER: %s#53\n", qPrintable(server.toString())); +} + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + QDnsLookup::Type type = {}; + QString domain, server; + const QStringList args = QCoreApplication::arguments().sliced(1); + for (const QString &arg : args) { + if (arg.startsWith(u'@')) { + server = arg.mid(1); + continue; + } + if (arg == u"-h") + return showHelp(argv[0], EXIT_SUCCESS); + if (domain.isNull()) { + domain = arg; + continue; + } + if (type != QDnsLookup::Type{}) + return showHelp(argv[0], EXIT_FAILURE); + + type = typeFromString(arg); + if (type == QDnsLookup::Type{}) { + fprintf(stderr, "%s: unknown DNS record type '%s'. Valid types are:\n", + argv[0], qPrintable(arg)); + QMetaEnum me = QMetaEnum::fromType<QDnsLookup::Type>(); + for (int i = 0; i < me.keyCount(); ++i) + fprintf(stderr, " %s\n", me.key(i)); + return EXIT_FAILURE; + } + } + + if (domain.isEmpty()) + domain = u"qt-project.org"_s; + if (type == QDnsLookup::Type{}) + type = QDnsLookup::A; + + QDnsLookup lookup(type, domain); + if (!server.isEmpty()) { + QHostAddress addr(server); + if (addr.isNull()) + addr = QHostInfo::fromName(server).addresses().value(0); + if (addr.isNull()) { + fprintf(stderr, "%s: could not parse name server address '%s'\n", + argv[0], qPrintable(server)); + return EXIT_FAILURE; + } + lookup.setNameserver(addr); + } + + // execute the lookup + QObject::connect(&lookup, &QDnsLookup::finished, qApp, &QCoreApplication::quit); + QTimer::singleShot(15s, []() { qApp->exit(EXIT_FAILURE); }); + + QElapsedTimer timer; + timer.start(); + lookup.lookup(); + if (a.exec() == EXIT_FAILURE) + return EXIT_FAILURE; + printf("; <<>> QDnsLookup " QT_VERSION_STR " <<>> %s %s\n", + qPrintable(QCoreApplication::applicationName()), qPrintable(args.join(u' '))); + printResults(lookup, timer.durationElapsed()); + return 0; +} |