QDnsLookup: add initial support for DNS-over-TLS (DoT)
This is just an empty shell for now. The implementation will come in the next commit. [ChangeLog][QtNetwork][QDnsLookup] The class now supports DNS-over-TLS and some other DNSSEC experimental features, on some platforms. Use QDnsLookup::isProtocolSupported to know if the protocol is supported on a given platform. Change-Id: I455fe22ef4ad4b2f9b01fffd17c7e034dee75533 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>bb10
parent
fd6cfd2283
commit
9724b039ca
|
|
@ -149,6 +149,11 @@
|
|||
\title RFC 7252
|
||||
*/
|
||||
|
||||
/*!
|
||||
\externalpage https://datatracker.ietf.org/doc/html/rfc7858
|
||||
\title RFC 7858
|
||||
*/
|
||||
|
||||
/*!
|
||||
\externalpage https://datatracker.ietf.org/doc/html/rfc8018#section-5.1
|
||||
\title RFC 8018, section 5.1
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieStrin
|
|||
|
||||
#if QT_NETWORK_REMOVED_SINCE(6, 8)
|
||||
|
||||
#if QT_CONFIG(dnslookup)
|
||||
# include "qdnslookup.h" // inlined API
|
||||
#endif
|
||||
#include "qnetworkrequest.h" // inlined API
|
||||
|
||||
// #include "qotherheader.h"
|
||||
|
|
|
|||
|
|
@ -159,6 +159,21 @@ static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
|
|||
\note If you simply want to find the IP address(es) associated with a host
|
||||
name, or the host name associated with an IP address you should use
|
||||
QHostInfo instead.
|
||||
|
||||
\section1 DNS-over-TLS
|
||||
|
||||
QDnsLookup supports DNS-over-TLS (DoT, as specified by \l{RFC 7858}) on
|
||||
some platforms. That currently includes all Unix platforms where regular
|
||||
queries are supported, if \l QSslSocket support is present in Qt. To query
|
||||
if support is present at runtime, use isProtocolSupported().
|
||||
|
||||
When using DNS-over-TLS, QDnsLookup only implements the "Opportunistic
|
||||
Privacy Profile" method of authentication, as described in \l{RFC 7858}
|
||||
section 4.1. In this mode, QDnsLookup (through \l QSslSocket) only
|
||||
validates that the server presents a certificate that is valid for the
|
||||
server being connected to. Clients may use setSslConfiguration() to impose
|
||||
additional restrictions and sslConfiguration() to obtain information after
|
||||
the query is complete.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
@ -216,6 +231,62 @@ static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
|
|||
\value TXT text records.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QDnsLookup::Protocol
|
||||
|
||||
Indicates the type of DNS server that is being queried.
|
||||
|
||||
\value Standard
|
||||
Regular, unencrypted DNS, using UDP and falling back to TCP as necessary
|
||||
(default port: 53)
|
||||
|
||||
\value DnsOverTls
|
||||
Encrypted DNS over TLS (DoT, as specified by \l{RFC 7858}), over TCP
|
||||
(default port: 853)
|
||||
|
||||
\sa isProtocolSupported(), nameserverProtocol, setNameserver()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.8
|
||||
|
||||
Returns true if DNS queries using \a protocol are supported with QDnsLookup.
|
||||
|
||||
\sa nameserverProtocol
|
||||
*/
|
||||
bool QDnsLookup::isProtocolSupported(Protocol protocol)
|
||||
{
|
||||
#if QT_CONFIG(libresolv) || defined(Q_OS_WIN)
|
||||
switch (protocol) {
|
||||
case QDnsLookup::Standard:
|
||||
return true;
|
||||
case QDnsLookup::DnsOverTls:
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(protocol)
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.8
|
||||
|
||||
Returns the standard (default) port number for the protocol \a protocol.
|
||||
|
||||
\sa isProtocolSupported()
|
||||
*/
|
||||
quint16 QDnsLookup::defaultPortForProtocol(Protocol protocol) noexcept
|
||||
{
|
||||
switch (protocol) {
|
||||
case QDnsLookup::Standard:
|
||||
return DnsPort;
|
||||
case QDnsLookup::DnsOverTls:
|
||||
return DnsOverTlsPort;
|
||||
}
|
||||
return 0; // will probably fail somewhere
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn void QDnsLookup::finished()
|
||||
|
||||
|
|
@ -270,7 +341,7 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
|
|||
*/
|
||||
|
||||
QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
|
||||
: QDnsLookup(type, name, nameserver, DnsPort, parent)
|
||||
: QDnsLookup(type, name, nameserver, 0, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -285,8 +356,9 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &names
|
|||
//! [nameserver-port]
|
||||
\note Setting the port number to any value other than the default (53) can
|
||||
cause the name resolution to fail, depending on the operating system
|
||||
limitations and firewalls. Notably, the Windows API used by QDnsLookup is
|
||||
unable to handle alternate port numbers.
|
||||
limitations and firewalls, if the nameserverProtocol() to be used
|
||||
QDnsLookup::Standard. Notably, the Windows API used by QDnsLookup is unable
|
||||
to handle alternate port numbers.
|
||||
//! [nameserver-port]
|
||||
*/
|
||||
QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
|
||||
|
|
@ -299,6 +371,30 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &names
|
|||
d->nameserver = nameserver;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.8
|
||||
|
||||
Constructs a QDnsLookup object to issue a query for \a name of record type
|
||||
\a type, using the DNS server \a nameserver running on port \a port, and
|
||||
sets \a parent as the parent object.
|
||||
|
||||
The query will be sent using \a protocol, if supported. Use
|
||||
isProtocolSupported() to check if it is supported.
|
||||
|
||||
\include qdnslookup.cpp nameserver-port
|
||||
*/
|
||||
QDnsLookup::QDnsLookup(Type type, const QString &name, Protocol protocol,
|
||||
const QHostAddress &nameserver, quint16 port, QObject *parent)
|
||||
: QObject(*new QDnsLookupPrivate, parent)
|
||||
{
|
||||
Q_D(QDnsLookup);
|
||||
d->name = name;
|
||||
d->type = type;
|
||||
d->nameserver = nameserver;
|
||||
d->port = port;
|
||||
d->protocol = protocol;
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys the QDnsLookup object.
|
||||
|
||||
|
|
@ -416,6 +512,10 @@ QBindable<QHostAddress> QDnsLookup::bindableNameserver()
|
|||
\property QDnsLookup::nameserverPort
|
||||
\since 6.6
|
||||
\brief the port number of nameserver to use for DNS lookup.
|
||||
|
||||
The value of 0 indicates that QDnsLookup should use the default port for
|
||||
the nameserverProtocol().
|
||||
|
||||
\include qdnslookup.cpp nameserver-port
|
||||
*/
|
||||
|
||||
|
|
@ -437,18 +537,44 @@ QBindable<quint16> QDnsLookup::bindableNameserverPort()
|
|||
}
|
||||
|
||||
/*!
|
||||
\property QDnsLookup::nameserverProtocol
|
||||
\since 6.8
|
||||
\brief the protocol to use when sending the DNS query
|
||||
|
||||
\sa isProtocolSupported()
|
||||
*/
|
||||
QDnsLookup::Protocol QDnsLookup::nameserverProtocol() const
|
||||
{
|
||||
return d_func()->protocol;
|
||||
}
|
||||
|
||||
void QDnsLookup::setNameserverProtocol(Protocol protocol)
|
||||
{
|
||||
d_func()->protocol = protocol;
|
||||
}
|
||||
|
||||
QBindable<QDnsLookup::Protocol> QDnsLookup::bindableNameserverProtocol()
|
||||
{
|
||||
return &d_func()->protocol;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
|
||||
\since 6.6
|
||||
|
||||
Sets the nameserver to \a nameserver and the port to \a port.
|
||||
|
||||
\include qdnslookup.cpp nameserver-port
|
||||
|
||||
\sa QDnsLookup::nameserver, QDnsLookup::nameserverPort
|
||||
*/
|
||||
void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
|
||||
|
||||
void QDnsLookup::setNameserver(Protocol protocol, const QHostAddress &nameserver, quint16 port)
|
||||
{
|
||||
Qt::beginPropertyUpdateGroup();
|
||||
setNameserver(nameserver);
|
||||
setNameserverPort(port);
|
||||
setNameserverProtocol(protocol);
|
||||
Qt::endPropertyUpdateGroup();
|
||||
}
|
||||
|
||||
|
|
@ -523,6 +649,29 @@ QList<QDnsTextRecord> QDnsLookup::textRecords() const
|
|||
return d_func()->reply.textRecords;
|
||||
}
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
/*!
|
||||
\since 6.8
|
||||
Sets the \a sslConfiguration to use for outgoing DNS-over-TLS connections.
|
||||
|
||||
\sa sslConfiguration(), QSslSocket::setSslConfiguration()
|
||||
*/
|
||||
void QDnsLookup::setSslConfiguration(const QSslConfiguration &sslConfiguration)
|
||||
{
|
||||
Q_UNUSED(sslConfiguration)
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the current SSL configuration.
|
||||
|
||||
\sa setSslConfiguration()
|
||||
*/
|
||||
QSslConfiguration QDnsLookup::sslConfiguration() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Aborts the DNS lookup operation.
|
||||
|
||||
|
|
@ -564,6 +713,9 @@ void QDnsLookup::lookup()
|
|||
if (d->runnable == sender()) {
|
||||
#ifdef QDNSLOOKUP_DEBUG
|
||||
qDebug("DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString));
|
||||
#endif
|
||||
#if QT_CONFIG(ssl)
|
||||
d->sslConfiguration = std::move(reply.sslConfiguration);
|
||||
#endif
|
||||
d->reply = reply;
|
||||
d->runnable = nullptr;
|
||||
|
|
@ -1070,8 +1222,14 @@ inline QDnsLookupRunnable::QDnsLookupRunnable(const QDnsLookupPrivate *d)
|
|||
: requestName(encodeLabel(d->name)),
|
||||
nameserver(d->nameserver),
|
||||
requestType(d->type),
|
||||
port(d->port)
|
||||
port(d->port),
|
||||
protocol(d->protocol)
|
||||
{
|
||||
if (port == 0)
|
||||
port = QDnsLookup::defaultPortForProtocol(protocol);
|
||||
#if QT_CONFIG(ssl)
|
||||
sslConfiguration = d->sslConfiguration;
|
||||
#endif
|
||||
}
|
||||
|
||||
void QDnsLookupRunnable::run()
|
||||
|
|
@ -1120,9 +1278,16 @@ inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
|
|||
if (r->requestName.size() > MaxDomainNameLength)
|
||||
d << "... (truncated)";
|
||||
d << " type " << r->requestType;
|
||||
if (!r->nameserver.isNull())
|
||||
if (!r->nameserver.isNull()) {
|
||||
d << " to nameserver " << qUtf16Printable(r->nameserver.toString())
|
||||
<< " port " << (r->port ? r->port : DnsPort);
|
||||
<< " port " << (r->port ? r->port : QDnsLookup::defaultPortForProtocol(r->protocol));
|
||||
switch (r->protocol) {
|
||||
case QDnsLookup::Standard:
|
||||
break;
|
||||
case QDnsLookup::DnsOverTls:
|
||||
d << " (TLS)";
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class QDnsHostAddressRecordPrivate;
|
|||
class QDnsMailExchangeRecordPrivate;
|
||||
class QDnsServiceRecordPrivate;
|
||||
class QDnsTextRecordPrivate;
|
||||
class QSslConfiguration;
|
||||
|
||||
class Q_NETWORK_EXPORT QDnsDomainNameRecord
|
||||
{
|
||||
|
|
@ -148,6 +149,8 @@ class Q_NETWORK_EXPORT QDnsLookup : public QObject
|
|||
BINDABLE bindableNameserver)
|
||||
Q_PROPERTY(quint16 nameserverPort READ nameserverPort WRITE setNameserverPort
|
||||
NOTIFY nameserverPortChanged BINDABLE bindableNameserverPort)
|
||||
Q_PROPERTY(Protocol nameserverProtocol READ nameserverProtocol WRITE setNameserverProtocol
|
||||
NOTIFY nameserverProtocolChanged BINDABLE bindableNameserverProtocol)
|
||||
|
||||
public:
|
||||
enum Error
|
||||
|
|
@ -178,11 +181,19 @@ public:
|
|||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
enum Protocol : quint8 {
|
||||
Standard = 0,
|
||||
DnsOverTls,
|
||||
};
|
||||
Q_ENUM(Protocol)
|
||||
|
||||
explicit QDnsLookup(QObject *parent = nullptr);
|
||||
QDnsLookup(Type type, const QString &name, QObject *parent = nullptr);
|
||||
QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent = nullptr);
|
||||
QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port,
|
||||
QObject *parent = nullptr);
|
||||
QDnsLookup(Type type, const QString &name, Protocol protocol, const QHostAddress &nameserver,
|
||||
quint16 port = 0, QObject *parent = nullptr);
|
||||
~QDnsLookup();
|
||||
|
||||
Error error() const;
|
||||
|
|
@ -203,6 +214,11 @@ public:
|
|||
quint16 nameserverPort() const;
|
||||
void setNameserverPort(quint16 port);
|
||||
QBindable<quint16> bindableNameserverPort();
|
||||
Protocol nameserverProtocol() const;
|
||||
void setNameserverProtocol(Protocol protocol);
|
||||
QBindable<Protocol> bindableNameserverProtocol();
|
||||
void setNameserver(Protocol protocol, const QHostAddress &nameserver, quint16 port = 0);
|
||||
QT_NETWORK_INLINE_SINCE(6, 8)
|
||||
void setNameserver(const QHostAddress &nameserver, quint16 port);
|
||||
|
||||
QList<QDnsDomainNameRecord> canonicalNameRecords() const;
|
||||
|
|
@ -214,6 +230,14 @@ public:
|
|||
QList<QDnsTextRecord> textRecords() const;
|
||||
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
void setSslConfiguration(const QSslConfiguration &sslConfiguration);
|
||||
QSslConfiguration sslConfiguration() const;
|
||||
#endif
|
||||
|
||||
static bool isProtocolSupported(Protocol protocol);
|
||||
static quint16 defaultPortForProtocol(Protocol protocol) noexcept Q_DECL_CONST_FUNCTION;
|
||||
|
||||
public Q_SLOTS:
|
||||
void abort();
|
||||
void lookup();
|
||||
|
|
@ -224,11 +248,19 @@ Q_SIGNALS:
|
|||
void typeChanged(Type type);
|
||||
void nameserverChanged(const QHostAddress &nameserver);
|
||||
void nameserverPortChanged(quint16 port);
|
||||
void nameserverProtocolChanged(Protocol protocol);
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE(QDnsLookup)
|
||||
};
|
||||
|
||||
#if QT_NETWORK_INLINE_IMPL_SINCE(6, 8)
|
||||
void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
|
||||
{
|
||||
setNameserver(Standard, nameserver, port);
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QDNSLOOKUP_H
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
#include "private/qobject_p.h"
|
||||
#include "private/qurl_p.h"
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
# include "qsslconfiguration.h"
|
||||
#endif
|
||||
|
||||
QT_REQUIRE_CONFIG(dnslookup);
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
@ -35,6 +39,7 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
constexpr qsizetype MaxDomainNameLength = 255;
|
||||
constexpr quint16 DnsPort = 53;
|
||||
constexpr quint16 DnsOverTlsPort = 853;
|
||||
|
||||
class QDnsLookupRunnable;
|
||||
QDebug operator<<(QDebug &, QDnsLookupRunnable *);
|
||||
|
|
@ -53,6 +58,10 @@ public:
|
|||
QList<QDnsServiceRecord> serviceRecords;
|
||||
QList<QDnsTextRecord> textRecords;
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
std::optional<QSslConfiguration> sslConfiguration;
|
||||
#endif
|
||||
|
||||
// helper methods
|
||||
void setError(QDnsLookup::Error err, QString &&msg)
|
||||
{
|
||||
|
|
@ -129,7 +138,8 @@ class QDnsLookupPrivate : public QObjectPrivate
|
|||
public:
|
||||
QDnsLookupPrivate()
|
||||
: type(QDnsLookup::A)
|
||||
, port(DnsPort)
|
||||
, port(0)
|
||||
, protocol(QDnsLookup::Standard)
|
||||
{ }
|
||||
|
||||
void nameChanged()
|
||||
|
|
@ -162,11 +172,22 @@ public:
|
|||
Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, quint16,
|
||||
port, &QDnsLookupPrivate::nameserverPortChanged);
|
||||
|
||||
void nameserverProtocolChanged()
|
||||
{
|
||||
emit q_func()->nameserverProtocolChanged(protocol);
|
||||
}
|
||||
|
||||
Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QDnsLookup::Protocol,
|
||||
protocol, &QDnsLookupPrivate::nameserverProtocolChanged);
|
||||
|
||||
QDnsLookupReply reply;
|
||||
QDnsLookupRunnable *runnable = nullptr;
|
||||
bool isFinished = false;
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
std::optional<QSslConfiguration> sslConfiguration;
|
||||
#endif
|
||||
|
||||
Q_DECLARE_PUBLIC(QDnsLookup)
|
||||
};
|
||||
|
||||
|
|
@ -198,6 +219,11 @@ private:
|
|||
QHostAddress nameserver;
|
||||
QDnsLookup::Type requestType;
|
||||
quint16 port;
|
||||
QDnsLookup::Protocol protocol;
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
std::optional<QSslConfiguration> sslConfiguration;
|
||||
#endif
|
||||
friend QDebug operator<<(QDebug &, QDnsLookupRunnable *);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@ prepareQueryBuffer(res_state state, QueryBuffer &buffer, const char *label, ns_r
|
|||
|
||||
void QDnsLookupRunnable::query(QDnsLookupReply *reply)
|
||||
{
|
||||
if (protocol != QDnsLookup::Standard)
|
||||
return reply->setError(QDnsLookup::ResolverError,
|
||||
QDnsLookup::tr("DNS over TLS not implemented"));
|
||||
|
||||
// Initialize state.
|
||||
std::remove_pointer_t<res_state> state = {};
|
||||
if (res_ninit(&state) < 0) {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
|
|||
request.QueryType = requestType;
|
||||
request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN;
|
||||
|
||||
if (!nameserver.isNull()) {
|
||||
if (protocol == QDnsLookup::Standard && !nameserver.isNull()) {
|
||||
memset(dnsAddresses, 0, sizeof(dnsAddresses));
|
||||
request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY;
|
||||
auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1];
|
||||
|
|
@ -87,7 +87,16 @@ void QDnsLookupRunnable::query(QDnsLookupReply *reply)
|
|||
|
||||
DNS_QUERY_RESULT results = {};
|
||||
results.Version = 1;
|
||||
const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr);
|
||||
DNS_STATUS status = ERROR_INVALID_PARAMETER;
|
||||
switch (protocol) {
|
||||
case QDnsLookup::Standard:
|
||||
status = DnsQueryEx(&request, &results, nullptr);
|
||||
break;
|
||||
case QDnsLookup::DnsOverTls:
|
||||
return reply->setError(QDnsLookup::ResolverError,
|
||||
QDnsLookup::tr("DNS over TLS not implemented"));
|
||||
}
|
||||
|
||||
if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST)
|
||||
return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1);
|
||||
else if (status == ERROR_TIMEOUT)
|
||||
|
|
|
|||
|
|
@ -37,8 +37,11 @@ class tst_QDnsLookup: public QObject
|
|||
QStringList domainNameListAlternatives(const QString &input);
|
||||
|
||||
std::unique_ptr<QDnsLookup> lookupCommon(QDnsLookup::Type type, const QString &domain,
|
||||
const QHostAddress &server = {}, quint16 port = 53);
|
||||
const QHostAddress &server = {}, quint16 port = 0,
|
||||
QDnsLookup::Protocol protocol = QDnsLookup::Standard);
|
||||
QStringList formatReply(const QDnsLookup *lookup) const;
|
||||
|
||||
void setNameserver_helper(QDnsLookup::Protocol protocol);
|
||||
public slots:
|
||||
void initTestCase();
|
||||
|
||||
|
|
@ -57,6 +60,8 @@ private slots:
|
|||
void setNameserverLoopback();
|
||||
void setNameserver_data();
|
||||
void setNameserver();
|
||||
void dnsOverTls_data();
|
||||
void dnsOverTls();
|
||||
void bindingsAndProperties();
|
||||
void automatedBindings();
|
||||
};
|
||||
|
|
@ -74,9 +79,11 @@ static const char preparedDnsQuery[] =
|
|||
"\x00\x00\x06\x00\x01" // <root domain> IN SOA
|
||||
;
|
||||
|
||||
static QList<QHostAddress> systemNameservers()
|
||||
static QList<QHostAddress> systemNameservers(QDnsLookup::Protocol protocol)
|
||||
{
|
||||
QList<QHostAddress> result;
|
||||
if (protocol != QDnsLookup::Standard)
|
||||
return result;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
ULONG infosize = 0;
|
||||
|
|
@ -113,7 +120,7 @@ static QList<QHostAddress> systemNameservers()
|
|||
return result;
|
||||
}
|
||||
|
||||
static QList<QHostAddress> globalPublicNameservers()
|
||||
static QList<QHostAddress> globalPublicNameservers(QDnsLookup::Protocol proto)
|
||||
{
|
||||
const char *const candidates[] = {
|
||||
// Google's dns.google
|
||||
|
|
@ -129,6 +136,8 @@ static QList<QHostAddress> globalPublicNameservers()
|
|||
};
|
||||
|
||||
QList<QHostAddress> result;
|
||||
if (proto != QDnsLookup::Standard)
|
||||
return result;
|
||||
QRandomGenerator &rng = *QRandomGenerator::system();
|
||||
for (auto name : candidates) {
|
||||
// check the candidates for reachability
|
||||
|
|
@ -221,9 +230,10 @@ QStringList tst_QDnsLookup::domainNameListAlternatives(const QString &input)
|
|||
|
||||
std::unique_ptr<QDnsLookup>
|
||||
tst_QDnsLookup::lookupCommon(QDnsLookup::Type type, const QString &domain,
|
||||
const QHostAddress &server, quint16 port)
|
||||
const QHostAddress &server, quint16 port,
|
||||
QDnsLookup::Protocol protocol)
|
||||
{
|
||||
auto lookup = std::make_unique<QDnsLookup>(type, domainName(domain), server, port);
|
||||
auto lookup = std::make_unique<QDnsLookup>(type, domainName(domain), protocol, server, port);
|
||||
QObject::connect(lookup.get(), &QDnsLookup::finished,
|
||||
&QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
|
||||
lookup->lookup();
|
||||
|
|
@ -591,24 +601,34 @@ void tst_QDnsLookup::setNameserverLoopback()
|
|||
QCOMPARE(lookup.error(), QDnsLookup::NotFoundError);
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::setNameserver_data()
|
||||
template <QDnsLookup::Protocol Protocol>
|
||||
static void setNameserver_data_helper(const QByteArray &protoName)
|
||||
{
|
||||
static QList<QHostAddress> servers = systemNameservers() + globalPublicNameservers();
|
||||
if (!QDnsLookup::isProtocolSupported(Protocol))
|
||||
QSKIP(protoName + " not supported");
|
||||
|
||||
static QList<QHostAddress> servers = systemNameservers(Protocol)
|
||||
+ globalPublicNameservers(Protocol);
|
||||
QTest::addColumn<QHostAddress>("server");
|
||||
|
||||
if (servers.isEmpty()) {
|
||||
QSKIP("No reachable DNS servers were found");
|
||||
QSKIP("No reachable " + protoName + " servers were found");
|
||||
} else {
|
||||
for (const QHostAddress &h : std::as_const(servers))
|
||||
QTest::addRow("%s", qUtf8Printable(h.toString())) << h;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::setNameserver()
|
||||
void tst_QDnsLookup::setNameserver_data()
|
||||
{
|
||||
setNameserver_data_helper<QDnsLookup::Standard>("DNS");
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::setNameserver_helper(QDnsLookup::Protocol protocol)
|
||||
{
|
||||
QFETCH(QHostAddress, server);
|
||||
std::unique_ptr<QDnsLookup> lookup =
|
||||
lookupCommon(QDnsLookup::Type::A, "a-single", server);
|
||||
lookupCommon(QDnsLookup::Type::A, "a-single", server, 0, protocol);
|
||||
if (!lookup)
|
||||
return;
|
||||
QCOMPARE(lookup->error(), QDnsLookup::NoError);
|
||||
|
|
@ -616,6 +636,21 @@ void tst_QDnsLookup::setNameserver()
|
|||
QCOMPARE(result, "A 192.0.2.1");
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::setNameserver()
|
||||
{
|
||||
setNameserver_helper(QDnsLookup::Standard);
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::dnsOverTls_data()
|
||||
{
|
||||
setNameserver_data_helper<QDnsLookup::DnsOverTls>("DNS-over-TLS");
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::dnsOverTls()
|
||||
{
|
||||
setNameserver_helper(QDnsLookup::DnsOverTls);
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::bindingsAndProperties()
|
||||
{
|
||||
QDnsLookup lookup;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@
|
|||
#include <QtNetwork/QHostInfo>
|
||||
#include <QtNetwork/QDnsLookup>
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
# include <QtNetwork/QSslCipher>
|
||||
# include <QtNetwork/QSslConfiguration>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
|
@ -32,6 +37,12 @@ static QDnsLookup::Type typeFromString(QString str)
|
|||
return QDnsLookup::Type(value);
|
||||
}
|
||||
|
||||
template <typename Enum> [[maybe_unused]] static const char *enumToKey(Enum e)
|
||||
{
|
||||
QMetaEnum me = QMetaEnum::fromType<Enum>();
|
||||
return me.valueToKey(int(e));
|
||||
}
|
||||
|
||||
static int showHelp(const char *argv0, int exitcode)
|
||||
{
|
||||
// like dig
|
||||
|
|
@ -43,7 +54,7 @@ static auto parseServerAddress(QString server)
|
|||
{
|
||||
struct R {
|
||||
QHostAddress address;
|
||||
int port = -1;
|
||||
int port;
|
||||
} r;
|
||||
|
||||
// let's use QUrl to help us
|
||||
|
|
@ -52,7 +63,7 @@ static auto parseServerAddress(QString server)
|
|||
if (!url.isValid() || !url.userInfo().isNull())
|
||||
return r; // failed
|
||||
|
||||
r.port = url.port();
|
||||
r.port = url.port(0);
|
||||
r.address.setAddress(url.host());
|
||||
if (r.address.isNull()) {
|
||||
// try to resolve a hostname
|
||||
|
|
@ -121,8 +132,21 @@ static void printResults(const QDnsLookup &lookup, QElapsedTimer::Duration durat
|
|||
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#%d\n", qPrintable(server.toString()), lookup.nameserverPort());
|
||||
if (QHostAddress server = lookup.nameserver(); !server.isNull()) {
|
||||
quint16 port = lookup.nameserverPort();
|
||||
if (port == 0)
|
||||
port = QDnsLookup::defaultPortForProtocol(lookup.nameserverProtocol());
|
||||
printf(";; SERVER: %s#%d", qPrintable(server.toString()), port);
|
||||
#if QT_CONFIG(ssl)
|
||||
if (lookup.nameserverProtocol() != QDnsLookup::Standard) {
|
||||
if (QSslConfiguration conf = lookup.sslConfiguration(); !conf.isNull()) {
|
||||
printf(" (%s %s)", enumToKey(conf.sessionProtocol()),
|
||||
qPrintable(conf.sessionCipher().name()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
puts("");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
|
@ -130,6 +154,7 @@ int main(int argc, char *argv[])
|
|||
QCoreApplication a(argc, argv);
|
||||
|
||||
QDnsLookup::Type type = {};
|
||||
QDnsLookup::Protocol protocol = QDnsLookup::Standard;
|
||||
QString domain, server;
|
||||
const QStringList args = QCoreApplication::arguments().sliced(1);
|
||||
for (const QString &arg : args) {
|
||||
|
|
@ -139,6 +164,14 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
if (arg == u"-h")
|
||||
return showHelp(argv[0], EXIT_SUCCESS);
|
||||
if (arg == "+tls") {
|
||||
protocol = QDnsLookup::DnsOverTls;
|
||||
continue;
|
||||
} else if (arg == "+notls") {
|
||||
protocol = QDnsLookup::Standard;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (domain.isNull()) {
|
||||
domain = arg;
|
||||
continue;
|
||||
|
|
@ -170,9 +203,7 @@ int main(int argc, char *argv[])
|
|||
argv[0], qPrintable(server));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
lookup.setNameserver(addr.address);
|
||||
if (addr.port > 0)
|
||||
lookup.setNameserverPort(addr.port);
|
||||
lookup.setNameserver(protocol, addr.address, addr.port);
|
||||
}
|
||||
|
||||
// execute the lookup
|
||||
|
|
|
|||
Loading…
Reference in New Issue