QBearerEngine *QNativeWifiEnginePlugin::create(const QString &key) const { if (key != QLatin1String("nativewifi")) return 0; resolveLibrary(); // native wifi dll not available if (!local_WlanOpenHandle) return 0; QNativeWifiEngine *engine = new QNativeWifiEngine; // could not initialise subsystem if (engine && !engine->available()) { delete engine; return 0; } return engine; }
QString QHostInfo::localDomainName() { #if !defined(Q_OS_VXWORKS) resolveLibrary(); if (local_res_ninit) { // using thread-safe version res_state_ptr state = res_state_ptr(qMalloc(sizeof(*state))); Q_CHECK_PTR(state); memset(state, 0, sizeof(*state)); local_res_ninit(state); QString domainName = QUrl::fromAce(state->defdname); if (domainName.isEmpty()) domainName = QUrl::fromAce(state->dnsrch[0]); local_res_nclose(state); qFree(state); return domainName; } if (local_res_init && local_res) { // using thread-unsafe version #if defined(QT_NO_GETADDRINFO) // We have to call res_init to be sure that _res was initialized // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too QMutexLocker locker(::getHostByNameMutex()); #endif local_res_init(); QString domainName = QUrl::fromAce(local_res->defdname); if (domainName.isEmpty()) domainName = QUrl::fromAce(local_res->dnsrch[0]); return domainName; } #endif // nothing worked, try doing it by ourselves: QFile resolvconf; #if defined(_PATH_RESCONF) resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF)); #else resolvconf.setFileName(QLatin1String("/etc/resolv.conf")); #endif if (!resolvconf.open(QIODevice::ReadOnly)) return QString(); // failure QString domainName; while (!resolvconf.atEnd()) { QByteArray line = resolvconf.readLine().trimmed(); if (line.startsWith("domain ")) return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed()); // in case there's no "domain" line, fall back to the first "search" entry if (domainName.isEmpty() && line.startsWith("search ")) { QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed(); int pos = searchDomain.indexOf(' '); if (pos != -1) searchDomain.truncate(pos); domainName = QUrl::fromAce(searchDomain); } } // return the fallen-back-to searched domain return domainName; }
QHostInfo QHostInfoAgent::fromName(const QString &hostName) { QHostInfo results; #if defined(QHOSTINFO_DEBUG) qDebug("QHostInfoAgent::fromName(%s) looking up...", hostName.toLatin1().constData()); #endif // Load res_init on demand. static volatile bool triedResolve = false; if (!triedResolve) { QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_init)); if (!triedResolve) { resolveLibrary(); triedResolve = true; } } // If res_init is available, poll it. if (local_res_init) local_res_init(); QHostAddress address; if (address.setAddress(hostName)) { // Reverse lookup // Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead. #if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) sockaddr_in sa4; #ifndef QT_NO_IPV6 sockaddr_in6 sa6; #endif sockaddr *sa = 0; QT_SOCKLEN_T saSize = 0; if (address.protocol() == QAbstractSocket::IPv4Protocol) { sa = (sockaddr *)&sa4; saSize = sizeof(sa4); memset(&sa4, 0, sizeof(sa4)); sa4.sin_family = AF_INET; sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); } #ifndef QT_NO_IPV6 else { sa = (sockaddr *)&sa6; saSize = sizeof(sa6); memset(&sa6, 0, sizeof(sa6)); sa6.sin6_family = AF_INET6; memcpy(sa6.sin6_addr.s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.s6_addr)); } #endif char hbuf[NI_MAXHOST]; if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) results.setHostName(QString::fromLatin1(hbuf)); #else in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData()); struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET); if (ent) results.setHostName(QString::fromLatin1(ent->h_name)); #endif if (results.hostName().isEmpty()) results.setHostName(address.toString()); results.setAddresses(QList<QHostAddress>() << address); return results; } // IDN support QByteArray aceHostname = QUrl::toAce(hostName); results.setHostName(hostName); if (aceHostname.isEmpty()) { results.setError(QHostInfo::HostNotFound); results.setErrorString(hostName.isEmpty() ? QCoreApplication::translate("QHostInfoAgent", "No host name given") : QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); return results; } #if !defined (QT_NO_GETADDRINFO) // Call getaddrinfo, and place all IPv4 addresses at the start and // the IPv6 addresses at the end of the address list in results. addrinfo *res = 0; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; #ifdef Q_ADDRCONFIG hints.ai_flags = Q_ADDRCONFIG; #endif int result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); # ifdef Q_ADDRCONFIG if (result == EAI_BADFLAGS) { // if the lookup failed with AI_ADDRCONFIG set, try again without it hints.ai_flags = 0; result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); } # endif if (result == 0) { addrinfo *node = res; QList<QHostAddress> addresses; while (node) { #ifdef QHOSTINFO_DEBUG qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol << "ai_addrlen:" << node->ai_addrlen; #endif if (node->ai_family == AF_INET) { QHostAddress addr; addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr)); if (!addresses.contains(addr)) addresses.append(addr); } #ifndef QT_NO_IPV6 else if (node->ai_family == AF_INET6) { QHostAddress addr; sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; addr.setAddress(sa6->sin6_addr.s6_addr); if (sa6->sin6_scope_id) addr.setScopeId(QString::number(sa6->sin6_scope_id)); if (!addresses.contains(addr)) addresses.append(addr); } #endif node = node->ai_next; } if (addresses.isEmpty() && node == 0) { // Reached the end of the list, but no addresses were found; this // means the list contains one or more unknown address types. results.setError(QHostInfo::UnknownError); results.setErrorString(tr("Unknown address type")); } results.setAddresses(addresses); freeaddrinfo(res); } else if (result == EAI_NONAME || result == EAI_FAIL #ifdef EAI_NODATA // EAI_NODATA is deprecated in RFC 3493 || result == EAI_NODATA #endif ) { results.setError(QHostInfo::HostNotFound); results.setErrorString(tr("Host not found")); } else { results.setError(QHostInfo::UnknownError); results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); } #else // Fall back to gethostbyname for platforms that don't define // getaddrinfo. gethostbyname does not support IPv6, and it's not // reentrant on all platforms. For now this is okay since we only // use one QHostInfoAgent, but if more agents are introduced, locking // must be provided. QMutexLocker locker(::getHostByNameMutex()); hostent *result = gethostbyname(aceHostname.constData()); if (result) { if (result->h_addrtype == AF_INET) { QList<QHostAddress> addresses; for (char **p = result->h_addr_list; *p != 0; p++) { QHostAddress addr; addr.setAddress(ntohl(*((quint32 *)*p))); if (!addresses.contains(addr)) addresses.prepend(addr); } results.setAddresses(addresses); } else { results.setError(QHostInfo::UnknownError); results.setErrorString(tr("Unknown address type")); } #if !defined(Q_OS_VXWORKS) } else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA || h_errno == NO_ADDRESS) { results.setError(QHostInfo::HostNotFound); results.setErrorString(tr("Host not found")); #endif } else { results.setError(QHostInfo::UnknownError); results.setErrorString(tr("Unknown error")); } #endif // !defined (QT_NO_GETADDRINFO) #if defined(QHOSTINFO_DEBUG) if (results.error() != QHostInfo::NoError) { qDebug("QHostInfoAgent::fromName(): error #%d %s", h_errno, results.errorString().toLatin1().constData()); } else { QString tmp; QList<QHostAddress> addresses = results.addresses(); for (int i = 0; i < addresses.count(); ++i) { if (i != 0) tmp += ", "; tmp += addresses.at(i).toString(); } qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}", addresses.count(), hostName.toLatin1().constData(), tmp.toLatin1().constData()); } #endif return results; }
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); if (!triedResolve.loadAcquire()) { QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_ninit)); if (!triedResolve.load()) { resolveLibrary(); triedResolve.storeRelease(true); } } // If dn_expand, res_ninit or res_nquery is missing, fail. if (!local_dn_expand || !local_res_nclose || !local_res_ninit || !local_res_nquery) { reply->error = QDnsLookup::ResolverError; reply->errorString = tr("Resolver functions not found"); return; } // Initialize state. struct __res_state state; memset(&state, 0, sizeof(state)); if (local_res_ninit(&state) < 0) { reply->error = QDnsLookup::ResolverError; 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 QScopedPointer<struct __res_state, QDnsLookupStateDeleter> state_ptr(&state); // Perform DNS query. unsigned char response[PACKETSZ]; memset(response, 0, sizeof(response)); const int responseLength = local_res_nquery(&state, requestName, C_IN, requestType, response, sizeof(response)); // Check the response header. HEADER *header = (HEADER*)response; const int answerCount = ntohs(header->ancount); switch (header->rcode) { case NOERROR: break; case FORMERR: reply->error = QDnsLookup::InvalidRequestError; reply->errorString = tr("Server could not process query"); return; case SERVFAIL: reply->error = QDnsLookup::ServerFailureError; reply->errorString = tr("Server failure"); return; case NXDOMAIN: reply->error = QDnsLookup::NotFoundError; reply->errorString = tr("Non existent domain"); return; case REFUSED: reply->error = QDnsLookup::ServerRefusedError; reply->errorString = tr("Server refused to answer"); return; default: reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid reply received"); return; } // Check the reply is valid. if (responseLength < int(sizeof(HEADER))) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid reply received"); return; } // Skip the query host, type (2 bytes) and class (2 bytes). char host[PACKETSZ], answer[PACKETSZ]; unsigned char *p = response + sizeof(HEADER); int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); if (status < 0) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Could not expand domain name"); return; } p += status + 4; // Extract results. int answerIndex = 0; while ((p < response + responseLength) && (answerIndex < answerCount)) { status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); if (status < 0) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Could not expand domain name"); return; } const QString name = QUrl::fromAce(host); p += status; const quint16 type = (p[0] << 8) | p[1]; p += 2; // RR type p += 2; // RR class const quint32 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; p += 4; const quint16 size = (p[0] << 8) | p[1]; p += 2; if (type == QDnsLookup::A) { if (size != 4) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid IPv4 address record"); return; } const quint32 addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; QDnsHostAddressRecord record; record.d->name = name; record.d->timeToLive = ttl; record.d->value = QHostAddress(addr); reply->hostAddressRecords.append(record); } else if (type == QDnsLookup::AAAA) { if (size != 16) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid IPv6 address record"); return; } QDnsHostAddressRecord record; record.d->name = name; record.d->timeToLive = ttl; record.d->value = QHostAddress(p); reply->hostAddressRecords.append(record); } else if (type == QDnsLookup::CNAME) { status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); if (status < 0) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid canonical name record"); return; } QDnsDomainNameRecord record; record.d->name = name; record.d->timeToLive = ttl; record.d->value = QUrl::fromAce(answer); reply->canonicalNameRecords.append(record); } else if (type == QDnsLookup::NS) { status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); if (status < 0) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid name server record"); return; } QDnsDomainNameRecord record; record.d->name = name; record.d->timeToLive = ttl; record.d->value = QUrl::fromAce(answer); reply->nameServerRecords.append(record); } else if (type == QDnsLookup::PTR) { status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); if (status < 0) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid pointer record"); return; } QDnsDomainNameRecord record; record.d->name = name; record.d->timeToLive = ttl; record.d->value = QUrl::fromAce(answer); reply->pointerRecords.append(record); } else if (type == QDnsLookup::MX) { const quint16 preference = (p[0] << 8) | p[1]; status = local_dn_expand(response, response + responseLength, p + 2, answer, sizeof(answer)); if (status < 0) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid mail exchange record"); return; } QDnsMailExchangeRecord record; record.d->exchange = QUrl::fromAce(answer); record.d->name = name; record.d->preference = preference; record.d->timeToLive = ttl; reply->mailExchangeRecords.append(record); } else if (type == QDnsLookup::SRV) { const quint16 priority = (p[0] << 8) | p[1]; const quint16 weight = (p[2] << 8) | p[3]; const quint16 port = (p[4] << 8) | p[5]; status = local_dn_expand(response, response + responseLength, p + 6, answer, sizeof(answer)); if (status < 0) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid service record"); return; } QDnsServiceRecord record; record.d->name = name; record.d->target = QUrl::fromAce(answer); record.d->port = port; record.d->priority = priority; record.d->timeToLive = ttl; record.d->weight = weight; reply->serviceRecords.append(record); } else if (type == QDnsLookup::TXT) { unsigned char *txt = p; QDnsTextRecord record; record.d->name = name; record.d->timeToLive = ttl; while (txt < p + size) { const unsigned char length = *txt; txt++; if (txt + length > p + size) { reply->error = QDnsLookup::InvalidReplyError; reply->errorString = tr("Invalid text record"); return; } record.d->values << QByteArray((char*)txt, length); txt += length; } reply->textRecords.append(record); } p += size; answerIndex++; } }