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