From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Frontends/VBoxManage/VBoxManageHostonly.cpp | 546 +++++++++++++++++++++ 1 file changed, 546 insertions(+) create mode 100644 src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp (limited to 'src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp') diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp new file mode 100644 index 00000000..d5b2444d --- /dev/null +++ b/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp @@ -0,0 +1,546 @@ +/* $Id: VBoxManageHostonly.cpp $ */ +/** @file + * VBoxManage - Implementation of hostonlyif command. + */ + +/* + * Copyright (C) 2006-2023 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 . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "VBoxManage.h" + +DECLARE_TRANSLATION_CONTEXT(HostOnly); + + +using namespace com; + +static const RTGETOPTDEF g_aHostOnlyCreateOptions[] = +{ + { "--machinereadable", 'M', RTGETOPT_REQ_NOTHING }, +}; + +#if defined(VBOX_WITH_NETFLT) && !defined(RT_OS_SOLARIS) +static RTEXITCODE handleCreate(HandlerArg *a) +{ + /* + * Parse input. + */ + bool fMachineReadable = false; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, a->argc, a->argv, g_aHostOnlyCreateOptions, + RT_ELEMENTS(g_aHostOnlyCreateOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); + int c; + while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) + { + switch (c) + { + case 'M': // --machinereadable + fMachineReadable = true; + break; + + default: + return errorGetOpt(c, &ValueUnion); + } + } + + /* + * Do the work. + */ + ComPtr host; + CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE); + + ComPtr hif; + ComPtr progress; + + CHECK_ERROR2I_RET(host, CreateHostOnlyNetworkInterface(hif.asOutParam(), progress.asOutParam()), RTEXITCODE_FAILURE); + + if (fMachineReadable) + { + progress->WaitForCompletion(10000); /* Ten seconds should probably be enough. */ + CHECK_PROGRESS_ERROR_RET(progress, (""), RTEXITCODE_FAILURE); + } + else + { + /*HRESULT hrc =*/ showProgress(progress); + CHECK_PROGRESS_ERROR_RET(progress, (HostOnly::tr("Failed to create the host-only adapter")), RTEXITCODE_FAILURE); + } + + Bstr bstrName; + CHECK_ERROR2I(hif, COMGETTER(Name)(bstrName.asOutParam())); + + if (fMachineReadable) + RTPrintf("%ls", bstrName.raw()); + else + RTPrintf(HostOnly::tr("Interface '%ls' was successfully created\n"), bstrName.raw()); + return RTEXITCODE_SUCCESS; +} + +static RTEXITCODE handleRemove(HandlerArg *a) +{ + /* + * Parse input. + */ + const char *pszName = NULL; + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, a->argc, a->argv, NULL, 0, 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); + while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0) + switch (ch) + { + case VINF_GETOPT_NOT_OPTION: + if (pszName) + return errorSyntax(HostOnly::tr("Only one interface name can be specified")); + pszName = ValueUnion.psz; + break; + + default: + return errorGetOpt(ch, &ValueUnion); + } + if (!pszName) + return errorSyntax(HostOnly::tr("No interface name was specified")); + + /* + * Do the work. + */ + ComPtr host; + CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE); + + ComPtr hif; + CHECK_ERROR2I_RET(host, FindHostNetworkInterfaceByName(Bstr(pszName).raw(), hif.asOutParam()), RTEXITCODE_FAILURE); + + Bstr guid; + CHECK_ERROR2I_RET(hif, COMGETTER(Id)(guid.asOutParam()), RTEXITCODE_FAILURE); + + ComPtr progress; + CHECK_ERROR2I_RET(host, RemoveHostOnlyNetworkInterface(guid.raw(), progress.asOutParam()), RTEXITCODE_FAILURE); + + /*HRESULT hrc =*/ showProgress(progress); + CHECK_PROGRESS_ERROR_RET(progress, (HostOnly::tr("Failed to remove the host-only adapter")), RTEXITCODE_FAILURE); + + return RTEXITCODE_SUCCESS; +} +#endif + +static const RTGETOPTDEF g_aHostOnlyIPOptions[] + = { + { "--dhcp", 'd', RTGETOPT_REQ_NOTHING }, + { "-dhcp", 'd', RTGETOPT_REQ_NOTHING }, // deprecated + { "--ip", 'a', RTGETOPT_REQ_STRING }, + { "-ip", 'a', RTGETOPT_REQ_STRING }, // deprecated + { "--netmask", 'm', RTGETOPT_REQ_STRING }, + { "-netmask", 'm', RTGETOPT_REQ_STRING }, // deprecated + { "--ipv6", 'b', RTGETOPT_REQ_STRING }, + { "-ipv6", 'b', RTGETOPT_REQ_STRING }, // deprecated + { "--netmasklengthv6", 'l', RTGETOPT_REQ_UINT8 }, + { "-netmasklengthv6", 'l', RTGETOPT_REQ_UINT8 } // deprecated + }; + +static RTEXITCODE handleIpConfig(HandlerArg *a) +{ + bool fDhcp = false; + bool fNetmasklengthv6 = false; + uint32_t uNetmasklengthv6 = UINT32_MAX; + const char *pszIpv6 = NULL; + const char *pszIp = NULL; + const char *pszNetmask = NULL; + const char *pszName = NULL; + + int c; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, a->argc, a->argv, g_aHostOnlyIPOptions, RT_ELEMENTS(g_aHostOnlyIPOptions), + 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); + while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) + { + switch (c) + { + case 'd': // --dhcp + fDhcp = true; + break; + case 'a': // --ip + if (pszIp) + RTMsgWarning(HostOnly::tr("The --ip option is specified more than once")); + pszIp = ValueUnion.psz; + break; + case 'm': // --netmask + if (pszNetmask) + RTMsgWarning(HostOnly::tr("The --netmask option is specified more than once")); + pszNetmask = ValueUnion.psz; + break; + case 'b': // --ipv6 + if (pszIpv6) + RTMsgWarning(HostOnly::tr("The --ipv6 option is specified more than once")); + pszIpv6 = ValueUnion.psz; + break; + case 'l': // --netmasklengthv6 + if (fNetmasklengthv6) + RTMsgWarning(HostOnly::tr("The --netmasklengthv6 option is specified more than once")); + fNetmasklengthv6 = true; + uNetmasklengthv6 = ValueUnion.u8; + break; + case VINF_GETOPT_NOT_OPTION: + if (pszName) + return errorSyntax(HostOnly::tr("Only one interface name can be specified")); + pszName = ValueUnion.psz; + break; + default: + return errorGetOpt(c, &ValueUnion); + } + } + + /* parameter sanity check */ + if (fDhcp && (fNetmasklengthv6 || pszIpv6 || pszIp || pszNetmask)) + return errorSyntax(HostOnly::tr("You can not use --dhcp with static ip configuration parameters: --ip, --netmask, --ipv6 and --netmasklengthv6.")); + if ((pszIp || pszNetmask) && (fNetmasklengthv6 || pszIpv6)) + return errorSyntax(HostOnly::tr("You can not use ipv4 configuration (--ip and --netmask) with ipv6 (--ipv6 and --netmasklengthv6) simultaneously.")); + + ComPtr host; + CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE); + + ComPtr hif; + CHECK_ERROR2I_RET(host, FindHostNetworkInterfaceByName(Bstr(pszName).raw(), hif.asOutParam()), RTEXITCODE_FAILURE); + if (hif.isNull()) + return errorArgument(HostOnly::tr("Could not find interface '%s'"), pszName); + + if (fDhcp) + CHECK_ERROR2I_RET(hif, EnableDynamicIPConfig(), RTEXITCODE_FAILURE); + else if (pszIp) + { + if (!pszNetmask) + pszNetmask = "255.255.255.0"; /* ?? */ + CHECK_ERROR2I_RET(hif, EnableStaticIPConfig(Bstr(pszIp).raw(), Bstr(pszNetmask).raw()), RTEXITCODE_FAILURE); + } + else if (pszIpv6) + { + BOOL fIpV6Supported; + CHECK_ERROR2I_RET(hif, COMGETTER(IPV6Supported)(&fIpV6Supported), RTEXITCODE_FAILURE); + if (!fIpV6Supported) + { + RTMsgError(HostOnly::tr("IPv6 setting is not supported for this adapter")); + return RTEXITCODE_FAILURE; + } + + if (uNetmasklengthv6 == UINT32_MAX) + uNetmasklengthv6 = 64; /* ?? */ + CHECK_ERROR2I_RET(hif, EnableStaticIPConfigV6(Bstr(pszIpv6).raw(), (ULONG)uNetmasklengthv6), RTEXITCODE_FAILURE); + } + else + return errorSyntax(HostOnly::tr("Neither -dhcp nor -ip nor -ipv6 was specfified")); + + return RTEXITCODE_SUCCESS; +} + + +RTEXITCODE handleHostonlyIf(HandlerArg *a) +{ + if (a->argc < 1) + return errorSyntax(HostOnly::tr("No sub-command specified")); + + RTEXITCODE rcExit; + if (!strcmp(a->argv[0], "ipconfig")) + { + setCurrentSubcommand(HELP_SCOPE_HOSTONLYIF_IPCONFIG); + rcExit = handleIpConfig(a); + } +#if defined(VBOX_WITH_NETFLT) && !defined(RT_OS_SOLARIS) + else if (!strcmp(a->argv[0], "create")) + { + setCurrentSubcommand(HELP_SCOPE_HOSTONLYIF_CREATE); + rcExit = handleCreate(a); + } + else if (!strcmp(a->argv[0], "remove")) + { + setCurrentSubcommand(HELP_SCOPE_HOSTONLYIF_REMOVE); + rcExit = handleRemove(a); + } +#endif + else + rcExit = errorSyntax(HostOnly::tr("Unknown sub-command '%s'"), a->argv[0]); + return rcExit; +} + +#ifdef VBOX_WITH_VMNET +struct HostOnlyNetworkOptions +{ + bool fEnable; + bool fDisable; + Bstr bstrNetworkId; + Bstr bstrNetworkName; + Bstr bstrNetworkMask; + Bstr bstrLowerIp; + Bstr bstrUpperIp; + /* Initialize fEnable and fDisable */ + HostOnlyNetworkOptions() : fEnable(false), fDisable(false) {}; +}; +typedef struct HostOnlyNetworkOptions HOSTONLYNETOPT; + +static RTEXITCODE createUpdateHostOnlyNetworkParse(HandlerArg *a, HOSTONLYNETOPT& options) +{ + static const RTGETOPTDEF s_aOptions[] = + { + { "--id", 'i', RTGETOPT_REQ_STRING }, + { "--name", 'n', RTGETOPT_REQ_STRING }, + { "--netmask", 'm', RTGETOPT_REQ_STRING }, + { "--lower-ip", 'l', RTGETOPT_REQ_STRING }, + { "--lowerip", 'l', RTGETOPT_REQ_STRING }, + { "--upper-ip", 'u', RTGETOPT_REQ_STRING }, + { "--upperip", 'u', RTGETOPT_REQ_STRING }, + { "--enable", 'e', RTGETOPT_REQ_NOTHING }, + { "--disable", 'd', RTGETOPT_REQ_NOTHING }, + }; + + RTGETOPTSTATE GetState; + RTGETOPTUNION ValueUnion; + int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1 /* iFirst */, 0); + AssertRCReturn(vrc, RTEXITCODE_FAILURE); + + int c; + while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) + { + switch (c) + { + case 'i': + options.bstrNetworkId = ValueUnion.psz; + break; + case 'n': + options.bstrNetworkName = ValueUnion.psz; + break; + case 'm': + options.bstrNetworkMask = ValueUnion.psz; + break; + case 'l': + options.bstrLowerIp = ValueUnion.psz; + break; + case 'u': + options.bstrUpperIp = ValueUnion.psz; + break; + case 'e': + options.fEnable = true; + break; + case 'd': + options.fDisable = true; + break; + case VINF_GETOPT_NOT_OPTION: + return errorUnknownSubcommand(ValueUnion.psz); + default: + return errorGetOpt(c, &ValueUnion); + } + } + return RTEXITCODE_SUCCESS; +} + +static RTEXITCODE createUpdateHostOnlyNetworkCommon(ComPtr hostOnlyNetwork, HOSTONLYNETOPT& options) +{ + HRESULT hrc = S_OK; + + if (options.bstrNetworkId.isNotEmpty()) + { + CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(Id)(options.bstrNetworkId.raw()), RTEXITCODE_FAILURE); + } + if (options.bstrNetworkName.isNotEmpty()) + { + CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(NetworkName)(options.bstrNetworkName.raw()), RTEXITCODE_FAILURE); + } + if (options.bstrNetworkMask.isNotEmpty()) + { + CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(NetworkMask)(options.bstrNetworkMask.raw()), RTEXITCODE_FAILURE); + } + if (options.bstrLowerIp.isNotEmpty()) + { + CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(LowerIP)(options.bstrLowerIp.raw()), RTEXITCODE_FAILURE); + } + if (options.bstrUpperIp.isNotEmpty()) + { + CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(UpperIP)(options.bstrUpperIp.raw()), RTEXITCODE_FAILURE); + } + if (options.fEnable) + { + CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE); + } + if (options.fDisable) + { + CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE); + } + + return RTEXITCODE_SUCCESS; +} + +static RTEXITCODE handleNetAdd(HandlerArg *a) +{ + HRESULT hrc = S_OK; + + HOSTONLYNETOPT options; + hrc = createUpdateHostOnlyNetworkParse(a, options); + + ComPtr pVirtualBox = a->virtualBox; + ComPtr hostOnlyNetwork; + + if (options.bstrNetworkName.isEmpty()) + return errorArgument(HostOnly::tr("The --name parameter must be specified")); + if (options.bstrNetworkMask.isEmpty()) + return errorArgument(HostOnly::tr("The --netmask parameter must be specified")); + if (options.bstrLowerIp.isEmpty()) + return errorArgument(HostOnly::tr("The --lower-ip parameter must be specified")); + if (options.bstrUpperIp.isEmpty()) + return errorArgument(HostOnly::tr("The --upper-ip parameter must be specified")); + + CHECK_ERROR2_RET(hrc, pVirtualBox, + CreateHostOnlyNetwork(options.bstrNetworkName.raw(), hostOnlyNetwork.asOutParam()), + RTEXITCODE_FAILURE); + return createUpdateHostOnlyNetworkCommon(hostOnlyNetwork, options); +} + +static RTEXITCODE handleNetModify(HandlerArg *a) +{ + HRESULT hrc = S_OK; + + HOSTONLYNETOPT options; + hrc = createUpdateHostOnlyNetworkParse(a, options); + + ComPtr pVirtualBox = a->virtualBox; + ComPtr hostOnlyNetwork; + + if (options.bstrNetworkName.isNotEmpty()) + { + CHECK_ERROR2_RET(hrc, pVirtualBox, + FindHostOnlyNetworkByName(options.bstrNetworkName.raw(), hostOnlyNetwork.asOutParam()), + RTEXITCODE_FAILURE); + } + else if (options.bstrNetworkId.isNotEmpty()) + { + CHECK_ERROR2_RET(hrc, pVirtualBox, + FindHostOnlyNetworkById(options.bstrNetworkId.raw(), hostOnlyNetwork.asOutParam()), + RTEXITCODE_FAILURE); + } + else + return errorArgument(HostOnly::tr("Either --name or --id parameter must be specified")); + + return createUpdateHostOnlyNetworkCommon(hostOnlyNetwork, options); +} + +static RTEXITCODE handleNetRemove(HandlerArg *a) +{ + HRESULT hrc = S_OK; + + static const RTGETOPTDEF s_aOptions[] = + { + { "--id", 'i', RTGETOPT_REQ_STRING }, + { "--name", 'n', RTGETOPT_REQ_STRING }, + }; + + RTGETOPTSTATE GetState; + RTGETOPTUNION ValueUnion; + int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1 /* iFirst */, 0); + AssertRCReturn(vrc, RTEXITCODE_FAILURE); + + Bstr strNetworkId, strNetworkName; + + int c; + while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) + { + switch (c) + { + case 'i': + strNetworkId=ValueUnion.psz; + break; + case 'n': + strNetworkName=ValueUnion.psz; + break; + case VINF_GETOPT_NOT_OPTION: + return errorUnknownSubcommand(ValueUnion.psz); + default: + return errorGetOpt(c, &ValueUnion); + } + } + + ComPtr pVirtualBox = a->virtualBox; + ComPtr hostOnlyNetwork; + + if (!strNetworkName.isEmpty()) + { + CHECK_ERROR2_RET(hrc, pVirtualBox, + FindHostOnlyNetworkByName(strNetworkName.raw(), hostOnlyNetwork.asOutParam()), + RTEXITCODE_FAILURE); + } + else if (!strNetworkId.isEmpty()) + { + CHECK_ERROR2_RET(hrc, pVirtualBox, + FindHostOnlyNetworkById(strNetworkId.raw(), hostOnlyNetwork.asOutParam()), + RTEXITCODE_FAILURE); + } + else + return errorArgument(HostOnly::tr("Either --name or --id parameter must be specified")); + + CHECK_ERROR2_RET(hrc, pVirtualBox, + RemoveHostOnlyNetwork(hostOnlyNetwork), + RTEXITCODE_FAILURE); + return RTEXITCODE_SUCCESS; +} + +RTEXITCODE handleHostonlyNet(HandlerArg *a) +{ + if (a->argc < 1) + return errorSyntax(HostOnly::tr("No sub-command specified")); + + RTEXITCODE rcExit; + if (!strcmp(a->argv[0], "add")) + { + setCurrentSubcommand(HELP_SCOPE_HOSTONLYNET_ADD); + rcExit = handleNetAdd(a); + } + else if (!strcmp(a->argv[0], "modify")) + { + setCurrentSubcommand(HELP_SCOPE_HOSTONLYNET_MODIFY); + rcExit = handleNetModify(a); + } + else if (!strcmp(a->argv[0], "remove")) + { + setCurrentSubcommand(HELP_SCOPE_HOSTONLYNET_REMOVE); + rcExit = handleNetRemove(a); + } + else + rcExit = errorSyntax(HostOnly::tr("Unknown sub-command '%s'"), a->argv[0]); + return rcExit; +} +#endif /* VBOX_WITH_VMNET */ -- cgit v1.2.3