VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp@ 53390

Last change on this file since 53390 was 53242, checked in by vboxsync, 10 years ago

Main/HostDnsService: Tcpip\Parameters\NameServer value is not updated
when the list of name servers is statically configured, so don't
inspect NameServer and DhcpNameServer directly - instead use
DnsQueryConfig(DnsConfigDnsServerList, ...) from DnsAPI.dll

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.0 KB
Line 
1/* $Id: HostDnsServiceWin.cpp 53242 2014-11-05 16:28:08Z vboxsync $ */
2/** @file
3 * Host DNS listener for Windows.
4 */
5
6/*
7 * Copyright (C) 2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#include "../HostDnsService.h"
18
19#include <VBox/com/string.h>
20#include <VBox/com/ptr.h>
21
22#include <iprt/assert.h>
23#include <iprt/err.h>
24#include <VBox/log.h>
25
26#include <Windows.h>
27#include <windns.h>
28
29#include <algorithm>
30#include <sstream>
31#include <string>
32#include <vector>
33
34struct HostDnsServiceWin::Data
35{
36 HKEY hKeyTcpipParameters;
37
38#define DATA_SHUTDOWN_EVENT 0
39#define DATA_DNS_UPDATE_EVENT 1
40#define DATA_MAX_EVENT 2
41 HANDLE haDataEvent[DATA_MAX_EVENT];
42
43 Data()
44 {
45 hKeyTcpipParameters = NULL;
46
47 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
48 haDataEvent[i] = NULL;
49 }
50
51 ~Data()
52 {
53 if (hKeyTcpipParameters != NULL)
54 RegCloseKey(hKeyTcpipParameters);
55
56 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
57 if (haDataEvent[i] != NULL)
58 CloseHandle(haDataEvent[i]);
59 }
60};
61
62
63HostDnsServiceWin::HostDnsServiceWin()
64 : HostDnsMonitor(true),
65 m(NULL)
66{
67 std::auto_ptr<Data> data(new Data());
68 LONG lrc;
69
70 lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
71 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
72 0,
73 KEY_READ|KEY_NOTIFY,
74 &data->hKeyTcpipParameters);
75 if (lrc != ERROR_SUCCESS)
76 {
77 LogRel(("HostDnsServiceWin: failed to open key Tcpip\\Parameters (error %d)\n", lrc));
78 return;
79 }
80
81 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
82 {
83 data->haDataEvent[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
84 if (data->haDataEvent[i] == NULL)
85 {
86 LogRel(("HostDnsServiceWin: failed to create event (error %d)\n", GetLastError()));
87 return;
88 }
89 }
90
91 m = data.release();
92}
93
94
95HostDnsServiceWin::~HostDnsServiceWin()
96{
97 if (m != NULL)
98 delete m;
99}
100
101
102HRESULT HostDnsServiceWin::init()
103{
104 if (m == NULL)
105 return E_FAIL;
106
107 HRESULT hrc = HostDnsMonitor::init();
108 if (FAILED(hrc))
109 return hrc;
110
111 return updateInfo();
112}
113
114
115void HostDnsServiceWin::monitorThreadShutdown()
116{
117 Assert(m != NULL);
118 SetEvent(m->haDataEvent[DATA_SHUTDOWN_EVENT]);
119}
120
121
122static inline int registerNotification(const HKEY& hKey, HANDLE& hEvent)
123{
124 LONG lrc = RegNotifyChangeKeyValue(hKey,
125 TRUE,
126 REG_NOTIFY_CHANGE_LAST_SET,
127 hEvent,
128 TRUE);
129 AssertMsgReturn(lrc == ERROR_SUCCESS,
130 ("Failed to register event on the key. Please debug me!"),
131 VERR_INTERNAL_ERROR);
132
133 return VINF_SUCCESS;
134}
135
136
137int HostDnsServiceWin::monitorWorker()
138{
139 Assert(m != NULL);
140
141 registerNotification(m->hKeyTcpipParameters,
142 m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
143
144 monitorThreadInitializationDone();
145
146 for (;;)
147 {
148 DWORD dwReady;
149
150 dwReady = WaitForMultipleObjects(DATA_MAX_EVENT, m->haDataEvent,
151 FALSE, INFINITE);
152
153 if (dwReady == WAIT_OBJECT_0 + DATA_SHUTDOWN_EVENT)
154 break;
155
156 if (dwReady == WAIT_OBJECT_0 + DATA_DNS_UPDATE_EVENT)
157 {
158 updateInfo();
159 notifyAll();
160
161 ResetEvent(m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
162 registerNotification(m->hKeyTcpipParameters,
163 m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
164
165 }
166 else
167 {
168 if (dwReady == WAIT_FAILED)
169 LogRel(("HostDnsServiceWin: WaitForMultipleObjects failed: error %d\n", GetLastError()));
170 else
171 LogRel(("HostDnsServiceWin: WaitForMultipleObjects unexpected return value %d\n", dwReady));
172 return VERR_INTERNAL_ERROR;
173 }
174 }
175
176 return VINF_SUCCESS;
177}
178
179
180void vappend(std::vector<std::string> &v, const std::string &s, char sep = ' ')
181{
182 if (s.empty())
183 return;
184
185 std::istringstream stream(s);
186 std::string substr;
187
188 while (std::getline(stream, substr, sep))
189 {
190 if (substr.empty())
191 continue;
192
193 if (std::find(v.cbegin(), v.cend(), substr) != v.cend())
194 continue;
195
196 v.push_back(substr);
197 }
198}
199
200
201HRESULT HostDnsServiceWin::updateInfo()
202{
203 LONG lrc;
204
205 std::string strDomain;
206 std::string strDhcpDomain;
207 std::string strSearchList; /* NB: comma separated, no spaces */
208
209 for (DWORD regIndex = 0; /**/; ++regIndex) {
210 char keyName[256];
211 DWORD cbKeyName = sizeof(keyName);
212 DWORD keyType = 0;
213 char keyData[1024];
214 DWORD cbKeyData = sizeof(keyData);
215
216 lrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex,
217 keyName, &cbKeyName, 0,
218 &keyType, (LPBYTE)keyData, &cbKeyData);
219
220 if (lrc == ERROR_NO_MORE_ITEMS)
221 break;
222
223 if (lrc == ERROR_MORE_DATA) /* buffer too small; handle? */
224 continue;
225
226 if (lrc != ERROR_SUCCESS)
227 {
228 LogRel(("HostDnsServiceWin: RegEnumValue error %d\n", (int)lrc));
229 return E_FAIL;
230 }
231
232 if (keyType != REG_SZ)
233 continue;
234
235 if (cbKeyData > 0 && keyData[cbKeyData - 1] == '\0')
236 --cbKeyData; /* don't count trailing NUL if present */
237
238 if (RTStrICmp("Domain", keyName) == 0)
239 {
240 strDomain.assign(keyData, cbKeyData);
241 Log2(("... Domain=\"%s\"\n", strDomain.c_str()));
242 }
243 else if (RTStrICmp("DhcpDomain", keyName) == 0)
244 {
245 strDhcpDomain.assign(keyData, cbKeyData);
246 Log2(("... DhcpDomain=\"%s\"\n", strDhcpDomain.c_str()));
247 }
248 else if (RTStrICmp("SearchList", keyName) == 0)
249 {
250 strSearchList.assign(keyData, cbKeyData);
251 Log2(("... SearchList=\"%s\"\n", strSearchList.c_str()));
252 }
253 }
254
255 HostDnsInformation info;
256
257 /*
258 * When name servers are configured statically it seems that the
259 * value of Tcpip\Parameters\NameServer is NOT set, inly interface
260 * specific NameServer value is (which triggers notification for
261 * us to pick up the change). Fortunately, DnsApi seems to do the
262 * right thing there.
263 */
264 DNS_STATUS status;
265 PIP4_ARRAY pIp4Array = NULL;
266
267 // NB: must be set on input it seems, despite docs' claim to the contrary.
268 DWORD cbBuffer = sizeof(&pIp4Array);
269
270 status = DnsQueryConfig(DnsConfigDnsServerList,
271 DNS_CONFIG_FLAG_ALLOC, NULL, NULL,
272 &pIp4Array, &cbBuffer);
273
274 if (status == NO_ERROR && pIp4Array != NULL)
275 {
276 for (DWORD i = 0; i < pIp4Array->AddrCount; ++i)
277 {
278 char szAddrStr[16] = "";
279 RTStrPrintf(szAddrStr, sizeof(szAddrStr), "%RTnaipv4", pIp4Array->AddrArray[i]);
280
281 Log2((" server %d: %s\n", i+1, szAddrStr));
282 info.servers.push_back(szAddrStr);
283 }
284
285 LocalFree(pIp4Array);
286 }
287
288 if (!strDomain.empty())
289 {
290 info.domain = strDomain;
291
292 info.searchList.push_back(strDomain);
293 if (!strDhcpDomain.empty() && strDhcpDomain != strDomain)
294 info.searchList.push_back(strDhcpDomain);
295 }
296 else if (!strDhcpDomain.empty())
297 {
298 info.domain = strDhcpDomain;
299 info.searchList.push_back(strDomain);
300 }
301
302 vappend(info.searchList, strSearchList, ',');
303 if (info.searchList.size() == 1)
304 info.searchList.clear();
305
306 HostDnsMonitor::setInfo(info);
307
308 return S_OK;
309}
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