Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qhostinfo_unix.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:trusted-data
4
5//#define QHOSTINFO_DEBUG
6
7#include "qhostinfo_p.h"
8
9#include <qbytearray.h>
10#include <qfile.h>
11#include <qplatformdefs.h>
12#include <qurl.h>
13
14#include <sys/types.h>
15#include <netdb.h>
16#include <netinet/in.h>
17
18#if QT_CONFIG(libresolv)
19# include <resolv.h>
20#endif
21
22#ifndef _PATH_RESCONF
23# define _PATH_RESCONF "/etc/resolv.conf"
24#endif
25
26QT_BEGIN_NAMESPACE
27
28using namespace Qt::StringLiterals;
29
31{
32#if defined(RES_NORELOAD)
33 // If RES_NORELOAD is defined, then the libc is capable of watching
34 // /etc/resolv.conf for changes and reloading as necessary. So accept
35 // whatever is configured.
36 return;
37#elif defined(Q_OS_DARWIN)
38 // Apple's libsystem_info.dylib:getaddrinfo() uses the
39 // libsystem_dnssd.dylib to resolve hostnames. Using res_init() has no
40 // effect on it and is thread-unsafe.
41 return;
42#elif defined(Q_OS_FREEBSD)
43 // FreeBSD automatically refreshes:
44 // https://github.com/freebsd/freebsd-src/blob/b3fe5d932264445cbf9a1c4eab01afb6179b499b/lib/libc/resolv/res_state.c#L69
45 return;
46#elif defined(Q_OS_OPENBSD)
47 // OpenBSD automatically refreshes:
48 // https://github.com/ligurio/openbsd-src/blob/b1ce0da17da254cc15b8aff25b3d55d3c7a82cec/lib/libc/asr/asr.c#L367
49 return;
50#elif defined(Q_OS_QNX)
51 // res_init() is not thread-safe; executing it leads to state corruption.
52 // Whether it reloads resolv.conf on its own is unknown.
53 return;
54#endif
55
56#if QT_CONFIG(libresolv)
57 // OSes known or thought to reach here: AIX, NetBSD, Solaris,
58 // Linux with MUSL (though res_init() does nothing and is unnecessary)
59
60 Q_CONSTINIT static QT_STATBUF lastStat = {};
61 Q_CONSTINIT static QBasicMutex mutex = {};
62 if (QT_STATBUF st; QT_STAT(_PATH_RESCONF, &st) == 0) {
63 QMutexLocker locker(&mutex);
64 bool refresh = false;
65 if ((_res.options & RES_INIT) == 0)
66 refresh = true;
67 else if (lastStat.st_ctime != st.st_ctime)
68 refresh = true; // file was updated
69 else if (lastStat.st_dev != st.st_dev || lastStat.st_ino != st.st_ino)
70 refresh = true; // file was replaced
71 if (refresh) {
72 lastStat = st;
73 res_init();
74 }
75 }
76#endif
77}
78
79QHostInfo QHostInfoAgent::fromName(const QString &hostName)
80{
81 QHostInfo results;
82
83#if defined(QHOSTINFO_DEBUG)
84 qDebug("QHostInfoAgent::fromName(%s) looking up...",
85 hostName.toLatin1().constData());
86#endif
87
89
90 QHostAddress address;
91 if (address.setAddress(hostName))
92 return reverseLookup(address);
93
94 return lookup(hostName);
95}
96
97QString QHostInfo::localDomainName()
98{
99#if QT_CONFIG(libresolv)
100 auto domainNameFromRes = [](res_state r) {
101 QString domainName;
102 if (r->defdname[0])
103 domainName = QUrl::fromAce(r->defdname);
104 if (domainName.isEmpty())
105 domainName = QUrl::fromAce(r->dnsrch[0]);
106 return domainName;
107 };
108 std::remove_pointer_t<res_state> state = {};
109 if (res_ninit(&state) == 0) {
110 // using thread-safe version
111 auto guard = qScopeGuard([&] { res_nclose(&state); });
112 return domainNameFromRes(&state);
113 }
114
115 // using thread-unsafe version
116 maybeRefreshResolver();
117 return domainNameFromRes(&_res);
118#endif // !QT_CONFIG(libresolv)
119
120 // nothing worked, try doing it by ourselves:
121 QFile resolvconf;
122 resolvconf.setFileName(_PATH_RESCONF ""_L1);
123 if (!resolvconf.open(QIODevice::ReadOnly))
124 return QString(); // failure
125
126 QString domainName;
127 QByteArray lineArray;
128 while (resolvconf.readLineInto(&lineArray)) {
129 QByteArrayView line = QByteArrayView(lineArray).trimmed();
130 constexpr QByteArrayView domainWithSpace = "domain ";
131 if (line.startsWith(domainWithSpace))
132 return QUrl::fromAce(line.mid(domainWithSpace.size()).trimmed().toByteArray());
133
134 // in case there's no "domain" line, fall back to the first "search" entry
135 constexpr QByteArrayView searchWithSpace = "search ";
136 if (domainName.isEmpty() && line.startsWith(searchWithSpace)) {
137 QByteArrayView searchDomain = line.mid(searchWithSpace.size()).trimmed();
138 int pos = searchDomain.indexOf(' ');
139 if (pos != -1)
140 searchDomain.truncate(pos);
141 domainName = QUrl::fromAce(searchDomain.toByteArray());
142 }
143 }
144
145 // return the fallen-back-to searched domain
146 return domainName;
147}
148
149QT_END_NAMESPACE
static void maybeRefreshResolver()
#define _PATH_RESCONF