diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
commit | 16f504a9dca3fe3b70568f67b7d41241ae485288 (patch) | |
tree | c60f36ada0496ba928b7161059ba5ab1ab224f9d /src/VBox/Main/src-server/win/NetIf-win.cpp | |
parent | Initial commit. (diff) | |
download | virtualbox-upstream.tar.xz virtualbox-upstream.zip |
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Main/src-server/win/NetIf-win.cpp')
-rw-r--r-- | src/VBox/Main/src-server/win/NetIf-win.cpp | 2017 |
1 files changed, 2017 insertions, 0 deletions
diff --git a/src/VBox/Main/src-server/win/NetIf-win.cpp b/src/VBox/Main/src-server/win/NetIf-win.cpp new file mode 100644 index 00000000..8a48a133 --- /dev/null +++ b/src/VBox/Main/src-server/win/NetIf-win.cpp @@ -0,0 +1,2017 @@ +/* $Id: NetIf-win.cpp $ */ +/** @file + * Main - NetIfList, Windows implementation. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_MAIN_HOST + +#define NETIF_WITHOUT_NETCFG + +#include <iprt/errcore.h> +#include <list> + +#define _WIN32_DCOM +#include <iprt/win/winsock2.h> +#include <iprt/win/ws2tcpip.h> +#include <iprt/win/windows.h> +#include <tchar.h> + +#ifdef VBOX_WITH_NETFLT +# include "VBox/VBoxNetCfg-win.h" +# include "devguid.h" +#endif + +#include <iprt/win/iphlpapi.h> +#include <iprt/win/ntddndis.h> + +#include "LoggingNew.h" +#include "HostNetworkInterfaceImpl.h" +#include "ProgressImpl.h" +#include "VirtualBoxImpl.h" +#include "VBoxNls.h" +#include "Global.h" +#include "netif.h" +#include "ThreadTask.h" + +DECLARE_TRANSLATION_CONTEXT(NetIfWin); + +#ifdef VBOX_WITH_NETFLT +# include <Wbemidl.h> + +# include "svchlp.h" + +# include <shellapi.h> +# define INITGUID +# include <guiddef.h> +# include <devguid.h> +# include <iprt/win/objbase.h> +# include <iprt/win/setupapi.h> +# include <iprt/win/shlobj.h> +# include <cfgmgr32.h> + +# define VBOX_APP_NAME L"VirtualBox" + +static int getDefaultInterfaceIndex() +{ + PMIB_IPFORWARDTABLE pIpTable; + DWORD dwSize = sizeof(MIB_IPFORWARDTABLE) * 20; + DWORD dwRC = NO_ERROR; + int iIndex = -1; + + pIpTable = (MIB_IPFORWARDTABLE *)RTMemAlloc(dwSize); + if (GetIpForwardTable(pIpTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) + { + RTMemFree(pIpTable); + pIpTable = (MIB_IPFORWARDTABLE *)RTMemAlloc(dwSize); + if (!pIpTable) + return -1; + } + dwRC = GetIpForwardTable(pIpTable, &dwSize, 0); + if (dwRC == NO_ERROR) + { + for (unsigned int i = 0; i < pIpTable->dwNumEntries; i++) + if (pIpTable->table[i].dwForwardDest == 0) + { + iIndex = pIpTable->table[i].dwForwardIfIndex; + break; + } + } + RTMemFree(pIpTable); + return iIndex; +} + +static int collectNetIfInfo(Bstr &strName, Guid &guid, PNETIFINFO pInfo, int iDefault) +{ + RT_NOREF(strName); + + /* + * Most of the hosts probably have less than 10 adapters, + * so we'll mostly succeed from the first attempt. + */ + ULONG uBufLen = sizeof(IP_ADAPTER_ADDRESSES) * 10; + PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAlloc(uBufLen); + if (!pAddresses) + return VERR_NO_MEMORY; + DWORD dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen); + if (dwRc == ERROR_BUFFER_OVERFLOW) + { + /* Impressive! More than 10 adapters! Get more memory and try again. */ + RTMemFree(pAddresses); + pAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAlloc(uBufLen); + if (!pAddresses) + return VERR_NO_MEMORY; + dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen); + } + if (dwRc == NO_ERROR) + { + PIP_ADAPTER_ADDRESSES pAdapter; + for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next) + { + char *pszUuid = RTStrDup(pAdapter->AdapterName); + size_t len = strlen(pszUuid) - 1; + if (pszUuid[0] == '{' && pszUuid[len] == '}') + { + pszUuid[len] = 0; + if (!RTUuidCompareStr(&pInfo->Uuid, pszUuid + 1)) + { + bool fIPFound, fIPv6Found; + PIP_ADAPTER_UNICAST_ADDRESS pAddr; + fIPFound = fIPv6Found = false; + for (pAddr = pAdapter->FirstUnicastAddress; pAddr; pAddr = pAddr->Next) + { + switch (pAddr->Address.lpSockaddr->sa_family) + { + case AF_INET: + if (!fIPFound) + { + fIPFound = true; + memcpy(&pInfo->IPAddress, + &((struct sockaddr_in *)pAddr->Address.lpSockaddr)->sin_addr.s_addr, + sizeof(pInfo->IPAddress)); + } + break; + case AF_INET6: + if (!fIPv6Found) + { + fIPv6Found = true; + memcpy(&pInfo->IPv6Address, + ((struct sockaddr_in6 *)pAddr->Address.lpSockaddr)->sin6_addr.s6_addr, + sizeof(pInfo->IPv6Address)); + } + break; + } + } + PIP_ADAPTER_PREFIX pPrefix; + fIPFound = fIPv6Found = false; + for (pPrefix = pAdapter->FirstPrefix; pPrefix; pPrefix = pPrefix->Next) + { + switch (pPrefix->Address.lpSockaddr->sa_family) + { + case AF_INET: + if (!fIPFound) + { + if (pPrefix->PrefixLength <= sizeof(pInfo->IPNetMask) * 8) + { + fIPFound = true; + RTNetPrefixToMaskIPv4(pPrefix->PrefixLength, &pInfo->IPNetMask); + } + else + LogFunc(("Unexpected IPv4 prefix length of %d\n", + pPrefix->PrefixLength)); + } + break; + case AF_INET6: + if (!fIPv6Found) + { + if (pPrefix->PrefixLength <= sizeof(pInfo->IPv6NetMask) * 8) + { + fIPv6Found = true; + RTNetPrefixToMaskIPv6(pPrefix->PrefixLength, &pInfo->IPv6NetMask); + } + else + LogFunc(("Unexpected IPv6 prefix length of %d\n", + pPrefix->PrefixLength)); + } + break; + } + } + if (sizeof(pInfo->MACAddress) != pAdapter->PhysicalAddressLength) + LogFunc(("Unexpected physical address length: %u\n", pAdapter->PhysicalAddressLength)); + else + memcpy(pInfo->MACAddress.au8, pAdapter->PhysicalAddress, sizeof(pInfo->MACAddress)); + pInfo->enmMediumType = NETIF_T_ETHERNET; + pInfo->enmStatus = pAdapter->OperStatus == IfOperStatusUp ? NETIF_S_UP : NETIF_S_DOWN; + pInfo->fIsDefault = (pAdapter->IfIndex == (DWORD)iDefault); + RTStrFree(pszUuid); + break; + } + } + RTStrFree(pszUuid); + } + + ADAPTER_SETTINGS Settings; + HRESULT hr = VBoxNetCfgWinGetAdapterSettings((const GUID *)guid.raw(), &Settings); + if (hr == S_OK) + { + if (Settings.ip) + { + pInfo->IPAddress.u = Settings.ip; + pInfo->IPNetMask.u = Settings.mask; + } + pInfo->fDhcpEnabled = Settings.bDhcp; + } + else + { + pInfo->fDhcpEnabled = false; + } + } + RTMemFree(pAddresses); + + return VINF_SUCCESS; +} + +/* svc helper func */ + +struct StaticIpConfig +{ + ULONG IPAddress; + ULONG IPNetMask; +}; + +struct StaticIpV6Config +{ + char * IPV6Address; + ULONG IPV6NetMaskLength; +}; + +class NetworkInterfaceHelperClientData : public ThreadVoidData +{ +public: + NetworkInterfaceHelperClientData(){}; + ~NetworkInterfaceHelperClientData() + { + if (msgCode == SVCHlpMsg::EnableStaticIpConfigV6 && u.StaticIPV6.IPV6Address) + { + RTStrFree(u.StaticIPV6.IPV6Address); + u.StaticIPV6.IPV6Address = NULL; + } + }; + + SVCHlpMsg::Code msgCode; + /* for SVCHlpMsg::CreateHostOnlyNetworkInterface */ + Bstr name; + ComObjPtr<HostNetworkInterface> iface; + ComObjPtr<VirtualBox> ptrVBox; + /* for SVCHlpMsg::RemoveHostOnlyNetworkInterface */ + Guid guid; + + union + { + StaticIpConfig StaticIP; + StaticIpV6Config StaticIPV6; + } u; + +}; + +static HRESULT netIfNetworkInterfaceHelperClient(SVCHlpClient *aClient, + Progress *aProgress, + void *aUser, int *aVrc) +{ + LogFlowFuncEnter(); + LogFlowFunc(("aClient={%p}, aProgress={%p}, aUser={%p}\n", + aClient, aProgress, aUser)); + + AssertReturn( (aClient == NULL && aProgress == NULL && aVrc == NULL) + || (aClient != NULL && aProgress != NULL && aVrc != NULL), + E_POINTER); + AssertReturn(aUser, E_POINTER); + + NetworkInterfaceHelperClientData* d = static_cast<NetworkInterfaceHelperClientData *>(aUser); + + if (aClient == NULL) + { + /* "cleanup only" mode, just return (it will free aUser) */ + return S_OK; + } + + HRESULT rc = S_OK; + int vrc = VINF_SUCCESS; + + switch (d->msgCode) + { + case SVCHlpMsg::CreateHostOnlyNetworkInterface: + { + LogFlowFunc(("CreateHostOnlyNetworkInterface:\n")); + LogFlowFunc(("Network connection name = '%ls'\n", d->name.raw())); + + /* write message and parameters */ + vrc = aClient->write(d->msgCode); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(Utf8Str(d->name)); + if (RT_FAILURE(vrc)) break; + + /* wait for a reply */ + bool endLoop = false; + while (!endLoop) + { + SVCHlpMsg::Code reply = SVCHlpMsg::Null; + + vrc = aClient->read(reply); + if (RT_FAILURE(vrc)) break; + + switch (reply) + { + case SVCHlpMsg::CreateHostOnlyNetworkInterface_OK: + { + /* read the GUID */ + Guid guid; + Utf8Str name; + vrc = aClient->read(name); + if (RT_FAILURE(vrc)) break; + vrc = aClient->read(guid); + if (RT_FAILURE(vrc)) break; + + LogFlowFunc(("Network connection GUID = {%RTuuid}\n", guid.raw())); + + /* initialize the object returned to the caller by + * CreateHostOnlyNetworkInterface() */ + rc = d->iface->init(Bstr(name), Bstr(name), guid, HostNetworkInterfaceType_HostOnly); + if (SUCCEEDED(rc)) + { + rc = d->iface->i_setVirtualBox(d->ptrVBox); + if (SUCCEEDED(rc)) + { + rc = d->iface->updateConfig(); + if (SUCCEEDED(rc)) + rc = d->iface->i_updatePersistentConfig(); + } + } + endLoop = true; + break; + } + case SVCHlpMsg::Error: + { + /* read the error message */ + Utf8Str errMsg; + vrc = aClient->read(errMsg); + if (RT_FAILURE(vrc)) break; + + rc = E_FAIL; + d->iface->setError(E_FAIL, errMsg.c_str()); + endLoop = true; + break; + } + default: + { + endLoop = true; + rc = E_FAIL;/// @todo ComAssertMsgFailedBreak(( + //"Invalid message code %d (%08lX)\n", + //reply, reply), + //rc = E_FAIL); + } + } + } + + break; + } + case SVCHlpMsg::RemoveHostOnlyNetworkInterface: + { + LogFlowFunc(("RemoveHostOnlyNetworkInterface:\n")); + LogFlowFunc(("Network connection GUID = {%RTuuid}\n", d->guid.raw())); + + /* write message and parameters */ + vrc = aClient->write(d->msgCode); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->guid); + if (RT_FAILURE(vrc)) break; + + /* wait for a reply */ + bool endLoop = false; + while (!endLoop) + { + SVCHlpMsg::Code reply = SVCHlpMsg::Null; + + vrc = aClient->read(reply); + if (RT_FAILURE(vrc)) break; + + switch (reply) + { + case SVCHlpMsg::OK: + { + /* no parameters */ + rc = S_OK; + endLoop = true; + break; + } + case SVCHlpMsg::Error: + { + /* read the error message */ + Utf8Str errMsg; + vrc = aClient->read(errMsg); + if (RT_FAILURE(vrc)) break; + + rc = E_FAIL; + d->iface->setError(E_FAIL, errMsg.c_str()); + endLoop = true; + break; + } + default: + { + endLoop = true; + rc = E_FAIL; /// @todo ComAssertMsgFailedBreak(( + //"Invalid message code %d (%08lX)\n", + //reply, reply), + //rc = E_FAIL); + } + } + } + + break; + } + case SVCHlpMsg::EnableDynamicIpConfig: /* see usage in code */ + { + LogFlowFunc(("EnableDynamicIpConfig:\n")); + LogFlowFunc(("Network connection name = '%ls'\n", d->name.raw())); + + /* write message and parameters */ + vrc = aClient->write(d->msgCode); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->guid); + if (RT_FAILURE(vrc)) break; + + /* wait for a reply */ + bool endLoop = false; + while (!endLoop) + { + SVCHlpMsg::Code reply = SVCHlpMsg::Null; + + vrc = aClient->read(reply); + if (RT_FAILURE(vrc)) break; + + switch (reply) + { + case SVCHlpMsg::OK: + { + /* no parameters */ + rc = d->iface->updateConfig(); + endLoop = true; + break; + } + case SVCHlpMsg::Error: + { + /* read the error message */ + Utf8Str errMsg; + vrc = aClient->read(errMsg); + if (RT_FAILURE(vrc)) break; + + rc = E_FAIL; + d->iface->setError(E_FAIL, errMsg.c_str()); + endLoop = true; + break; + } + default: + { + endLoop = true; + rc = E_FAIL; /// @todo ComAssertMsgFailedBreak(( + //"Invalid message code %d (%08lX)\n", + //reply, reply), + //rc = E_FAIL); + } + } + } + + break; + } + case SVCHlpMsg::EnableStaticIpConfig: /* see usage in code */ + { + LogFlowFunc(("EnableStaticIpConfig:\n")); + LogFlowFunc(("Network connection name = '%ls'\n", d->name.raw())); + + /* write message and parameters */ + vrc = aClient->write(d->msgCode); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->guid); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->u.StaticIP.IPAddress); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->u.StaticIP.IPNetMask); + if (RT_FAILURE(vrc)) break; + + /* wait for a reply */ + bool endLoop = false; + while (!endLoop) + { + SVCHlpMsg::Code reply = SVCHlpMsg::Null; + + vrc = aClient->read(reply); + if (RT_FAILURE(vrc)) break; + + switch (reply) + { + case SVCHlpMsg::OK: + { + /* no parameters */ + rc = d->iface->updateConfig(); + endLoop = true; + break; + } + case SVCHlpMsg::Error: + { + /* read the error message */ + Utf8Str errMsg; + vrc = aClient->read(errMsg); + if (RT_FAILURE(vrc)) break; + + rc = E_FAIL; + d->iface->setError(E_FAIL, errMsg.c_str()); + endLoop = true; + break; + } + default: + { + endLoop = true; + rc = E_FAIL; /// @todo ComAssertMsgFailedBreak(( + //"Invalid message code %d (%08lX)\n", + //reply, reply), + //rc = E_FAIL); + } + } + } + + break; + } + case SVCHlpMsg::EnableStaticIpConfigV6: /* see usage in code */ + { + LogFlowFunc(("EnableStaticIpConfigV6:\n")); + LogFlowFunc(("Network connection name = '%ls'\n", d->name.raw())); + + /* write message and parameters */ + vrc = aClient->write(d->msgCode); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->guid); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->u.StaticIPV6.IPV6Address); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->u.StaticIPV6.IPV6NetMaskLength); + if (RT_FAILURE(vrc)) break; + + /* wait for a reply */ + bool endLoop = false; + while (!endLoop) + { + SVCHlpMsg::Code reply = SVCHlpMsg::Null; + + vrc = aClient->read(reply); + if (RT_FAILURE(vrc)) break; + + switch (reply) + { + case SVCHlpMsg::OK: + { + /* no parameters */ + rc = d->iface->updateConfig(); + endLoop = true; + break; + } + case SVCHlpMsg::Error: + { + /* read the error message */ + Utf8Str errMsg; + vrc = aClient->read(errMsg); + if (RT_FAILURE(vrc)) break; + + rc = E_FAIL; + d->iface->setError(E_FAIL, errMsg.c_str()); + endLoop = true; + break; + } + default: + { + endLoop = true; + rc = E_FAIL; /// @todo ComAssertMsgFailedBreak(( + //"Invalid message code %d (%08lX)\n", + //reply, reply), + //rc = E_FAIL); + } + } + } + + break; + } + case SVCHlpMsg::DhcpRediscover: /* see usage in code */ + { + LogFlowFunc(("DhcpRediscover:\n")); + LogFlowFunc(("Network connection name = '%ls'\n", d->name.raw())); + + /* write message and parameters */ + vrc = aClient->write(d->msgCode); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(d->guid); + if (RT_FAILURE(vrc)) break; + + /* wait for a reply */ + bool endLoop = false; + while (!endLoop) + { + SVCHlpMsg::Code reply = SVCHlpMsg::Null; + + vrc = aClient->read(reply); + if (RT_FAILURE(vrc)) break; + + switch (reply) + { + case SVCHlpMsg::OK: + { + /* no parameters */ + rc = d->iface->updateConfig(); + endLoop = true; + break; + } + case SVCHlpMsg::Error: + { + /* read the error message */ + Utf8Str errMsg; + vrc = aClient->read(errMsg); + if (RT_FAILURE(vrc)) break; + + rc = E_FAIL; + d->iface->setError(E_FAIL, errMsg.c_str()); + endLoop = true; + break; + } + default: + { + endLoop = true; + rc = E_FAIL; /// @todo ComAssertMsgFailedBreak(( + //"Invalid message code %d (%08lX)\n", + //reply, reply), + //rc = E_FAIL); + } + } + } + + break; + } + default: + rc = E_FAIL; /// @todo ComAssertMsgFailedBreak(( +// "Invalid message code %d (%08lX)\n", +// d->msgCode, d->msgCode), +// rc = E_FAIL); + } + + if (aVrc) + *aVrc = vrc; + + LogFlowFunc(("rc=0x%08X, vrc=%Rrc\n", rc, vrc)); + LogFlowFuncLeave(); + return rc; +} + + +int netIfNetworkInterfaceHelperServer(SVCHlpClient *aClient, + SVCHlpMsg::Code aMsgCode) +{ + LogFlowFuncEnter(); + LogFlowFunc(("aClient={%p}, aMsgCode=%d\n", aClient, aMsgCode)); + + AssertReturn(aClient, VERR_INVALID_POINTER); + + int vrc = VINF_SUCCESS; + HRESULT hrc; + + switch (aMsgCode) + { + case SVCHlpMsg::CreateHostOnlyNetworkInterface: + { + LogFlowFunc(("CreateHostOnlyNetworkInterface:\n")); + + Utf8Str desiredName; + vrc = aClient->read(desiredName); + if (RT_FAILURE(vrc)) break; + + Guid guid; + Utf8Str errMsg; + Bstr name; + Bstr bstrErr; + +#ifdef VBOXNETCFG_DELAYEDRENAME + Bstr devId; + hrc = VBoxNetCfgWinCreateHostOnlyNetworkInterface(NULL, false, Bstr(desiredName).raw(), guid.asOutParam(), devId.asOutParam(), + bstrErr.asOutParam()); +#else /* !VBOXNETCFG_DELAYEDRENAME */ + hrc = VBoxNetCfgWinCreateHostOnlyNetworkInterface(NULL, false, Bstr(desiredName).raw(), guid.asOutParam(), name.asOutParam(), + bstrErr.asOutParam()); +#endif /* !VBOXNETCFG_DELAYEDRENAME */ + + if (hrc == S_OK) + { + ULONG ip, mask; + hrc = VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(&ip, &mask); + if (hrc == S_OK) + { + /* ip returned by VBoxNetCfgWinGenHostOnlyNetworkNetworkIp is a network ip, + * i.e. 192.168.xxx.0, assign 192.168.xxx.1 for the hostonly adapter */ + ip = ip | (1 << 24); + hrc = VBoxNetCfgWinEnableStaticIpConfig((const GUID*)guid.raw(), ip, mask); + if (hrc != S_OK) + LogRel(("VBoxNetCfgWinEnableStaticIpConfig failed (0x%x)\n", hrc)); + } + else + LogRel(("VBoxNetCfgWinGenHostOnlyNetworkNetworkIp failed (0x%x)\n", hrc)); +#ifdef VBOXNETCFG_DELAYEDRENAME + hrc = VBoxNetCfgWinRenameHostOnlyConnection((const GUID*)guid.raw(), devId.raw(), name.asOutParam()); + if (hrc != S_OK) + LogRel(("VBoxNetCfgWinRenameHostOnlyConnection failed, error = 0x%x", hrc)); +#endif /* VBOXNETCFG_DELAYEDRENAME */ + /* write success followed by GUID */ + vrc = aClient->write(SVCHlpMsg::CreateHostOnlyNetworkInterface_OK); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(Utf8Str(name)); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(guid); + if (RT_FAILURE(vrc)) break; + } + else + { + vrc = VERR_GENERAL_FAILURE; + errMsg = Utf8Str(bstrErr); + /* write failure followed by error message */ + if (errMsg.isEmpty()) + errMsg = Utf8StrFmt("Unspecified error (%Rrc)", vrc); + vrc = aClient->write(SVCHlpMsg::Error); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(errMsg); + if (RT_FAILURE(vrc)) break; + } + + break; + } + case SVCHlpMsg::RemoveHostOnlyNetworkInterface: + { + LogFlowFunc(("RemoveHostOnlyNetworkInterface:\n")); + + Guid guid; + Bstr bstrErr; + + vrc = aClient->read(guid); + if (RT_FAILURE(vrc)) break; + + Utf8Str errMsg; + hrc = VBoxNetCfgWinRemoveHostOnlyNetworkInterface((const GUID*)guid.raw(), bstrErr.asOutParam()); + + if (hrc == S_OK) + { + /* write parameter-less success */ + vrc = aClient->write(SVCHlpMsg::OK); + if (RT_FAILURE(vrc)) break; + } + else + { + vrc = VERR_GENERAL_FAILURE; + errMsg = Utf8Str(bstrErr); + /* write failure followed by error message */ + if (errMsg.isEmpty()) + errMsg = Utf8StrFmt("Unspecified error (%Rrc)", vrc); + vrc = aClient->write(SVCHlpMsg::Error); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(errMsg); + if (RT_FAILURE(vrc)) break; + } + + break; + } + case SVCHlpMsg::EnableStaticIpConfigV6: + { + LogFlowFunc(("EnableStaticIpConfigV6:\n")); + + Guid guid; + Utf8Str ipV6; + ULONG maskLengthV6; + vrc = aClient->read(guid); + if (RT_FAILURE(vrc)) break; + vrc = aClient->read(ipV6); + if (RT_FAILURE(vrc)) break; + vrc = aClient->read(maskLengthV6); + if (RT_FAILURE(vrc)) break; + + Utf8Str errMsg; + vrc = VERR_NOT_IMPLEMENTED; + + if (RT_SUCCESS(vrc)) + { + /* write success followed by GUID */ + vrc = aClient->write(SVCHlpMsg::OK); + if (RT_FAILURE(vrc)) break; + } + else + { + /* write failure followed by error message */ + if (errMsg.isEmpty()) + errMsg = Utf8StrFmt("Unspecified error (%Rrc)", vrc); + vrc = aClient->write(SVCHlpMsg::Error); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(errMsg); + if (RT_FAILURE(vrc)) break; + } + + break; + } + case SVCHlpMsg::EnableStaticIpConfig: + { + LogFlowFunc(("EnableStaticIpConfig:\n")); + + Guid guid; + ULONG ip, mask; + vrc = aClient->read(guid); + if (RT_FAILURE(vrc)) break; + vrc = aClient->read(ip); + if (RT_FAILURE(vrc)) break; + vrc = aClient->read(mask); + if (RT_FAILURE(vrc)) break; + + Utf8Str errMsg; + hrc = VBoxNetCfgWinEnableStaticIpConfig((const GUID *)guid.raw(), ip, mask); + + if (hrc == S_OK) + { + /* write success followed by GUID */ + vrc = aClient->write(SVCHlpMsg::OK); + if (RT_FAILURE(vrc)) break; + } + else + { + vrc = VERR_GENERAL_FAILURE; + /* write failure followed by error message */ + if (errMsg.isEmpty()) + errMsg = Utf8StrFmt("Unspecified error (%Rrc)", vrc); + vrc = aClient->write(SVCHlpMsg::Error); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(errMsg); + if (RT_FAILURE(vrc)) break; + } + + break; + } + case SVCHlpMsg::EnableDynamicIpConfig: + { + LogFlowFunc(("EnableDynamicIpConfig:\n")); + + Guid guid; + vrc = aClient->read(guid); + if (RT_FAILURE(vrc)) break; + + Utf8Str errMsg; + hrc = VBoxNetCfgWinEnableDynamicIpConfig((const GUID *)guid.raw()); + + if (hrc == S_OK) + { + /* write success followed by GUID */ + vrc = aClient->write(SVCHlpMsg::OK); + if (RT_FAILURE(vrc)) break; + } + else + { + vrc = VERR_GENERAL_FAILURE; + /* write failure followed by error message */ + if (errMsg.isEmpty()) + errMsg = Utf8StrFmt("Unspecified error (%Rrc)", vrc); + vrc = aClient->write(SVCHlpMsg::Error); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(errMsg); + if (RT_FAILURE(vrc)) break; + } + + break; + } + case SVCHlpMsg::DhcpRediscover: + { + LogFlowFunc(("DhcpRediscover:\n")); + + Guid guid; + vrc = aClient->read(guid); + if (RT_FAILURE(vrc)) break; + + Utf8Str errMsg; + hrc = VBoxNetCfgWinDhcpRediscover((const GUID *)guid.raw()); + + if (hrc == S_OK) + { + /* write success followed by GUID */ + vrc = aClient->write(SVCHlpMsg::OK); + if (RT_FAILURE(vrc)) break; + } + else + { + vrc = VERR_GENERAL_FAILURE; + /* write failure followed by error message */ + if (errMsg.isEmpty()) + errMsg = Utf8StrFmt("Unspecified error (%Rrc)", vrc); + vrc = aClient->write(SVCHlpMsg::Error); + if (RT_FAILURE(vrc)) break; + vrc = aClient->write(errMsg); + if (RT_FAILURE(vrc)) break; + } + + break; + } + default: + AssertMsgFailedBreakStmt( + ("Invalid message code %d (%08lX)\n", aMsgCode, aMsgCode), + VERR_GENERAL_FAILURE); + } + + LogFlowFunc(("vrc=%Rrc\n", vrc)); + LogFlowFuncLeave(); + return vrc; +} + +/** @todo REMOVE. OBSOLETE NOW. */ +/** + * Returns TRUE if the Windows version is 6.0 or greater (i.e. it's Vista and + * later OSes) and it has the UAC (User Account Control) feature enabled. + */ +static BOOL IsUACEnabled() +{ + LONG rc = 0; + + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + rc = GetVersionEx((OSVERSIONINFO *) &info); + AssertReturn(rc != 0, FALSE); + + LogFlowFunc(("dwMajorVersion=%d, dwMinorVersion=%d\n", + info.dwMajorVersion, info.dwMinorVersion)); + + /* we are interested only in Vista (and newer versions...). In all + * earlier versions UAC is not present. */ + if (info.dwMajorVersion < 6) + return FALSE; + + /* the default EnableLUA value is 1 (Enabled) */ + DWORD dwEnableLUA = 1; + + HKEY hKey; + rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", + 0, KEY_QUERY_VALUE, &hKey); + + Assert(rc == ERROR_SUCCESS || rc == ERROR_PATH_NOT_FOUND); + if (rc == ERROR_SUCCESS) + { + + DWORD cbEnableLUA = sizeof(dwEnableLUA); + rc = RegQueryValueExA(hKey, "EnableLUA", NULL, NULL, + (LPBYTE) &dwEnableLUA, &cbEnableLUA); + + RegCloseKey(hKey); + + Assert(rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND); + } + + LogFlowFunc(("rc=%d, dwEnableLUA=%d\n", rc, dwEnableLUA)); + + return dwEnableLUA == 1; +} + +/* end */ + +static int vboxNetWinAddComponent(std::list<ComObjPtr<HostNetworkInterface> > * pPist, + INetCfgComponent * pncc, HostNetworkInterfaceType enmType, + int iDefaultInterface) +{ + LPWSTR lpszName; + GUID IfGuid; + HRESULT hr; + int rc = VERR_GENERAL_FAILURE; + + hr = pncc->GetDisplayName(&lpszName); + Assert(hr == S_OK); + if (hr == S_OK) + { + Bstr name(lpszName); + + hr = pncc->GetInstanceGuid(&IfGuid); + Assert(hr == S_OK); + if (hr == S_OK) + { + Guid guidIfCopy(IfGuid); + NETIFINFO Info; + RT_ZERO(Info); + Info.Uuid = *guidIfCopy.raw(); + rc = collectNetIfInfo(name, guidIfCopy, &Info, iDefaultInterface); + if (RT_FAILURE(rc)) + LogRelFunc(("collectNetIfInfo() -> %Rrc\n", rc)); + LogFunc(("adding %ls\n", lpszName)); + /* create a new object and add it to the list */ + ComObjPtr<HostNetworkInterface> iface; + iface.createObject(); + /* remove the curly bracket at the end */ + rc = iface->init(name, enmType, &Info); + if (SUCCEEDED(rc)) + { + if (Info.fIsDefault) + pPist->push_front(iface); + else + pPist->push_back(iface); + } + else + { + LogRelFunc(("HostNetworkInterface::init() -> %Rrc\n", rc)); + AssertComRC(rc); + } + } + else + LogRelFunc(("failed to get device instance GUID (0x%x)\n", hr)); + CoTaskMemFree(lpszName); + } + else + LogRelFunc(("failed to get device display name (0x%x)\n", hr)); + + return rc; +} + +#endif /* VBOX_WITH_NETFLT */ + + +static int netIfListHostAdapters(INetCfg *pNc, std::list<ComObjPtr<HostNetworkInterface> > &list) +{ +#ifndef VBOX_WITH_NETFLT + /* VBoxNetAdp is available only when VBOX_WITH_NETFLT is enabled */ + return VERR_NOT_IMPLEMENTED; +#else /* # if defined VBOX_WITH_NETFLT */ + INetCfgComponent *pMpNcc; + HRESULT hr; + IEnumNetCfgComponent *pEnumComponent; + + hr = pNc->EnumComponents(&GUID_DEVCLASS_NET, &pEnumComponent); + if (hr == S_OK) + { + while ((hr = pEnumComponent->Next(1, &pMpNcc, NULL)) == S_OK) + { + LPWSTR pwszName; + ULONG uComponentStatus; + hr = pMpNcc->GetDisplayName(&pwszName); + if (hr == S_OK) + LogFunc(("%ls\n", pwszName)); + else + LogRelFunc(("failed to get device display name (0x%x)\n", hr)); + hr = pMpNcc->GetDeviceStatus(&uComponentStatus); + if (hr == S_OK) + { + if (uComponentStatus == 0) + { + LPWSTR pId; + hr = pMpNcc->GetId(&pId); + Assert(hr == S_OK); + if (hr == S_OK) + { + LogFunc(("id = %ls\n", pId)); + if (!_wcsnicmp(pId, L"sun_VBoxNetAdp", sizeof(L"sun_VBoxNetAdp")/2)) + { + vboxNetWinAddComponent(&list, pMpNcc, HostNetworkInterfaceType_HostOnly, -1); + } + CoTaskMemFree(pId); + } + else + LogRelFunc(("failed to get device id (0x%x)\n", hr)); + } + } + else + LogRelFunc(("failed to get device status (0x%x)\n", hr)); + pMpNcc->Release(); + } + Assert(hr == S_OK || hr == S_FALSE); + + pEnumComponent->Release(); + } + else + LogRelFunc(("EnumComponents error (0x%x)\n", hr)); +#endif /* # if defined VBOX_WITH_NETFLT */ + return VINF_SUCCESS; +} + +int NetIfGetConfig(HostNetworkInterface * pIf, NETIFINFO *pInfo) +{ +#ifndef VBOX_WITH_NETFLT + return VERR_NOT_IMPLEMENTED; +#else + Bstr name; + HRESULT hr = pIf->COMGETTER(Name)(name.asOutParam()); + if (hr == S_OK) + { + Bstr IfGuid; + hr = pIf->COMGETTER(Id)(IfGuid.asOutParam()); + Assert(hr == S_OK); + if (hr == S_OK) + { + memset(pInfo, 0, sizeof(NETIFINFO)); + Guid guid(IfGuid); + pInfo->Uuid = *(guid.raw()); + + return collectNetIfInfo(name, guid, pInfo, getDefaultInterfaceIndex()); + } + } + return VERR_GENERAL_FAILURE; +#endif +} + +int NetIfGetConfigByName(PNETIFINFO) +{ + return VERR_NOT_IMPLEMENTED; +} + +/** + * Obtain the current state of the interface. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param penmState Where to store the retrieved state. + */ +int NetIfGetState(const char *pcszIfName, NETIFSTATUS *penmState) +{ + RT_NOREF(pcszIfName, penmState); + return VERR_NOT_IMPLEMENTED; +} + +/** + * Retrieve the physical link speed in megabits per second. If the interface is + * not up or otherwise unavailable the zero speed is returned. + * + * @returns VBox status code. + * + * @param pcszIfName Interface name. + * @param puMbits Where to store the link speed. + */ +int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits) +{ + RT_NOREF(pcszIfName, puMbits); + return VERR_NOT_IMPLEMENTED; +} + +int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVirtualBox, + IHostNetworkInterface **aHostNetworkInterface, + IProgress **aProgress, + IN_BSTR aName) +{ +#ifndef VBOX_WITH_NETFLT + return VERR_NOT_IMPLEMENTED; +#else + /* create a progress object */ + ComObjPtr<Progress> progress; + HRESULT hrc = progress.createObject(); + AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc)); + + ComPtr<IHost> host; + hrc = pVirtualBox->COMGETTER(Host)(host.asOutParam()); + if (SUCCEEDED(hrc)) + { + hrc = progress->init(pVirtualBox, host, + Bstr(NetIfWin::tr("Creating host only network interface")).raw(), + FALSE /* aCancelable */); + if (SUCCEEDED(hrc)) + { + progress.queryInterfaceTo(aProgress); + + /* create a new uninitialized host interface object */ + ComObjPtr<HostNetworkInterface> iface; + iface.createObject(); + iface.queryInterfaceTo(aHostNetworkInterface); + + /* create the networkInterfaceHelperClient() argument */ + NetworkInterfaceHelperClientData* d = new NetworkInterfaceHelperClientData(); + + d->msgCode = SVCHlpMsg::CreateHostOnlyNetworkInterface; + d->name = aName; + d->iface = iface; + d->ptrVBox = pVirtualBox; + + hrc = pVirtualBox->i_startSVCHelperClient(IsUACEnabled() == TRUE /* aPrivileged */, + netIfNetworkInterfaceHelperClient, + static_cast<void *>(d), + progress); + /* d is now owned by netIfNetworkInterfaceHelperClient(), no need to delete one here */ + + } + } + + return Global::vboxStatusCodeFromCOM(hrc); +#endif +} + +int NetIfRemoveHostOnlyNetworkInterface(VirtualBox *pVirtualBox, const Guid &aId, + IProgress **aProgress) +{ +#ifndef VBOX_WITH_NETFLT + return VERR_NOT_IMPLEMENTED; +#else + /* create a progress object */ + ComObjPtr<Progress> progress; + HRESULT hrc = progress.createObject(); + AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc)); + + ComPtr<IHost> host; + hrc = pVirtualBox->COMGETTER(Host)(host.asOutParam()); + if (SUCCEEDED(hrc)) + { + hrc = progress->init(pVirtualBox, host, + Bstr(NetIfWin::tr("Removing host network interface")).raw(), + FALSE /* aCancelable */); + if (SUCCEEDED(hrc)) + { + progress.queryInterfaceTo(aProgress); + + /* create the networkInterfaceHelperClient() argument */ + NetworkInterfaceHelperClientData* d = new NetworkInterfaceHelperClientData(); + + d->msgCode = SVCHlpMsg::RemoveHostOnlyNetworkInterface; + d->guid = aId; + + hrc = pVirtualBox->i_startSVCHelperClient(IsUACEnabled() == TRUE /* aPrivileged */, + netIfNetworkInterfaceHelperClient, + static_cast<void *>(d), + progress); + /* d is now owned by netIfNetworkInterfaceHelperClient(), no need to delete one here */ + + } + } + + return Global::vboxStatusCodeFromCOM(hrc); +#endif +} + +int NetIfEnableStaticIpConfig(VirtualBox *pVBox, HostNetworkInterface * pIf, ULONG aOldIp, ULONG ip, ULONG mask) +{ + RT_NOREF(aOldIp); +#ifndef VBOX_WITH_NETFLT + return VERR_NOT_IMPLEMENTED; +#else + Bstr guid; + HRESULT rc = pIf->COMGETTER(Id)(guid.asOutParam()); + if (SUCCEEDED(rc)) + { +// ComPtr<VirtualBox> pVBox; +// rc = pIf->getVirtualBox(pVBox.asOutParam()); +// if (SUCCEEDED(rc)) + { + /* create a progress object */ + ComObjPtr<Progress> progress; + progress.createObject(); +// ComPtr<IHost> host; +// HRESULT rc = pVBox->COMGETTER(Host)(host.asOutParam()); +// if (SUCCEEDED(rc)) + { + rc = progress->init(pVBox, (IHostNetworkInterface*)pIf, + Bstr(NetIfWin::tr("Enabling Dynamic Ip Configuration")).raw(), + FALSE /* aCancelable */); + if (SUCCEEDED(rc)) + { + if (FAILED(rc)) return rc; +// progress.queryInterfaceTo(aProgress); + + /* create the networkInterfaceHelperClient() argument */ + NetworkInterfaceHelperClientData* d = new NetworkInterfaceHelperClientData(); + + d->msgCode = SVCHlpMsg::EnableStaticIpConfig; + d->guid = Guid(guid); + d->iface = pIf; + d->u.StaticIP.IPAddress = ip; + d->u.StaticIP.IPNetMask = mask; + + rc = pVBox->i_startSVCHelperClient(IsUACEnabled() == TRUE /* aPrivileged */, + netIfNetworkInterfaceHelperClient, + static_cast<void *>(d), + progress); + /* d is now owned by netIfNetworkInterfaceHelperClient(), no need to delete one here */ + + if (SUCCEEDED(rc)) + { + progress->WaitForCompletion(-1); + } + } + } + } + } + + return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; +#endif +} + +int NetIfEnableStaticIpConfigV6(VirtualBox *pVBox, HostNetworkInterface * pIf, const Utf8Str &aOldIPV6Address, + const Utf8Str &aIPV6Address, ULONG aIPV6MaskPrefixLength) +{ + RT_NOREF(aOldIPV6Address); +#ifndef VBOX_WITH_NETFLT + return VERR_NOT_IMPLEMENTED; +#else + Bstr guid; + HRESULT rc = pIf->COMGETTER(Id)(guid.asOutParam()); + if (SUCCEEDED(rc)) + { +// ComPtr<VirtualBox> pVBox; +// rc = pIf->getVirtualBox(pVBox.asOutParam()); +// if (SUCCEEDED(rc)) + { + /* create a progress object */ + ComObjPtr<Progress> progress; + progress.createObject(); +// ComPtr<IHost> host; +// HRESULT rc = pVBox->COMGETTER(Host)(host.asOutParam()); +// if (SUCCEEDED(rc)) + { + rc = progress->init(pVBox, (IHostNetworkInterface*)pIf, + Bstr(NetIfWin::tr("Enabling Dynamic Ip Configuration")).raw(), + FALSE /* aCancelable */); + if (SUCCEEDED(rc)) + { + if (FAILED(rc)) return rc; +// progress.queryInterfaceTo(aProgress); + + /* create the networkInterfaceHelperClient() argument */ + NetworkInterfaceHelperClientData* d = new NetworkInterfaceHelperClientData(); + + d->msgCode = SVCHlpMsg::EnableStaticIpConfigV6; + d->guid = guid; + d->iface = pIf; + d->u.StaticIPV6.IPV6Address = RTStrDup(aIPV6Address.c_str()); + d->u.StaticIPV6.IPV6NetMaskLength = aIPV6MaskPrefixLength; + + rc = pVBox->i_startSVCHelperClient(IsUACEnabled() == TRUE /* aPrivileged */, + netIfNetworkInterfaceHelperClient, + static_cast<void *>(d), + progress); + /* d is now owned by netIfNetworkInterfaceHelperClient(), no need to delete one here */ + + if (SUCCEEDED(rc)) + { + progress->WaitForCompletion(-1); + } + } + } + } + } + + return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; +#endif +} + +int NetIfEnableDynamicIpConfig(VirtualBox *pVBox, HostNetworkInterface * pIf) +{ +#ifndef VBOX_WITH_NETFLT + return VERR_NOT_IMPLEMENTED; +#else + HRESULT rc; + Bstr guid; + rc = pIf->COMGETTER(Id)(guid.asOutParam()); + if (SUCCEEDED(rc)) + { +// ComPtr<VirtualBox> pVBox; +// rc = pIf->getVirtualBox(pVBox.asOutParam()); +// if (SUCCEEDED(rc)) + { + /* create a progress object */ + ComObjPtr<Progress> progress; + progress.createObject(); +// ComPtr<IHost> host; +// HRESULT rc = pVBox->COMGETTER(Host)(host.asOutParam()); +// if (SUCCEEDED(rc)) + { + rc = progress->init(pVBox, (IHostNetworkInterface*)pIf, + Bstr(NetIfWin::tr("Enabling Dynamic Ip Configuration")).raw(), + FALSE /* aCancelable */); + if (SUCCEEDED(rc)) + { + if (FAILED(rc)) return rc; +// progress.queryInterfaceTo(aProgress); + + /* create the networkInterfaceHelperClient() argument */ + NetworkInterfaceHelperClientData* d = new NetworkInterfaceHelperClientData(); + + d->msgCode = SVCHlpMsg::EnableDynamicIpConfig; + d->guid = guid; + d->iface = pIf; + + rc = pVBox->i_startSVCHelperClient(IsUACEnabled() == TRUE /* aPrivileged */, + netIfNetworkInterfaceHelperClient, + static_cast<void *>(d), + progress); + /* d is now owned by netIfNetworkInterfaceHelperClient(), no need to delete one here */ + + if (SUCCEEDED(rc)) + { + progress->WaitForCompletion(-1); + } + } + } + } + } + + return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; +#endif +} + +int NetIfDhcpRediscover(VirtualBox *pVBox, HostNetworkInterface * pIf) +{ +#ifndef VBOX_WITH_NETFLT + return VERR_NOT_IMPLEMENTED; +#else + HRESULT rc; + Bstr guid; + rc = pIf->COMGETTER(Id)(guid.asOutParam()); + if (SUCCEEDED(rc)) + { +// ComPtr<VirtualBox> pVBox; +// rc = pIf->getVirtualBox(pVBox.asOutParam()); +// if (SUCCEEDED(rc)) + { + /* create a progress object */ + ComObjPtr<Progress> progress; + progress.createObject(); +// ComPtr<IHost> host; +// HRESULT rc = pVBox->COMGETTER(Host)(host.asOutParam()); +// if (SUCCEEDED(rc)) + { + rc = progress->init(pVBox, (IHostNetworkInterface*)pIf, + Bstr(NetIfWin::tr("Enabling Dynamic Ip Configuration")).raw(), + FALSE /* aCancelable */); + if (SUCCEEDED(rc)) + { + if (FAILED(rc)) return rc; +// progress.queryInterfaceTo(aProgress); + + /* create the networkInterfaceHelperClient() argument */ + NetworkInterfaceHelperClientData* d = new NetworkInterfaceHelperClientData(); + + d->msgCode = SVCHlpMsg::DhcpRediscover; + d->guid = guid; + d->iface = pIf; + + rc = pVBox->i_startSVCHelperClient(IsUACEnabled() == TRUE /* aPrivileged */, + netIfNetworkInterfaceHelperClient, + static_cast<void *>(d), + progress); + /* d is now owned by netIfNetworkInterfaceHelperClient(), no need to delete one here */ + + if (SUCCEEDED(rc)) + { + progress->WaitForCompletion(-1); + } + } + } + } + } + + return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; +#endif +} + + +#define netIfLog LogFunc + +struct BoundAdapter +{ + LPWSTR pName; + LPWSTR pHwId; + RTUUID guid; + PIP_ADAPTER_ADDRESSES pAdapter; + BOOL fWireless; +}; + +static int netIfGetUnboundHostOnlyAdapters(INetCfg *pNetCfg, std::list<BoundAdapter> &adapters) +{ + INetCfgComponent *pMiniport; + HRESULT hr; + IEnumNetCfgComponent *pEnumComponent; + + if ((hr = pNetCfg->EnumComponents(&GUID_DEVCLASS_NET, &pEnumComponent)) != S_OK) + LogRelFunc(("failed to enumerate network adapter components (0x%x)\n", hr)); + else + { + while ((hr = pEnumComponent->Next(1, &pMiniport, NULL)) == S_OK) + { + GUID guid; + ULONG uComponentStatus; + struct BoundAdapter adapter; + memset(&adapter, 0, sizeof(adapter)); + if ((hr = pMiniport->GetDisplayName(&adapter.pName)) != S_OK) + LogRelFunc(("failed to get device display name (0x%x)\n", hr)); + else if ((hr = pMiniport->GetDeviceStatus(&uComponentStatus)) != S_OK) + netIfLog(("failed to get device status (0x%x)\n", hr)); + else if (uComponentStatus != 0) + netIfLog(("wrong device status (0x%x)\n", uComponentStatus)); + else if ((hr = pMiniport->GetId(&adapter.pHwId)) != S_OK) + LogRelFunc(("failed to get device id (0x%x)\n", hr)); + else if (_wcsnicmp(adapter.pHwId, L"sun_VBoxNetAdp", sizeof(L"sun_VBoxNetAdp")/2)) + netIfLog(("not host-only id = %ls, ignored\n", adapter.pHwId)); + else if ((hr = pMiniport->GetInstanceGuid(&guid)) != S_OK) + LogRelFunc(("failed to get instance id (0x%x)\n", hr)); + else + { + adapter.guid = *(Guid(guid).raw()); + netIfLog(("guid=%RTuuid, name=%ls id = %ls\n", &adapter.guid, adapter.pName, adapter.pHwId)); + adapters.push_back(adapter); + adapter.pName = adapter.pHwId = NULL; /* do not free, will be done later */ + } + if (adapter.pHwId) + CoTaskMemFree(adapter.pHwId); + if (adapter.pName) + CoTaskMemFree(adapter.pName); + pMiniport->Release(); + } + Assert(hr == S_OK || hr == S_FALSE); + + pEnumComponent->Release(); + } + netIfLog(("return\n")); + return VINF_SUCCESS; +} + +#define DEVNAME_PREFIX L"\\\\.\\" + +static BOOL netIfIsWireless(INetCfgComponent *pAdapter) +{ + bool fWireless = false; + + /* Construct a device name. */ + LPWSTR pwszBindName = NULL; + HRESULT hrc = pAdapter->GetBindName(&pwszBindName); + if (SUCCEEDED(hrc) && pwszBindName) + { + WCHAR wszFileName[MAX_PATH]; + int vrc = RTUtf16Copy(wszFileName, MAX_PATH, DEVNAME_PREFIX); + if (RT_SUCCESS(vrc)) + vrc = RTUtf16Cat(wszFileName, MAX_PATH, pwszBindName); + if (RT_SUCCESS(vrc)) + { + /* open the device */ + HANDLE hDevice = CreateFileW(wszFileName, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hDevice != INVALID_HANDLE_VALUE) + { + /* now issue the OID_GEN_PHYSICAL_MEDIUM query */ + DWORD Oid = OID_GEN_PHYSICAL_MEDIUM; + NDIS_PHYSICAL_MEDIUM PhMedium = NdisPhysicalMediumUnspecified; + DWORD cbResultIgn = 0; + if (DeviceIoControl(hDevice, + IOCTL_NDIS_QUERY_GLOBAL_STATS, + &Oid, + sizeof(Oid), + &PhMedium, + sizeof(PhMedium), + &cbResultIgn, + NULL)) + { + /* that was simple, now examine PhMedium */ + fWireless = PhMedium == NdisPhysicalMediumWirelessWan + || PhMedium == NdisPhysicalMediumWirelessLan + || PhMedium == NdisPhysicalMediumNative802_11 + || PhMedium == NdisPhysicalMediumBluetooth; + } + else + { + DWORD rcWin = GetLastError(); + LogRel(("netIfIsWireless: DeviceIoControl to '%ls' failed with rcWin=%u (%#x) - ignoring\n", + wszFileName, rcWin, rcWin)); + Assert(rcWin == ERROR_INVALID_PARAMETER || rcWin == ERROR_NOT_SUPPORTED || rcWin == ERROR_BAD_COMMAND); + } + CloseHandle(hDevice); + } + else + { + DWORD rcWin = GetLastError(); +#if 0 /* bird: Triggers on each VBoxSVC startup so, disabled. Whoever want it, can enable using DEBUG_xxxx. */ + AssertLogRelMsgFailed(("netIfIsWireless: CreateFile on '%ls' failed with rcWin=%u (%#x) - ignoring\n", + wszFileName, rcWin, rcWin)); +#else + LogRel(("netIfIsWireless: CreateFile on '%ls' failed with rcWin=%u (%#x) - ignoring\n", + wszFileName, rcWin, rcWin)); +#endif + } + } + CoTaskMemFree(pwszBindName); + } + else + LogRel(("netIfIsWireless: GetBindName failed hrc=%Rhrc\n", hrc)); + + return fWireless; +} + +static HRESULT netIfGetBoundAdapters(std::list<BoundAdapter> &boundAdapters) +{ + INetCfg *pNetCfg = NULL; + INetCfgComponent *pFilter; + LPWSTR lpszApp; + HRESULT hr; + + netIfLog(("building the list of interfaces\n")); + /* we are using the INetCfg API for getting the list of miniports */ + hr = VBoxNetCfgWinQueryINetCfg(&pNetCfg, FALSE, + VBOX_APP_NAME, + 10000, + &lpszApp); + Assert(hr == S_OK); + if (hr != S_OK) + { + LogRelFunc(("failed to query INetCfg (0x%x)\n", hr)); + return hr; + } + + if ((hr = pNetCfg->FindComponent(L"oracle_VBoxNetLwf", &pFilter)) != S_OK + /* fall back to NDIS5 miniport lookup */ + && (hr = pNetCfg->FindComponent(L"sun_VBoxNetFlt", &pFilter))) + LogRelFunc(("could not find either 'oracle_VBoxNetLwf' or 'sun_VBoxNetFlt' components (0x%x)\n", hr)); + else + { + INetCfgComponentBindings *pFilterBindings; + if ((pFilter->QueryInterface(IID_INetCfgComponentBindings, (PVOID*)&pFilterBindings)) != S_OK) + LogRelFunc(("failed to query INetCfgComponentBindings (0x%x)\n", hr)); + else + { + IEnumNetCfgBindingPath *pEnumBp; + INetCfgBindingPath *pBp; + if ((pFilterBindings->EnumBindingPaths(EBP_BELOW, &pEnumBp)) != S_OK) + LogRelFunc(("failed to enumerate binding paths (0x%x)\n", hr)); + else + { + pEnumBp->Reset(); + while ((hr = pEnumBp->Next(1, &pBp, NULL)) == S_OK) + { + IEnumNetCfgBindingInterface *pEnumBi; + INetCfgBindingInterface *pBi; + if (pBp->IsEnabled() != S_OK) + { + /** @todo some id of disabled path could be useful. */ + netIfLog(("INetCfgBindingPath is disabled (0x%x)\n", hr)); + pBp->Release(); + continue; + } + if ((pBp->EnumBindingInterfaces(&pEnumBi)) != S_OK) + LogRelFunc(("failed to enumerate binding interfaces (0x%x)\n", hr)); + else + { + hr = pEnumBi->Reset(); + while ((hr = pEnumBi->Next(1, &pBi, NULL)) == S_OK) + { + INetCfgComponent *pAdapter; + if ((hr = pBi->GetLowerComponent(&pAdapter)) != S_OK) + LogRelFunc(("failed to get lower component (0x%x)\n", hr)); + else + { + LPWSTR pwszName = NULL; + if ((hr = pAdapter->GetDisplayName(&pwszName)) != S_OK) + LogRelFunc(("failed to get display name (0x%x)\n", hr)); + else + { + ULONG uStatus; + DWORD dwChars; + if ((hr = pAdapter->GetDeviceStatus(&uStatus)) != S_OK) + netIfLog(("%ls: failed to get device status (0x%x)\n", + pwszName, hr)); + else if ((hr = pAdapter->GetCharacteristics(&dwChars)) != S_OK) + netIfLog(("%ls: failed to get device characteristics (0x%x)\n", + pwszName, hr)); + else if (uStatus != 0) + netIfLog(("%ls: wrong status 0x%x\n", + pwszName, uStatus)); + else if (dwChars & NCF_HIDDEN) + netIfLog(("%ls: wrong characteristics 0x%x\n", + pwszName, dwChars)); + else + { + GUID guid; + LPWSTR pwszHwId = NULL; + if ((hr = pAdapter->GetId(&pwszHwId)) != S_OK) + LogRelFunc(("%ls: failed to get hardware id (0x%x)\n", + pwszName, hr)); + else if (!_wcsnicmp(pwszHwId, L"sun_VBoxNetAdp", sizeof(L"sun_VBoxNetAdp")/2)) + netIfLog(("host-only adapter %ls, ignored\n", pwszName)); + else if ((hr = pAdapter->GetInstanceGuid(&guid)) != S_OK) + LogRelFunc(("%ls: failed to get instance GUID (0x%x)\n", + pwszName, hr)); + else + { + struct BoundAdapter adapter; + adapter.pName = pwszName; + adapter.pHwId = pwszHwId; + adapter.guid = *(Guid(guid).raw()); + adapter.pAdapter = NULL; + adapter.fWireless = netIfIsWireless(pAdapter); + netIfLog(("guid=%RTuuid, name=%ls, hwid=%ls, status=%x, chars=%x\n", + &adapter.guid, pwszName, pwszHwId, uStatus, dwChars)); + boundAdapters.push_back(adapter); + pwszName = pwszHwId = NULL; /* do not free, will be done later */ + } + if (pwszHwId) + CoTaskMemFree(pwszHwId); + } + if (pwszName) + CoTaskMemFree(pwszName); + } + + pAdapter->Release(); + } + pBi->Release(); + } + pEnumBi->Release(); + } + pBp->Release(); + } + pEnumBp->Release(); + } + pFilterBindings->Release(); + } + pFilter->Release(); + } + /* Host-only adapters are not necessarily bound, add them separately. */ + netIfGetUnboundHostOnlyAdapters(pNetCfg, boundAdapters); + VBoxNetCfgWinReleaseINetCfg(pNetCfg, FALSE); + + return S_OK; +} + +#if 0 +static HRESULT netIfGetBoundAdaptersFallback(std::list<BoundAdapter> &boundAdapters) +{ + return CO_E_NOT_SUPPORTED; +} +#endif + +/** + * Walk through the list of adpater addresses and extract the required + * information. XP and older don't not have the OnLinkPrefixLength field. + */ +static void netIfFillInfoWithAddressesXp(PNETIFINFO pInfo, PIP_ADAPTER_ADDRESSES pAdapter) +{ + PIP_ADAPTER_UNICAST_ADDRESS pAddr; + bool fIPFound = false; + bool fIPv6Found = false; + for (pAddr = pAdapter->FirstUnicastAddress; pAddr; pAddr = pAddr->Next) + { + switch (pAddr->Address.lpSockaddr->sa_family) + { + case AF_INET: + if (!fIPFound) + { + fIPFound = true; + memcpy(&pInfo->IPAddress, + &((struct sockaddr_in *)pAddr->Address.lpSockaddr)->sin_addr.s_addr, + sizeof(pInfo->IPAddress)); + } + break; + case AF_INET6: + if (!fIPv6Found) + { + fIPv6Found = true; + memcpy(&pInfo->IPv6Address, + ((struct sockaddr_in6 *)pAddr->Address.lpSockaddr)->sin6_addr.s6_addr, + sizeof(pInfo->IPv6Address)); + } + break; + } + } + PIP_ADAPTER_PREFIX pPrefix; + ULONG uPrefixLenV4 = 0; + ULONG uPrefixLenV6 = 0; + for (pPrefix = pAdapter->FirstPrefix; pPrefix && !(uPrefixLenV4 && uPrefixLenV6); pPrefix = pPrefix->Next) + { + switch (pPrefix->Address.lpSockaddr->sa_family) + { + case AF_INET: + if (!uPrefixLenV4) + { + ULONG ip = ((PSOCKADDR_IN)(pPrefix->Address.lpSockaddr))->sin_addr.s_addr; + netIfLog(("prefix=%RTnaipv4 len=%u\n", ip, pPrefix->PrefixLength)); + if ( pPrefix->PrefixLength < sizeof(pInfo->IPNetMask) * 8 + && pPrefix->PrefixLength > 0 + && (ip & 0xF0) < 224) + { + uPrefixLenV4 = pPrefix->PrefixLength; + RTNetPrefixToMaskIPv4(pPrefix->PrefixLength, &pInfo->IPNetMask); + } + else + netIfLog(("Unexpected IPv4 prefix length of %d\n", + pPrefix->PrefixLength)); + } + break; + case AF_INET6: + if (!uPrefixLenV6) + { + PBYTE ipv6 = ((PSOCKADDR_IN6)(pPrefix->Address.lpSockaddr))->sin6_addr.s6_addr; + netIfLog(("prefix=%RTnaipv6 len=%u\n", ipv6, pPrefix->PrefixLength)); + if ( pPrefix->PrefixLength < sizeof(pInfo->IPv6NetMask) * 8 + && pPrefix->PrefixLength > 0 + && ipv6[0] != 0xFF) + { + uPrefixLenV6 = pPrefix->PrefixLength; + RTNetPrefixToMaskIPv6(pPrefix->PrefixLength, &pInfo->IPv6NetMask); + } + else + netIfLog(("Unexpected IPv6 prefix length of %d\n", pPrefix->PrefixLength)); + } + break; + } + } + netIfLog(("%RTnaipv4/%u\n", pInfo->IPAddress, uPrefixLenV4)); + netIfLog(("%RTnaipv6/%u\n", &pInfo->IPv6Address, uPrefixLenV6)); +} + +/** + * Walk through the list of adpater addresses and extract the required + * information. XP and older don't not have the OnLinkPrefixLength field. + */ +static void netIfFillInfoWithAddressesVista(PNETIFINFO pInfo, PIP_ADAPTER_ADDRESSES pAdapter) +{ + PIP_ADAPTER_UNICAST_ADDRESS pAddr; + + if (sizeof(pInfo->MACAddress) != pAdapter->PhysicalAddressLength) + netIfLog(("Unexpected physical address length: %u\n", pAdapter->PhysicalAddressLength)); + else + memcpy(pInfo->MACAddress.au8, pAdapter->PhysicalAddress, sizeof(pInfo->MACAddress)); + + bool fIPFound = false; + bool fIPv6Found = false; + for (pAddr = pAdapter->FirstUnicastAddress; pAddr; pAddr = pAddr->Next) + { + PIP_ADAPTER_UNICAST_ADDRESS_LH pAddrLh = (PIP_ADAPTER_UNICAST_ADDRESS_LH)pAddr; + switch (pAddrLh->Address.lpSockaddr->sa_family) + { + case AF_INET: + if (!fIPFound) + { + fIPFound = true; + memcpy(&pInfo->IPAddress, + &((struct sockaddr_in *)pAddrLh->Address.lpSockaddr)->sin_addr.s_addr, + sizeof(pInfo->IPAddress)); + if (pAddrLh->OnLinkPrefixLength > 32) + netIfLog(("Invalid IPv4 prefix length of %d\n", pAddrLh->OnLinkPrefixLength)); + else + RTNetPrefixToMaskIPv4(pAddrLh->OnLinkPrefixLength, &pInfo->IPNetMask); + } + break; + case AF_INET6: + if (!fIPv6Found) + { + fIPv6Found = true; + memcpy(&pInfo->IPv6Address, + ((struct sockaddr_in6 *)pAddrLh->Address.lpSockaddr)->sin6_addr.s6_addr, + sizeof(pInfo->IPv6Address)); + if (pAddrLh->OnLinkPrefixLength > 128) + netIfLog(("Invalid IPv6 prefix length of %d\n", pAddrLh->OnLinkPrefixLength)); + else + RTNetPrefixToMaskIPv6(pAddrLh->OnLinkPrefixLength, &pInfo->IPv6NetMask); + } + break; + } + } + + if (fIPFound) + { + int iPrefixIPv4 = -1; + RTNetMaskToPrefixIPv4(&pInfo->IPNetMask, &iPrefixIPv4); + netIfLog(("%RTnaipv4/%u\n", pInfo->IPAddress, iPrefixIPv4)); + } + if (fIPv6Found) + { + int iPrefixIPv6 = -1; + RTNetMaskToPrefixIPv6(&pInfo->IPv6NetMask, &iPrefixIPv6); + netIfLog(("%RTnaipv6/%u\n", &pInfo->IPv6Address, iPrefixIPv6)); + } +} + +#if (NTDDI_VERSION >= NTDDI_VISTA) +#define NETIF_GAA_FLAGS GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST +#else /* (NTDDI_VERSION < NTDDI_VISTA) */ +#define NETIF_GAA_FLAGS GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST +#endif /* (NTDDI_VERSION < NTDDI_VISTA) */ + +int NetIfList(std::list<ComObjPtr<HostNetworkInterface> > &list) +{ + HRESULT hr = S_OK; + int iDefault = getDefaultInterfaceIndex(); + /* MSDN recommends to pre-allocate a 15KB buffer. */ + ULONG uBufLen = 15 * 1024; + PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAlloc(uBufLen); + if (!pAddresses) + return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + DWORD dwRc = GetAdaptersAddresses(AF_UNSPEC, NETIF_GAA_FLAGS, NULL, pAddresses, &uBufLen); + for (int tries = 0; tries < 3 && dwRc == ERROR_BUFFER_OVERFLOW; ++tries) + { + /* Get more memory and try again. */ + RTMemFree(pAddresses); + pAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAlloc(uBufLen); + if (!pAddresses) + return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + dwRc = GetAdaptersAddresses(AF_UNSPEC, NETIF_GAA_FLAGS, NULL, pAddresses, &uBufLen); + } + if (dwRc != NO_ERROR) + { + LogRelFunc(("GetAdaptersAddresses failed (0x%x)\n", dwRc)); + hr = HRESULT_FROM_WIN32(dwRc); + } + else + { + std::list<BoundAdapter> boundAdapters; + hr = netIfGetBoundAdapters(boundAdapters); +#if 0 + if (hr != S_OK) + hr = netIfGetBoundAdaptersFallback(boundAdapters); +#endif + if (hr != S_OK) + LogRelFunc(("netIfGetBoundAdapters failed (0x%x)\n", hr)); + else + { + PIP_ADAPTER_ADDRESSES pAdapter; + + for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next) + { + char *pszUuid = RTStrDup(pAdapter->AdapterName); + if (!pszUuid) + { + LogRelFunc(("out of memory\n")); + break; + } + size_t len = strlen(pszUuid) - 1; + if (pszUuid[0] != '{' || pszUuid[len] != '}') + LogRelFunc(("ignoring invalid GUID %s\n", pAdapter->AdapterName)); + else + { + std::list<BoundAdapter>::iterator it; + pszUuid[len] = 0; + for (it = boundAdapters.begin(); it != boundAdapters.end(); ++it) + { + if (!RTUuidCompareStr(&(*it).guid, pszUuid + 1)) + { + (*it).pAdapter = pAdapter; + break; + } + } + } + RTStrFree(pszUuid); + } + std::list<BoundAdapter>::iterator it; + for (it = boundAdapters.begin(); it != boundAdapters.end(); ++it) + { + NETIFINFO info; + memset(&info, 0, sizeof(info)); + info.Uuid = (*it).guid; + info.enmMediumType = NETIF_T_ETHERNET; + info.fWireless = (*it).fWireless; + pAdapter = (*it).pAdapter; + if (pAdapter) + { + info.enmStatus = pAdapter->OperStatus == IfOperStatusUp ? NETIF_S_UP : NETIF_S_DOWN; + info.fIsDefault = (pAdapter->IfIndex == (DWORD)iDefault); + info.fDhcpEnabled = pAdapter->Flags & IP_ADAPTER_DHCP_ENABLED; + OSVERSIONINFOEX OSInfoEx; + RT_ZERO(OSInfoEx); + OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if ( GetVersionEx((LPOSVERSIONINFO)&OSInfoEx) + && OSInfoEx.dwMajorVersion < 6) + netIfFillInfoWithAddressesXp(&info, pAdapter); + else + netIfFillInfoWithAddressesVista(&info, pAdapter); + } + else + info.enmStatus = NETIF_S_DOWN; + /* create a new object and add it to the list */ + ComObjPtr<HostNetworkInterface> iface; + iface.createObject(); + HostNetworkInterfaceType enmType = + _wcsnicmp((*it).pHwId, L"sun_VBoxNetAdp", sizeof(L"sun_VBoxNetAdp")/2) ? + HostNetworkInterfaceType_Bridged : HostNetworkInterfaceType_HostOnly; + netIfLog(("Adding %ls as %s\n", (*it).pName, + enmType == HostNetworkInterfaceType_Bridged ? "bridged" : + enmType == HostNetworkInterfaceType_HostOnly ? "host-only" : "unknown")); + int rc = iface->init((*it).pName, enmType, &info); + if (FAILED(rc)) + LogRelFunc(("HostNetworkInterface::init() -> %Rrc\n", rc)); + else + { + if (info.fIsDefault) + list.push_front(iface); + else + list.push_back(iface); + } + if ((*it).pHwId) + CoTaskMemFree((*it).pHwId); + if ((*it).pName) + CoTaskMemFree((*it).pName); + } + } + } + RTMemFree(pAddresses); + + return hr; +} |