VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostDnsService.cpp

Last change on this file was 98288, checked in by vboxsync, 16 months ago

Main/src-server: rc -> hrc/vrc (partial). bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.3 KB
Line 
1/* $Id: HostDnsService.cpp 98288 2023-01-24 15:32:43Z vboxsync $ */
2/** @file
3 * Base class for Host DNS & Co services.
4 */
5
6/*
7 * Copyright (C) 2013-2023 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#define LOG_GROUP LOG_GROUP_MAIN_HOST
29#include <VBox/com/array.h>
30#include <VBox/com/ptr.h>
31#include <VBox/com/string.h>
32
33#include <iprt/cpp/utils.h>
34
35#include "LoggingNew.h"
36#include "VirtualBoxImpl.h"
37#include <iprt/time.h>
38#include <iprt/thread.h>
39#include <iprt/semaphore.h>
40#include <iprt/critsect.h>
41
42#include <algorithm>
43#include <set>
44#include <iprt/sanitized/string>
45#include "HostDnsService.h"
46
47
48
49static void dumpHostDnsStrVector(const std::string &prefix, const std::vector<std::string> &v)
50{
51 int i = 1;
52 for (std::vector<std::string>::const_iterator it = v.begin();
53 it != v.end();
54 ++it, ++i)
55 LogRel((" %s %d: %s\n", prefix.c_str(), i, it->c_str()));
56 if (v.empty())
57 LogRel((" no %s entries\n", prefix.c_str()));
58}
59
60static void dumpHostDnsInformation(const HostDnsInformation &info)
61{
62 dumpHostDnsStrVector("server", info.servers);
63
64 if (!info.domain.empty())
65 LogRel((" domain: %s\n", info.domain.c_str()));
66 else
67 LogRel((" no domain set\n"));
68
69 dumpHostDnsStrVector("search string", info.searchList);
70}
71
72bool HostDnsInformation::equals(const HostDnsInformation &info, uint32_t fLaxComparison) const
73{
74 bool fSameServers;
75 if ((fLaxComparison & IGNORE_SERVER_ORDER) == 0)
76 fSameServers = (servers == info.servers);
77 else
78 {
79 std::set<std::string> l(servers.begin(), servers.end());
80 std::set<std::string> r(info.servers.begin(), info.servers.end());
81
82 fSameServers = (l == r);
83 }
84
85 bool fSameDomain, fSameSearchList;
86 if ((fLaxComparison & IGNORE_SUFFIXES) == 0)
87 {
88 fSameDomain = (domain == info.domain);
89 fSameSearchList = (searchList == info.searchList);
90 }
91 else
92 fSameDomain = fSameSearchList = true;
93
94 return fSameServers && fSameDomain && fSameSearchList;
95}
96
97DECLINLINE(void) detachVectorOfString(const std::vector<std::string>& v, std::vector<com::Utf8Str> &aArray)
98{
99 aArray.resize(v.size());
100 size_t i = 0;
101 for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it, ++i)
102 aArray[i] = Utf8Str(it->c_str()); /** @todo r=bird: *it isn't necessarily UTF-8 clean!!
103 * On darwin we do silly shit like using CFStringGetSystemEncoding()
104 * that may be UTF-8 but doesn't need to be.
105 *
106 * Why on earth are we using std::string here anyway?
107 */
108}
109
110struct HostDnsServiceBase::Data
111{
112 Data(bool aThreaded)
113 : pProxy(NULL)
114 , fThreaded(aThreaded)
115 , hMonitorThreadEvent(NIL_RTSEMEVENT)
116 , hMonitorThread(NIL_RTTHREAD)
117 {}
118
119 /** Weak pointer to parent proxy object. */
120 HostDnsMonitorProxy *pProxy;
121 /** Whether the DNS monitor implementation has a dedicated monitoring thread. Optional. */
122 const bool fThreaded;
123 /** Event for the monitor thread, if any. */
124 RTSEMEVENT hMonitorThreadEvent;
125 /** Handle of the monitor thread, if any. */
126 RTTHREAD hMonitorThread;
127 /** Generic host DNS information. */
128 HostDnsInformation info;
129};
130
131struct HostDnsMonitorProxy::Data
132{
133 Data(HostDnsServiceBase *aMonitor, VirtualBox *aParent)
134 : pVirtualBox(aParent)
135 , pMonitorImpl(aMonitor)
136 , uLastExtraDataPoll(0)
137 , fLaxComparison(0)
138 , info()
139 {}
140
141 VirtualBox *pVirtualBox;
142 HostDnsServiceBase *pMonitorImpl;
143
144 uint64_t uLastExtraDataPoll;
145 uint32_t fLaxComparison;
146 HostDnsInformation info;
147};
148
149
150HostDnsServiceBase::HostDnsServiceBase(bool fThreaded)
151 : m(NULL)
152{
153 m = new HostDnsServiceBase::Data(fThreaded);
154}
155
156HostDnsServiceBase::~HostDnsServiceBase()
157{
158 if (m)
159 {
160 delete m;
161 m = NULL;
162 }
163}
164
165/* static */
166HostDnsServiceBase *HostDnsServiceBase::createHostDnsMonitor(void)
167{
168 HostDnsServiceBase *pMonitor = NULL;
169
170#if defined (RT_OS_DARWIN)
171 pMonitor = new HostDnsServiceDarwin();
172#elif defined(RT_OS_WINDOWS)
173 pMonitor = new HostDnsServiceWin();
174#elif defined(RT_OS_LINUX)
175 pMonitor = new HostDnsServiceLinux();
176#elif defined(RT_OS_SOLARIS)
177 pMonitor = new HostDnsServiceSolaris();
178#elif defined(RT_OS_FREEBSD)
179 pMonitor = new HostDnsServiceFreebsd();
180#elif defined(RT_OS_OS2)
181 pMonitor = new HostDnsServiceOs2();
182#else
183 pMonitor = new HostDnsServiceBase();
184#endif
185
186 return pMonitor;
187}
188
189HRESULT HostDnsServiceBase::init(HostDnsMonitorProxy *pProxy)
190{
191 LogRel(("HostDnsMonitor: initializing\n"));
192
193 AssertPtrReturn(pProxy, E_POINTER);
194 m->pProxy = pProxy;
195
196 if (m->fThreaded)
197 {
198 LogRel2(("HostDnsMonitor: starting thread ...\n"));
199
200 int vrc = RTSemEventCreate(&m->hMonitorThreadEvent);
201 AssertRCReturn(vrc, E_FAIL);
202
203 vrc = RTThreadCreate(&m->hMonitorThread,
204 HostDnsServiceBase::threadMonitorProc,
205 this, 128 * _1K, RTTHREADTYPE_IO,
206 RTTHREADFLAGS_WAITABLE, "dns-monitor");
207 AssertRCReturn(vrc, E_FAIL);
208
209 RTSemEventWait(m->hMonitorThreadEvent, RT_INDEFINITE_WAIT);
210
211 LogRel2(("HostDnsMonitor: thread started\n"));
212 }
213
214 return S_OK;
215}
216
217void HostDnsServiceBase::uninit(void)
218{
219 LogRel(("HostDnsMonitor: shutting down ...\n"));
220
221 if (m->fThreaded)
222 {
223 LogRel2(("HostDnsMonitor: waiting for thread ...\n"));
224
225 const RTMSINTERVAL uTimeoutMs = 30 * 1000; /* 30s */
226
227 monitorThreadShutdown(uTimeoutMs);
228
229 int vrc = RTThreadWait(m->hMonitorThread, uTimeoutMs, NULL);
230 if (RT_FAILURE(vrc))
231 LogRel(("HostDnsMonitor: waiting for thread failed with vrc=%Rrc\n", vrc));
232
233 if (m->hMonitorThreadEvent != NIL_RTSEMEVENT)
234 {
235 RTSemEventDestroy(m->hMonitorThreadEvent);
236 m->hMonitorThreadEvent = NIL_RTSEMEVENT;
237 }
238 }
239
240 LogRel(("HostDnsMonitor: shut down\n"));
241}
242
243void HostDnsServiceBase::setInfo(const HostDnsInformation &info)
244{
245 if (m->pProxy != NULL)
246 m->pProxy->notify(info);
247}
248
249void HostDnsMonitorProxy::pollGlobalExtraData(void)
250{
251 VirtualBox *pVirtualBox = m->pVirtualBox;
252 if (RT_UNLIKELY(pVirtualBox == NULL))
253 return;
254
255 uint64_t uNow = RTTimeNanoTS();
256 if (uNow - m->uLastExtraDataPoll >= RT_NS_30SEC || m->uLastExtraDataPoll == 0)
257 {
258 m->uLastExtraDataPoll = uNow;
259
260 /*
261 * Should we ignore the order of DNS servers?
262 */
263 const com::Bstr bstrHostDNSOrderIgnoreKey("VBoxInternal2/HostDNSOrderIgnore");
264 com::Bstr bstrHostDNSOrderIgnore;
265 pVirtualBox->GetExtraData(bstrHostDNSOrderIgnoreKey.raw(),
266 bstrHostDNSOrderIgnore.asOutParam());
267 uint32_t fDNSOrderIgnore = 0;
268 if (bstrHostDNSOrderIgnore.isNotEmpty())
269 {
270 if (bstrHostDNSOrderIgnore != "0")
271 fDNSOrderIgnore = HostDnsInformation::IGNORE_SERVER_ORDER;
272 }
273
274 if (fDNSOrderIgnore != (m->fLaxComparison & HostDnsInformation::IGNORE_SERVER_ORDER))
275 {
276
277 m->fLaxComparison ^= HostDnsInformation::IGNORE_SERVER_ORDER;
278 LogRel(("HostDnsMonitor: %ls=%ls\n",
279 bstrHostDNSOrderIgnoreKey.raw(),
280 bstrHostDNSOrderIgnore.raw()));
281 }
282
283 /*
284 * Should we ignore changes to the domain name or the search list?
285 */
286 const com::Bstr bstrHostDNSSuffixesIgnoreKey("VBoxInternal2/HostDNSSuffixesIgnore");
287 com::Bstr bstrHostDNSSuffixesIgnore;
288 pVirtualBox->GetExtraData(bstrHostDNSSuffixesIgnoreKey.raw(),
289 bstrHostDNSSuffixesIgnore.asOutParam());
290 uint32_t fDNSSuffixesIgnore = 0;
291 if (bstrHostDNSSuffixesIgnore.isNotEmpty())
292 {
293 if (bstrHostDNSSuffixesIgnore != "0")
294 fDNSSuffixesIgnore = HostDnsInformation::IGNORE_SUFFIXES;
295 }
296
297 if (fDNSSuffixesIgnore != (m->fLaxComparison & HostDnsInformation::IGNORE_SUFFIXES))
298 {
299
300 m->fLaxComparison ^= HostDnsInformation::IGNORE_SUFFIXES;
301 LogRel(("HostDnsMonitor: %ls=%ls\n",
302 bstrHostDNSSuffixesIgnoreKey.raw(),
303 bstrHostDNSSuffixesIgnore.raw()));
304 }
305 }
306}
307
308void HostDnsServiceBase::onMonitorThreadInitDone(void)
309{
310 if (!m->fThreaded) /* If non-threaded, bail out, nothing to do here. */
311 return;
312
313 RTSemEventSignal(m->hMonitorThreadEvent);
314}
315
316DECLCALLBACK(int) HostDnsServiceBase::threadMonitorProc(RTTHREAD, void *pvUser)
317{
318 HostDnsServiceBase *pThis = static_cast<HostDnsServiceBase *>(pvUser);
319 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
320 return pThis->monitorThreadProc();
321}
322
323/* HostDnsMonitorProxy */
324HostDnsMonitorProxy::HostDnsMonitorProxy()
325 : m(NULL)
326{
327}
328
329HostDnsMonitorProxy::~HostDnsMonitorProxy()
330{
331 uninit();
332}
333
334HRESULT HostDnsMonitorProxy::init(VirtualBox* aParent)
335{
336 AssertMsgReturn(m == NULL, ("DNS monitor proxy already initialized\n"), E_FAIL);
337
338 HostDnsServiceBase *pMonitorImpl = HostDnsServiceBase::createHostDnsMonitor();
339 AssertPtrReturn(pMonitorImpl, E_OUTOFMEMORY);
340
341 Assert(m == NULL); /* Paranoia. */
342 m = new HostDnsMonitorProxy::Data(pMonitorImpl, aParent);
343 AssertPtrReturn(m, E_OUTOFMEMORY);
344
345 return m->pMonitorImpl->init(this);
346}
347
348void HostDnsMonitorProxy::uninit(void)
349{
350 if (m)
351 {
352 if (m->pMonitorImpl)
353 {
354 m->pMonitorImpl->uninit();
355
356 delete m->pMonitorImpl;
357 m->pMonitorImpl = NULL;
358 }
359
360 delete m;
361 m = NULL;
362 }
363}
364
365void HostDnsMonitorProxy::notify(const HostDnsInformation &info)
366{
367 const bool fNotify = updateInfo(info);
368 if (fNotify)
369 m->pVirtualBox->i_onHostNameResolutionConfigurationChange();
370}
371
372HRESULT HostDnsMonitorProxy::GetNameServers(std::vector<com::Utf8Str> &aNameServers)
373{
374 AssertReturn(m != NULL, E_FAIL);
375 RTCLock grab(m_LockMtx);
376
377 LogRel(("HostDnsMonitorProxy::GetNameServers:\n"));
378 dumpHostDnsStrVector("name server", m->info.servers);
379
380 detachVectorOfString(m->info.servers, aNameServers);
381
382 return S_OK;
383}
384
385HRESULT HostDnsMonitorProxy::GetDomainName(com::Utf8Str *pDomainName)
386{
387 AssertReturn(m != NULL, E_FAIL);
388 RTCLock grab(m_LockMtx);
389
390 LogRel(("HostDnsMonitorProxy::GetDomainName: %s\n",
391 m->info.domain.empty() ? "no domain set" : m->info.domain.c_str()));
392
393 *pDomainName = m->info.domain.c_str();
394
395 return S_OK;
396}
397
398HRESULT HostDnsMonitorProxy::GetSearchStrings(std::vector<com::Utf8Str> &aSearchStrings)
399{
400 AssertReturn(m != NULL, E_FAIL);
401 RTCLock grab(m_LockMtx);
402
403 LogRel(("HostDnsMonitorProxy::GetSearchStrings:\n"));
404 dumpHostDnsStrVector("search string", m->info.searchList);
405
406 detachVectorOfString(m->info.searchList, aSearchStrings);
407
408 return S_OK;
409}
410
411bool HostDnsMonitorProxy::updateInfo(const HostDnsInformation &info)
412{
413 LogRel(("HostDnsMonitor: updating information\n"));
414 RTCLock grab(m_LockMtx);
415
416 if (info.equals(m->info))
417 {
418 LogRel(("HostDnsMonitor: unchanged\n"));
419 return false;
420 }
421
422 pollGlobalExtraData();
423
424 LogRel(("HostDnsMonitor: old information\n"));
425 dumpHostDnsInformation(m->info);
426 LogRel(("HostDnsMonitor: new information\n"));
427 dumpHostDnsInformation(info);
428
429 bool fIgnore = m->fLaxComparison != 0 && info.equals(m->info, m->fLaxComparison);
430 m->info = info;
431
432 if (fIgnore)
433 {
434 LogRel(("HostDnsMonitor: lax comparison %#x, not notifying\n", m->fLaxComparison));
435 return false;
436 }
437
438 return true;
439}
440
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use