VirtualBox

source: vbox/trunk/src/VBox/Main/win/NetIfList-win.cpp@ 15510

Last change on this file since 15510 was 15510, checked in by vboxsync, 16 years ago

#3282 HostNetIf API: Windows implementation is working and is enabled by default.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/* $Id: NetIfList-win.cpp 15510 2008-12-15 15:32:45Z vboxsync $ */
2/** @file
3 * Main - NetIfList, Windows implementation.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#define LOG_GROUP LOG_GROUP_MAIN
37
38#include <iprt/asm.h>
39#include <iprt/err.h>
40#include <list>
41
42#define _WIN32_DCOM
43#include <winsock2.h>
44#include <ws2tcpip.h>
45#include <windows.h>
46
47#ifdef VBOX_WITH_NETFLT
48#include "VBox/WinNetConfig.h"
49#endif
50
51#include <iphlpapi.h>
52
53#include "Logging.h"
54#include "HostNetworkInterfaceImpl.h"
55#include "netif.h"
56
57
58static int collectNetIfInfo(Bstr &strName, PNETIFINFO pInfo)
59{
60 DWORD dwRc;
61 /*
62 * Most of the hosts probably have less than 10 adapters,
63 * so we'll mostly succeed from the first attempt.
64 */
65 ULONG uBufLen = sizeof(IP_ADAPTER_ADDRESSES) * 10;
66 PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAlloc(uBufLen);
67 if (!pAddresses)
68 return VERR_NO_MEMORY;
69 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
70 if (dwRc == ERROR_BUFFER_OVERFLOW)
71 {
72 /* Impressive! More than 10 adapters! Get more memory and try again. */
73 RTMemFree(pAddresses);
74 pAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAlloc(uBufLen);
75 if (!pAddresses)
76 return VERR_NO_MEMORY;
77 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
78 }
79 if (dwRc == NO_ERROR)
80 {
81 PIP_ADAPTER_ADDRESSES pAdapter;
82 for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next)
83 {
84 char *pszUuid = RTStrDup(pAdapter->AdapterName);
85 size_t len = strlen(pszUuid) - 1;
86 if (pszUuid[0] == '{' && pszUuid[len] == '}')
87 {
88 pszUuid[len] = 0;
89 if (!RTUuidCompareStr(&pInfo->Uuid, pszUuid + 1))
90 {
91 bool fIPFound, fIPv6Found;
92 PIP_ADAPTER_UNICAST_ADDRESS pAddr;
93 fIPFound = fIPv6Found = false;
94 for (pAddr = pAdapter->FirstUnicastAddress; pAddr; pAddr = pAddr->Next)
95 {
96 switch (pAddr->Address.lpSockaddr->sa_family)
97 {
98 case AF_INET:
99 if (!fIPFound)
100 {
101 fIPFound = true;
102 memcpy(&pInfo->IPAddress,
103 &((struct sockaddr_in *)pAddr->Address.lpSockaddr)->sin_addr.s_addr,
104 sizeof(pInfo->IPAddress));
105 }
106 break;
107 case AF_INET6:
108 if (!fIPv6Found)
109 {
110 fIPv6Found = true;
111 memcpy(&pInfo->IPv6Address,
112 ((struct sockaddr_in6 *)pAddr->Address.lpSockaddr)->sin6_addr.s6_addr,
113 sizeof(pInfo->IPv6Address));
114 }
115 break;
116 }
117 }
118 PIP_ADAPTER_PREFIX pPrefix;
119 fIPFound = fIPv6Found = false;
120 for (pPrefix = pAdapter->FirstPrefix; pPrefix; pPrefix = pPrefix->Next)
121 {
122 switch (pPrefix->Address.lpSockaddr->sa_family)
123 {
124 case AF_INET:
125 if (!fIPFound)
126 {
127 fIPFound = true;
128 ASMBitSetRange(&pInfo->IPNetMask, 0, pPrefix->PrefixLength);
129 }
130 break;
131 case AF_INET6:
132 if (!fIPv6Found)
133 {
134 fIPv6Found = true;
135 ASMBitSetRange(&pInfo->IPv6NetMask, 0, pPrefix->PrefixLength);
136 }
137 break;
138 }
139 }
140 if (sizeof(pInfo->MACAddress) != pAdapter->PhysicalAddressLength)
141 Log(("collectNetIfInfo: Unexpected physical address length: %u\n", pAdapter->PhysicalAddressLength));
142 else
143 memcpy(pInfo->MACAddress.au8, pAdapter->PhysicalAddress, sizeof(pInfo->MACAddress));
144 pInfo->enmType = NETIF_T_ETHERNET;
145 pInfo->enmStatus = pAdapter->OperStatus == IfOperStatusUp ? NETIF_S_UP : NETIF_S_DOWN;
146 RTStrFree(pszUuid);
147 break;
148 }
149 }
150 RTStrFree(pszUuid);
151 }
152 }
153 RTMemFree(pAddresses);
154
155 return VINF_SUCCESS;
156}
157
158#ifdef VBOX_WITH_NETFLT
159# define VBOX_APP_NAME L"VirtualBox"
160
161static int vboxNetWinAddComponent(std::list <ComObjPtr <HostNetworkInterface> > * pPist, INetCfgComponent * pncc)
162{
163 LPWSTR lpszName;
164 GUID IfGuid;
165 HRESULT hr;
166 int rc = VERR_GENERAL_FAILURE;
167
168 hr = pncc->GetDisplayName( &lpszName );
169 Assert(hr == S_OK);
170 if(hr == S_OK)
171 {
172 size_t cUnicodeName = wcslen(lpszName) + 1;
173 size_t uniLen = (cUnicodeName * 2 + sizeof (OLECHAR) - 1) / sizeof (OLECHAR);
174 Bstr name (uniLen + 1 /* extra zero */);
175 wcscpy((wchar_t *) name.mutableRaw(), lpszName);
176
177 hr = pncc->GetInstanceGuid(&IfGuid);
178 Assert(hr == S_OK);
179 if (hr == S_OK)
180 {
181 NETIFINFO Info;
182 memset(&Info, 0, sizeof(Info));
183 Info.Uuid = *(Guid(IfGuid).raw());
184 rc = collectNetIfInfo(name, &Info);
185 if (RT_FAILURE(rc))
186 {
187 Log(("vboxNetWinAddComponent: collectNetIfInfo() -> %Vrc\n", rc));
188 }
189 /* create a new object and add it to the list */
190 ComObjPtr <HostNetworkInterface> iface;
191 iface.createObject();
192 /* remove the curly bracket at the end */
193 if (SUCCEEDED (iface->init (name, &Info)))
194 {
195 pPist->push_back (iface);
196 rc = VINF_SUCCESS;
197 }
198 else
199 {
200 Assert(0);
201 }
202 }
203 CoTaskMemFree(lpszName);
204 }
205
206 return rc;
207}
208
209#else /* #ifndef VBOX_WITH_NETFLT */
210/**
211 * Windows helper function for NetIfList().
212 *
213 * @returns true / false.
214 *
215 * @param guid The GUID.
216 */
217static bool IsTAPDevice(const char *guid)
218{
219 HKEY hNetcard;
220 LONG status;
221 DWORD len;
222 int i = 0;
223 bool ret = false;
224
225 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &hNetcard);
226 if (status != ERROR_SUCCESS)
227 return false;
228
229 for (;;)
230 {
231 char szEnumName[256];
232 char szNetCfgInstanceId[256];
233 DWORD dwKeyType;
234 HKEY hNetCardGUID;
235
236 len = sizeof(szEnumName);
237 status = RegEnumKeyExA(hNetcard, i, szEnumName, &len, NULL, NULL, NULL, NULL);
238 if (status != ERROR_SUCCESS)
239 break;
240
241 status = RegOpenKeyExA(hNetcard, szEnumName, 0, KEY_READ, &hNetCardGUID);
242 if (status == ERROR_SUCCESS)
243 {
244 len = sizeof(szNetCfgInstanceId);
245 status = RegQueryValueExA(hNetCardGUID, "NetCfgInstanceId", NULL, &dwKeyType, (LPBYTE)szNetCfgInstanceId, &len);
246 if (status == ERROR_SUCCESS && dwKeyType == REG_SZ)
247 {
248 char szNetProductName[256];
249 char szNetProviderName[256];
250
251 szNetProductName[0] = 0;
252 len = sizeof(szNetProductName);
253 status = RegQueryValueExA(hNetCardGUID, "ProductName", NULL, &dwKeyType, (LPBYTE)szNetProductName, &len);
254
255 szNetProviderName[0] = 0;
256 len = sizeof(szNetProviderName);
257 status = RegQueryValueExA(hNetCardGUID, "ProviderName", NULL, &dwKeyType, (LPBYTE)szNetProviderName, &len);
258
259 if ( !strcmp(szNetCfgInstanceId, guid)
260 && !strcmp(szNetProductName, "VirtualBox TAP Adapter")
261 && ( (!strcmp(szNetProviderName, "innotek GmbH"))
262 || (!strcmp(szNetProviderName, "Sun Microsystems, Inc."))))
263 {
264 ret = true;
265 RegCloseKey(hNetCardGUID);
266 break;
267 }
268 }
269 RegCloseKey(hNetCardGUID);
270 }
271 ++i;
272 }
273
274 RegCloseKey(hNetcard);
275 return ret;
276}
277#endif /* #ifndef VBOX_WITH_NETFLT */
278
279int NetIfList(std::list <ComObjPtr <HostNetworkInterface> > &list)
280{
281#ifndef VBOX_WITH_NETFLT
282 static const char *NetworkKey = "SYSTEM\\CurrentControlSet\\Control\\Network\\"
283 "{4D36E972-E325-11CE-BFC1-08002BE10318}";
284 HKEY hCtrlNet;
285 LONG status;
286 DWORD len;
287 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, NetworkKey, 0, KEY_READ, &hCtrlNet);
288 if (status != ERROR_SUCCESS)
289 {
290 Log(("NetIfList: Could not open registry key \"%s\"", NetworkKey));
291 return E_FAIL;
292 }
293
294 for (int i = 0;; ++ i)
295 {
296 char szNetworkGUID [256];
297 HKEY hConnection;
298 char szNetworkConnection [256];
299
300 len = sizeof (szNetworkGUID);
301 status = RegEnumKeyExA (hCtrlNet, i, szNetworkGUID, &len, NULL, NULL, NULL, NULL);
302 if (status != ERROR_SUCCESS)
303 break;
304
305 if (!IsTAPDevice(szNetworkGUID))
306 continue;
307
308 RTStrPrintf (szNetworkConnection, sizeof (szNetworkConnection),
309 "%s\\Connection", szNetworkGUID);
310 status = RegOpenKeyExA (hCtrlNet, szNetworkConnection, 0, KEY_READ, &hConnection);
311 if (status == ERROR_SUCCESS)
312 {
313 DWORD dwKeyType;
314 status = RegQueryValueExW (hConnection, TEXT("Name"), NULL,
315 &dwKeyType, NULL, &len);
316 if (status == ERROR_SUCCESS && dwKeyType == REG_SZ)
317 {
318 size_t uniLen = (len + sizeof (OLECHAR) - 1) / sizeof (OLECHAR);
319 Bstr name (uniLen + 1 /* extra zero */);
320 status = RegQueryValueExW (hConnection, TEXT("Name"), NULL,
321 &dwKeyType, (LPBYTE) name.mutableRaw(), &len);
322 if (status == ERROR_SUCCESS)
323 {
324 LogFunc(("Connection name %ls\n", name.mutableRaw()));
325 /* put a trailing zero, just in case (see MSDN) */
326 name.mutableRaw() [uniLen] = 0;
327 /* create a new object and add it to the list */
328 ComObjPtr <HostNetworkInterface> iface;
329 iface.createObject();
330 /* remove the curly bracket at the end */
331 szNetworkGUID [strlen(szNetworkGUID) - 1] = '\0';
332
333 NETIFINFO Info;
334 memset(&Info, 0, sizeof(Info));
335 Info.Uuid = *(Guid(szNetworkGUID + 1).raw());
336 int rc = collectNetIfInfo(name, &Info);
337 if (RT_FAILURE(rc))
338 {
339 Log(("vboxNetWinAddComponent: collectNetIfInfo() -> %Vrc\n", rc));
340 }
341
342 if (SUCCEEDED (iface->init (name, &Info)))
343 list.push_back (iface);
344 }
345 }
346 RegCloseKey (hConnection);
347 }
348 }
349 RegCloseKey (hCtrlNet);
350#else /* # if defined VBOX_WITH_NETFLT */
351 INetCfg *pNc;
352 INetCfgComponent *pMpNcc;
353 INetCfgComponent *pTcpIpNcc;
354 LPWSTR lpszApp;
355 HRESULT hr;
356 IEnumNetCfgBindingPath *pEnumBp;
357 INetCfgBindingPath *pBp;
358 IEnumNetCfgBindingInterface *pEnumBi;
359 INetCfgBindingInterface *pBi;
360
361 /* we are using the INetCfg API for getting the list of miniports */
362 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
363 VBOX_APP_NAME,
364 &pNc,
365 &lpszApp );
366 Assert(hr == S_OK);
367 if(hr == S_OK)
368 {
369# ifdef VBOX_NETFLT_ONDEMAND_BIND
370 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
371 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
372# else
373 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
374 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
375# ifndef VBOX_WITH_HARDENING
376 if(hr != S_OK)
377 {
378 /* TODO: try to install the netflt from here */
379 }
380# endif
381
382# endif
383
384 if(hr == S_OK)
385 {
386 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
387 Assert(hr == S_OK);
388 if ( hr == S_OK )
389 {
390 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
391 Assert(hr == S_OK || hr == S_FALSE);
392 while( hr == S_OK )
393 {
394 /* S_OK == enabled, S_FALSE == disabled */
395 if(pBp->IsEnabled() == S_OK)
396 {
397 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
398 Assert(hr == S_OK);
399 if ( hr == S_OK )
400 {
401 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
402 Assert(hr == S_OK);
403 while(hr == S_OK)
404 {
405 hr = pBi->GetLowerComponent( &pMpNcc );
406 Assert(hr == S_OK);
407 if(hr == S_OK)
408 {
409 vboxNetWinAddComponent(&list, pMpNcc);
410 VBoxNetCfgWinReleaseRef( pMpNcc );
411 }
412 VBoxNetCfgWinReleaseRef(pBi);
413
414 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
415 }
416 VBoxNetCfgWinReleaseRef(pEnumBi);
417 }
418 }
419 VBoxNetCfgWinReleaseRef(pBp);
420
421 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
422 }
423 VBoxNetCfgWinReleaseRef(pEnumBp);
424 }
425 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
426 }
427 else
428 {
429 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
430 }
431
432 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
433 }
434#endif /* # if defined VBOX_WITH_NETFLT */
435 return VINF_SUCCESS;
436}
Note: See TracBrowser for help on using the repository browser.

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