VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp@ 97698

Last change on this file since 97698 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.8 KB
Line 
1/* $Id: HostDnsServiceLinux.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * Linux specific DNS information fetching.
4 */
5
6/*
7 * Copyright (C) 2013-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <iprt/assert.h>
29#include <iprt/errcore.h>
30#include <iprt/initterm.h>
31#include <iprt/file.h>
32#include <iprt/log.h>
33#include <iprt/stream.h>
34#include <iprt/string.h>
35#include <iprt/semaphore.h>
36#include <iprt/thread.h>
37
38#include <errno.h>
39#include <poll.h>
40#include <string.h>
41#include <unistd.h>
42
43#include <fcntl.h>
44
45#include <linux/limits.h>
46
47/* Workaround for <sys/cdef.h> defining __flexarr to [] which beats us in
48 * struct inotify_event (char name __flexarr). */
49#include <sys/cdefs.h>
50#undef __flexarr
51#define __flexarr [0]
52#include <sys/inotify.h>
53#include <sys/types.h>
54#include <sys/socket.h>
55
56#include <iprt/sanitized/string>
57#include <vector>
58#include "../HostDnsService.h"
59
60
61static int g_DnsMonitorStop[2];
62
63static const std::string g_EtcFolder = "/etc";
64static const std::string g_ResolvConf = "resolv.conf";
65static const std::string g_ResolvConfFullPath = "/etc/resolv.conf";
66
67class FileDescriptor
68{
69 public:
70 FileDescriptor(int d = -1):fd(d){}
71
72 virtual ~FileDescriptor() {
73 if (fd != -1)
74 close(fd);
75 }
76
77 int fileDescriptor() const {return fd;}
78
79 protected:
80 int fd;
81};
82
83
84class AutoNotify:public FileDescriptor
85{
86 public:
87 AutoNotify()
88 {
89 FileDescriptor::fd = inotify_init();
90 AssertReturnVoid(FileDescriptor::fd != -1);
91 }
92};
93
94struct InotifyEventWithName
95{
96 struct inotify_event e;
97 char name[NAME_MAX];
98};
99
100HostDnsServiceLinux::~HostDnsServiceLinux()
101{
102}
103
104HRESULT HostDnsServiceLinux::init(HostDnsMonitorProxy *pProxy)
105{
106 return HostDnsServiceResolvConf::init(pProxy, "/etc/resolv.conf");
107}
108
109int HostDnsServiceLinux::monitorThreadShutdown(RTMSINTERVAL uTimeoutMs)
110{
111 RT_NOREF(uTimeoutMs);
112
113 send(g_DnsMonitorStop[0], "", 1, 0);
114
115 /** @todo r=andy Do we have to wait for something here? Can this fail? */
116 return VINF_SUCCESS;
117}
118
119int HostDnsServiceLinux::monitorThreadProc(void)
120{
121 AutoNotify a;
122
123 int rc = socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_DnsMonitorStop);
124 AssertMsgReturn(rc == 0, ("socketpair: failed (%d: %s)\n", errno, strerror(errno)), E_FAIL);
125
126 FileDescriptor stopper0(g_DnsMonitorStop[0]);
127 FileDescriptor stopper1(g_DnsMonitorStop[1]);
128
129 pollfd polls[2];
130 RT_ZERO(polls);
131
132 polls[0].fd = a.fileDescriptor();
133 polls[0].events = POLLIN;
134
135 polls[1].fd = g_DnsMonitorStop[1];
136 polls[1].events = POLLIN;
137
138 onMonitorThreadInitDone();
139
140 int wd[2];
141 wd[0] = wd[1] = -1;
142 /* inotify inialization */
143 wd[0] = inotify_add_watch(a.fileDescriptor(),
144 g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE|IN_DELETE_SELF);
145
146 /**
147 * If /etc/resolv.conf exists we want to listen for movements: because
148 * # mv /etc/resolv.conf ...
149 * won't arm IN_DELETE_SELF on wd[0] instead it will fire IN_MOVE_FROM on wd[1].
150 *
151 * Because on some distributions /etc/resolv.conf is link, wd[0] can't detect deletion,
152 * it's recognizible on directory level (wd[1]) only.
153 */
154 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
155 wd[0] == -1 ? IN_MOVED_TO|IN_CREATE : IN_MOVED_FROM|IN_DELETE);
156
157 struct InotifyEventWithName combo;
158 while(true)
159 {
160 rc = poll(polls, 2, -1);
161 if (rc == -1)
162 continue;
163
164 AssertMsgReturn( ((polls[0].revents & (POLLERR|POLLNVAL)) == 0)
165 && ((polls[1].revents & (POLLERR|POLLNVAL)) == 0),
166 ("Debug Me"), VERR_INTERNAL_ERROR);
167
168 if (polls[1].revents & POLLIN)
169 return VINF_SUCCESS; /* time to shutdown */
170
171 if (polls[0].revents & POLLIN)
172 {
173 RT_ZERO(combo);
174 ssize_t r = read(polls[0].fd, static_cast<void *>(&combo), sizeof(combo));
175 RT_NOREF(r);
176
177 if (combo.e.wd == wd[0])
178 {
179 if (combo.e.mask & IN_CLOSE_WRITE)
180 {
181 readResolvConf();
182 }
183 else if (combo.e.mask & IN_DELETE_SELF)
184 {
185 inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */
186 inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
187 IN_MOVED_TO|IN_CREATE); /* alter folder watcher */
188 }
189 else if (combo.e.mask & IN_IGNORED)
190 {
191 wd[0] = -1; /* we want receive any events on this watch */
192 }
193 else
194 {
195 /**
196 * It shouldn't happen, in release we will just ignore in debug
197 * we will have to chance to look at into inotify_event
198 */
199 AssertMsgFailed(("Debug Me!!!"));
200 }
201 }
202 else if (combo.e.wd == wd[1])
203 {
204 if ( combo.e.mask & IN_MOVED_FROM
205 || combo.e.mask & IN_DELETE)
206 {
207 if (g_ResolvConf == combo.e.name)
208 {
209 /**
210 * Our file has been moved so we should change watching mode.
211 */
212 inotify_rm_watch(a.fileDescriptor(), wd[0]);
213 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
214 IN_MOVED_TO|IN_CREATE);
215 AssertMsg(wd[1] != -1,
216 ("It shouldn't happen, further investigation is needed\n"));
217 }
218 }
219 else
220 {
221 AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE),
222 ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n",
223 combo.e.mask));
224 if (g_ResolvConf == combo.e.name)
225 {
226 AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n"));
227
228 /* alter folder watcher*/
229 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
230 IN_MOVED_FROM|IN_DELETE);
231 AssertMsg(wd[1] != -1, ("It shouldn't happen.\n"));
232
233 wd[0] = inotify_add_watch(a.fileDescriptor(),
234 g_ResolvConfFullPath.c_str(),
235 IN_CLOSE_WRITE | IN_DELETE_SELF);
236 AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n",
237 g_ResolvConfFullPath.c_str()));
238
239 /* Notify our listeners */
240 readResolvConf();
241 }
242 }
243 }
244 else
245 {
246 /* It shouldn't happen */
247 AssertMsgFailed(("Shouldn't happen! Please debug me!"));
248 }
249 }
250 }
251}
252
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette