From 62f01d581bdda6f67cd96af179ae1953e30fa218 Mon Sep 17 00:00:00 2001 From: Mandeep Sandhu Date: Fri, 27 Sep 2013 15:03:04 +0530 Subject: QDnsLookup: Add support for custom DNS server Implemented the use of the new QDnsLookup property "nameserver". On the Linux platform, we can specify both IPv4 and IPv6 addresses for the nameserver. On Windows since we are using DnsQuery_W(), which does not have a way of accepting IPv6 addresses, passing IPv6 nameserver address is not supported. On OSX/BSD platforms, specifying IPv6 addresses for nameserver require access to the __res_state_ext structure which is in a private header of libresolv (this header is different for BSDs and OSX). If this feature has to be enabled in the future, we have to figure out a way to access this struct by either accessing the private header or by specifying one of our own. Currently, I'm disabling it till such a solution is arrived at. Nameserver support on different platforms: Platform | IPv4 | IPv6 -------------+---------------+--------------- Linux/X11 | supported | supported -------------+---------------+--------------- Windows | supported | not supported -------------+---------------+--------------- OSX | supported | not supported -------------+---------------+--------------- WinRT | not supported | not supported -------------+---------------+--------------- Others | supported | not supported | (not tested) | -------------+---------------+--------------- Task-number: QTBUG-30166 Change-Id: Iedbddf15b9a62738ce4c2cfa0fce051514d64766 Reviewed-by: Thiago Macieira --- src/network/kernel/qdnslookup_unix.cpp | 39 +++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'src/network/kernel/qdnslookup_unix.cpp') diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp index 9fb488cee6..26834dff57 100644 --- a/src/network/kernel/qdnslookup_unix.cpp +++ b/src/network/kernel/qdnslookup_unix.cpp @@ -115,7 +115,7 @@ static void resolveLibrary() local_res_nquery = res_nquery_proto(lib.resolve("res_nquery")); } -void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) +void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply) { // Load dn_expand, res_ninit and res_nquery on demand. static QBasicAtomicInt triedResolve = Q_BASIC_ATOMIC_INITIALIZER(false); @@ -142,6 +142,43 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN reply->errorString = tr("Resolver initialization failed"); return; } + + //Check if a nameserver was set. If so, use it + if (!nameserver.isNull()) { + if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) { + state.nsaddr_list[0].sin_addr.s_addr = htonl(nameserver.toIPv4Address()); + state.nscount = 1; + } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) { +#if defined(Q_OS_LINUX) + struct sockaddr_in6 *ns; + ns = state._u._ext.nsaddrs[0]; + // nsaddrs will be NULL if no nameserver is set in /etc/resolv.conf + if (!ns) { + // Memory allocated here will be free'd in res_close() as we + // have done res_init() above. + ns = (struct sockaddr_in6*) calloc(1, sizeof(struct sockaddr_in6)); + Q_CHECK_PTR(ns); + state._u._ext.nsaddrs[0] = ns; + } + // Set nsmap[] to indicate that nsaddrs[0] is an IPv6 address + // See: https://sourceware.org/ml/libc-hacker/2002-05/msg00035.html + state._u._ext.nsmap[0] = MAXNS + 1; + state._u._ext.nscount6 = 1; + ns->sin6_family = AF_INET6; + ns->sin6_port = htons(53); + + Q_IPV6ADDR ipv6Address = nameserver.toIPv6Address(); + for (int i=0; i<16; i++) { + ns->sin6_addr.s6_addr[i] = ipv6Address[i]; + } +#else + qWarning() << Q_FUNC_INFO << "IPv6 addresses for nameservers is currently not supported"; + reply->error = QDnsLookup::ResolverError; + reply->errorString = tr("IPv6 addresses for nameservers is currently not supported"); + return; +#endif + } + } #ifdef QDNSLOOKUP_DEBUG state.options |= RES_DEBUG; #endif -- cgit v1.2.3