VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp@ 94670

Last change on this file since 94670 was 94234, checked in by vboxsync, 3 years ago

FE/VBoxManage: Remove the now unused VBoxManageHelp build target and the VBOX_ONLY_DOCS #ifdef's in the code, ​bugref:9186

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.0 KB
Line 
1/* $Id: VBoxManageHostonly.cpp 94234 2022-03-15 09:19:29Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of hostonlyif command.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <VBox/com/com.h>
23#include <VBox/com/array.h>
24#include <VBox/com/ErrorInfo.h>
25#include <VBox/com/errorprint.h>
26#include <VBox/com/VirtualBox.h>
27
28#include <iprt/cidr.h>
29#include <iprt/param.h>
30#include <iprt/path.h>
31#include <iprt/stream.h>
32#include <iprt/string.h>
33#include <iprt/net.h>
34#include <iprt/getopt.h>
35#include <iprt/ctype.h>
36
37#include <VBox/log.h>
38
39#include "VBoxManage.h"
40
41DECLARE_TRANSLATION_CONTEXT(HostOnly);
42
43
44using namespace com;
45
46static const RTGETOPTDEF g_aHostOnlyCreateOptions[] =
47{
48 { "--machinereadable", 'M', RTGETOPT_REQ_NOTHING },
49};
50
51#if defined(VBOX_WITH_NETFLT) && !defined(RT_OS_SOLARIS)
52static RTEXITCODE handleCreate(HandlerArg *a)
53{
54 /*
55 * Parse input.
56 */
57 bool fMachineReadable = false;
58 RTGETOPTUNION ValueUnion;
59 RTGETOPTSTATE GetState;
60 RTGetOptInit(&GetState, a->argc, a->argv, g_aHostOnlyCreateOptions,
61 RT_ELEMENTS(g_aHostOnlyCreateOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
62 int c;
63 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
64 {
65 switch (c)
66 {
67 case 'M': // --machinereadable
68 fMachineReadable = true;
69 break;
70
71 default:
72 return errorGetOpt(c, &ValueUnion);
73 }
74 }
75
76 /*
77 * Do the work.
78 */
79 ComPtr<IHost> host;
80 CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);
81
82 ComPtr<IHostNetworkInterface> hif;
83 ComPtr<IProgress> progress;
84
85 CHECK_ERROR2I_RET(host, CreateHostOnlyNetworkInterface(hif.asOutParam(), progress.asOutParam()), RTEXITCODE_FAILURE);
86
87 if (fMachineReadable)
88 {
89 progress->WaitForCompletion(10000); /* Ten seconds should probably be enough. */
90 CHECK_PROGRESS_ERROR_RET(progress, (""), RTEXITCODE_FAILURE);
91 }
92 else
93 {
94 /*HRESULT hrc =*/ showProgress(progress);
95 CHECK_PROGRESS_ERROR_RET(progress, (HostOnly::tr("Failed to create the host-only adapter")), RTEXITCODE_FAILURE);
96 }
97
98 Bstr bstrName;
99 CHECK_ERROR2I(hif, COMGETTER(Name)(bstrName.asOutParam()));
100
101 if (fMachineReadable)
102 RTPrintf("%ls", bstrName.raw());
103 else
104 RTPrintf(HostOnly::tr("Interface '%ls' was successfully created\n"), bstrName.raw());
105 return RTEXITCODE_SUCCESS;
106}
107
108static RTEXITCODE handleRemove(HandlerArg *a)
109{
110 /*
111 * Parse input.
112 */
113 const char *pszName = NULL;
114 int ch;
115 RTGETOPTUNION ValueUnion;
116 RTGETOPTSTATE GetState;
117 RTGetOptInit(&GetState, a->argc, a->argv, NULL, 0, 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
118 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
119 switch (ch)
120 {
121 case VINF_GETOPT_NOT_OPTION:
122 if (pszName)
123 return errorSyntax(HostOnly::tr("Only one interface name can be specified"));
124 pszName = ValueUnion.psz;
125 break;
126
127 default:
128 return errorGetOpt(ch, &ValueUnion);
129 }
130 if (!pszName)
131 return errorSyntax(HostOnly::tr("No interface name was specified"));
132
133 /*
134 * Do the work.
135 */
136 ComPtr<IHost> host;
137 CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);
138
139 ComPtr<IHostNetworkInterface> hif;
140 CHECK_ERROR2I_RET(host, FindHostNetworkInterfaceByName(Bstr(pszName).raw(), hif.asOutParam()), RTEXITCODE_FAILURE);
141
142 Bstr guid;
143 CHECK_ERROR2I_RET(hif, COMGETTER(Id)(guid.asOutParam()), RTEXITCODE_FAILURE);
144
145 ComPtr<IProgress> progress;
146 CHECK_ERROR2I_RET(host, RemoveHostOnlyNetworkInterface(guid.raw(), progress.asOutParam()), RTEXITCODE_FAILURE);
147
148 /*HRESULT hrc =*/ showProgress(progress);
149 CHECK_PROGRESS_ERROR_RET(progress, (HostOnly::tr("Failed to remove the host-only adapter")), RTEXITCODE_FAILURE);
150
151 return RTEXITCODE_SUCCESS;
152}
153#endif
154
155static const RTGETOPTDEF g_aHostOnlyIPOptions[]
156 = {
157 { "--dhcp", 'd', RTGETOPT_REQ_NOTHING },
158 { "-dhcp", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
159 { "--ip", 'a', RTGETOPT_REQ_STRING },
160 { "-ip", 'a', RTGETOPT_REQ_STRING }, // deprecated
161 { "--netmask", 'm', RTGETOPT_REQ_STRING },
162 { "-netmask", 'm', RTGETOPT_REQ_STRING }, // deprecated
163 { "--ipv6", 'b', RTGETOPT_REQ_STRING },
164 { "-ipv6", 'b', RTGETOPT_REQ_STRING }, // deprecated
165 { "--netmasklengthv6", 'l', RTGETOPT_REQ_UINT8 },
166 { "-netmasklengthv6", 'l', RTGETOPT_REQ_UINT8 } // deprecated
167 };
168
169static RTEXITCODE handleIpConfig(HandlerArg *a)
170{
171 bool fDhcp = false;
172 bool fNetmasklengthv6 = false;
173 uint32_t uNetmasklengthv6 = UINT32_MAX;
174 const char *pszIpv6 = NULL;
175 const char *pszIp = NULL;
176 const char *pszNetmask = NULL;
177 const char *pszName = NULL;
178
179 int c;
180 RTGETOPTUNION ValueUnion;
181 RTGETOPTSTATE GetState;
182 RTGetOptInit(&GetState, a->argc, a->argv, g_aHostOnlyIPOptions, RT_ELEMENTS(g_aHostOnlyIPOptions),
183 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
184 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
185 {
186 switch (c)
187 {
188 case 'd': // --dhcp
189 fDhcp = true;
190 break;
191 case 'a': // --ip
192 if (pszIp)
193 RTMsgWarning(HostOnly::tr("The --ip option is specified more than once"));
194 pszIp = ValueUnion.psz;
195 break;
196 case 'm': // --netmask
197 if (pszNetmask)
198 RTMsgWarning(HostOnly::tr("The --netmask option is specified more than once"));
199 pszNetmask = ValueUnion.psz;
200 break;
201 case 'b': // --ipv6
202 if (pszIpv6)
203 RTMsgWarning(HostOnly::tr("The --ipv6 option is specified more than once"));
204 pszIpv6 = ValueUnion.psz;
205 break;
206 case 'l': // --netmasklengthv6
207 if (fNetmasklengthv6)
208 RTMsgWarning(HostOnly::tr("The --netmasklengthv6 option is specified more than once"));
209 fNetmasklengthv6 = true;
210 uNetmasklengthv6 = ValueUnion.u8;
211 break;
212 case VINF_GETOPT_NOT_OPTION:
213 if (pszName)
214 return errorSyntax(HostOnly::tr("Only one interface name can be specified"));
215 pszName = ValueUnion.psz;
216 break;
217 default:
218 return errorGetOpt(c, &ValueUnion);
219 }
220 }
221
222 /* parameter sanity check */
223 if (fDhcp && (fNetmasklengthv6 || pszIpv6 || pszIp || pszNetmask))
224 return errorSyntax(HostOnly::tr("You can not use --dhcp with static ip configuration parameters: --ip, --netmask, --ipv6 and --netmasklengthv6."));
225 if ((pszIp || pszNetmask) && (fNetmasklengthv6 || pszIpv6))
226 return errorSyntax(HostOnly::tr("You can not use ipv4 configuration (--ip and --netmask) with ipv6 (--ipv6 and --netmasklengthv6) simultaneously."));
227
228 ComPtr<IHost> host;
229 CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);
230
231 ComPtr<IHostNetworkInterface> hif;
232 CHECK_ERROR2I_RET(host, FindHostNetworkInterfaceByName(Bstr(pszName).raw(), hif.asOutParam()), RTEXITCODE_FAILURE);
233 if (hif.isNull())
234 return errorArgument(HostOnly::tr("Could not find interface '%s'"), pszName);
235
236 if (fDhcp)
237 CHECK_ERROR2I_RET(hif, EnableDynamicIPConfig(), RTEXITCODE_FAILURE);
238 else if (pszIp)
239 {
240 if (!pszNetmask)
241 pszNetmask = "255.255.255.0"; /* ?? */
242 CHECK_ERROR2I_RET(hif, EnableStaticIPConfig(Bstr(pszIp).raw(), Bstr(pszNetmask).raw()), RTEXITCODE_FAILURE);
243 }
244 else if (pszIpv6)
245 {
246 BOOL fIpV6Supported;
247 CHECK_ERROR2I_RET(hif, COMGETTER(IPV6Supported)(&fIpV6Supported), RTEXITCODE_FAILURE);
248 if (!fIpV6Supported)
249 {
250 RTMsgError(HostOnly::tr("IPv6 setting is not supported for this adapter"));
251 return RTEXITCODE_FAILURE;
252 }
253
254 if (uNetmasklengthv6 == UINT32_MAX)
255 uNetmasklengthv6 = 64; /* ?? */
256 CHECK_ERROR2I_RET(hif, EnableStaticIPConfigV6(Bstr(pszIpv6).raw(), (ULONG)uNetmasklengthv6), RTEXITCODE_FAILURE);
257 }
258 else
259 return errorSyntax(HostOnly::tr("Neither -dhcp nor -ip nor -ipv6 was specfified"));
260
261 return RTEXITCODE_SUCCESS;
262}
263
264
265RTEXITCODE handleHostonlyIf(HandlerArg *a)
266{
267 if (a->argc < 1)
268 return errorSyntax(HostOnly::tr("No sub-command specified"));
269
270 RTEXITCODE rcExit;
271 if (!strcmp(a->argv[0], "ipconfig"))
272 {
273 setCurrentSubcommand(HELP_SCOPE_HOSTONLYIF_IPCONFIG);
274 rcExit = handleIpConfig(a);
275 }
276#if defined(VBOX_WITH_NETFLT) && !defined(RT_OS_SOLARIS)
277 else if (!strcmp(a->argv[0], "create"))
278 {
279 setCurrentSubcommand(HELP_SCOPE_HOSTONLYIF_CREATE);
280 rcExit = handleCreate(a);
281 }
282 else if (!strcmp(a->argv[0], "remove"))
283 {
284 setCurrentSubcommand(HELP_SCOPE_HOSTONLYIF_REMOVE);
285 rcExit = handleRemove(a);
286 }
287#endif
288 else
289 rcExit = errorSyntax(HostOnly::tr("Unknown sub-command '%s'"), a->argv[0]);
290 return rcExit;
291}
292
293#ifdef VBOX_WITH_VMNET
294struct HostOnlyNetworkOptions
295{
296 bool fEnable;
297 bool fDisable;
298 Bstr bstrNetworkId;
299 Bstr bstrNetworkName;
300 Bstr bstrNetworkMask;
301 Bstr bstrLowerIp;
302 Bstr bstrUpperIp;
303 /* Initialize fEnable and fDisable */
304 HostOnlyNetworkOptions() : fEnable(false), fDisable(false) {};
305};
306typedef struct HostOnlyNetworkOptions HOSTONLYNETOPT;
307
308static RTEXITCODE createUpdateHostOnlyNetworkParse(HandlerArg *a, HOSTONLYNETOPT& options)
309{
310 static const RTGETOPTDEF s_aOptions[] =
311 {
312 { "--id", 'i', RTGETOPT_REQ_STRING },
313 { "--name", 'n', RTGETOPT_REQ_STRING },
314 { "--netmask", 'm', RTGETOPT_REQ_STRING },
315 { "--lower-ip", 'l', RTGETOPT_REQ_STRING },
316 { "--lowerip", 'l', RTGETOPT_REQ_STRING },
317 { "--upper-ip", 'u', RTGETOPT_REQ_STRING },
318 { "--upperip", 'u', RTGETOPT_REQ_STRING },
319 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
320 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
321 };
322
323 RTGETOPTSTATE GetState;
324 RTGETOPTUNION ValueUnion;
325 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1 /* iFirst */, 0);
326 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
327
328 int c;
329 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
330 {
331 switch (c)
332 {
333 case 'i':
334 options.bstrNetworkId = ValueUnion.psz;
335 break;
336 case 'n':
337 options.bstrNetworkName = ValueUnion.psz;
338 break;
339 case 'm':
340 options.bstrNetworkMask = ValueUnion.psz;
341 break;
342 case 'l':
343 options.bstrLowerIp = ValueUnion.psz;
344 break;
345 case 'u':
346 options.bstrUpperIp = ValueUnion.psz;
347 break;
348 case 'e':
349 options.fEnable = true;
350 break;
351 case 'd':
352 options.fDisable = true;
353 break;
354 case VINF_GETOPT_NOT_OPTION:
355 return errorUnknownSubcommand(ValueUnion.psz);
356 default:
357 return errorGetOpt(c, &ValueUnion);
358 }
359 }
360 return RTEXITCODE_SUCCESS;
361}
362
363static RTEXITCODE createUpdateHostOnlyNetworkCommon(ComPtr<IHostOnlyNetwork> hostOnlyNetwork, HOSTONLYNETOPT& options)
364{
365 HRESULT hrc = S_OK;
366
367 if (options.bstrNetworkId.isNotEmpty())
368 {
369 CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(Id)(options.bstrNetworkId.raw()), RTEXITCODE_FAILURE);
370 }
371 if (options.bstrNetworkName.isNotEmpty())
372 {
373 CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(NetworkName)(options.bstrNetworkName.raw()), RTEXITCODE_FAILURE);
374 }
375 if (options.bstrNetworkMask.isNotEmpty())
376 {
377 CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(NetworkMask)(options.bstrNetworkMask.raw()), RTEXITCODE_FAILURE);
378 }
379 if (options.bstrLowerIp.isNotEmpty())
380 {
381 CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(LowerIP)(options.bstrLowerIp.raw()), RTEXITCODE_FAILURE);
382 }
383 if (options.bstrUpperIp.isNotEmpty())
384 {
385 CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(UpperIP)(options.bstrUpperIp.raw()), RTEXITCODE_FAILURE);
386 }
387 if (options.fEnable)
388 {
389 CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
390 }
391 if (options.fDisable)
392 {
393 CHECK_ERROR2_RET(hrc, hostOnlyNetwork, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE);
394 }
395
396 return RTEXITCODE_SUCCESS;
397}
398
399static RTEXITCODE handleNetAdd(HandlerArg *a)
400{
401 HRESULT hrc = S_OK;
402
403 HOSTONLYNETOPT options;
404 hrc = createUpdateHostOnlyNetworkParse(a, options);
405
406 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
407 ComPtr<IHostOnlyNetwork> hostOnlyNetwork;
408
409 if (options.bstrNetworkName.isEmpty())
410 return errorArgument(HostOnly::tr("The --name parameter must be specified"));
411 if (options.bstrNetworkMask.isEmpty())
412 return errorArgument(HostOnly::tr("The --netmask parameter must be specified"));
413 if (options.bstrLowerIp.isEmpty())
414 return errorArgument(HostOnly::tr("The --lower-ip parameter must be specified"));
415 if (options.bstrUpperIp.isEmpty())
416 return errorArgument(HostOnly::tr("The --upper-ip parameter must be specified"));
417
418 CHECK_ERROR2_RET(hrc, pVirtualBox,
419 CreateHostOnlyNetwork(options.bstrNetworkName.raw(), hostOnlyNetwork.asOutParam()),
420 RTEXITCODE_FAILURE);
421 return createUpdateHostOnlyNetworkCommon(hostOnlyNetwork, options);
422}
423
424static RTEXITCODE handleNetModify(HandlerArg *a)
425{
426 HRESULT hrc = S_OK;
427
428 HOSTONLYNETOPT options;
429 hrc = createUpdateHostOnlyNetworkParse(a, options);
430
431 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
432 ComPtr<IHostOnlyNetwork> hostOnlyNetwork;
433
434 if (options.bstrNetworkName.isNotEmpty())
435 {
436 CHECK_ERROR2_RET(hrc, pVirtualBox,
437 FindHostOnlyNetworkByName(options.bstrNetworkName.raw(), hostOnlyNetwork.asOutParam()),
438 RTEXITCODE_FAILURE);
439 }
440 else if (options.bstrNetworkId.isNotEmpty())
441 {
442 CHECK_ERROR2_RET(hrc, pVirtualBox,
443 FindHostOnlyNetworkById(options.bstrNetworkId.raw(), hostOnlyNetwork.asOutParam()),
444 RTEXITCODE_FAILURE);
445 }
446 else
447 return errorArgument(HostOnly::tr("Either --name or --id parameter must be specified"));
448
449 return createUpdateHostOnlyNetworkCommon(hostOnlyNetwork, options);
450}
451
452static RTEXITCODE handleNetRemove(HandlerArg *a)
453{
454 HRESULT hrc = S_OK;
455
456 static const RTGETOPTDEF s_aOptions[] =
457 {
458 { "--id", 'i', RTGETOPT_REQ_STRING },
459 { "--name", 'n', RTGETOPT_REQ_STRING },
460 };
461
462 RTGETOPTSTATE GetState;
463 RTGETOPTUNION ValueUnion;
464 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1 /* iFirst */, 0);
465 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
466
467 Bstr strNetworkId, strNetworkName;
468
469 int c;
470 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
471 {
472 switch (c)
473 {
474 case 'i':
475 strNetworkId=ValueUnion.psz;
476 break;
477 case 'n':
478 strNetworkName=ValueUnion.psz;
479 break;
480 case VINF_GETOPT_NOT_OPTION:
481 return errorUnknownSubcommand(ValueUnion.psz);
482 default:
483 return errorGetOpt(c, &ValueUnion);
484 }
485 }
486
487 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
488 ComPtr<IHostOnlyNetwork> hostOnlyNetwork;
489
490 if (!strNetworkName.isEmpty())
491 {
492 CHECK_ERROR2_RET(hrc, pVirtualBox,
493 FindHostOnlyNetworkByName(strNetworkName.raw(), hostOnlyNetwork.asOutParam()),
494 RTEXITCODE_FAILURE);
495 }
496 else if (!strNetworkId.isEmpty())
497 {
498 CHECK_ERROR2_RET(hrc, pVirtualBox,
499 FindHostOnlyNetworkById(strNetworkId.raw(), hostOnlyNetwork.asOutParam()),
500 RTEXITCODE_FAILURE);
501 }
502 else
503 return errorArgument(HostOnly::tr("Either --name or --id parameter must be specified"));
504
505 CHECK_ERROR2_RET(hrc, pVirtualBox,
506 RemoveHostOnlyNetwork(hostOnlyNetwork),
507 RTEXITCODE_FAILURE);
508 return RTEXITCODE_SUCCESS;
509}
510
511RTEXITCODE handleHostonlyNet(HandlerArg *a)
512{
513 if (a->argc < 1)
514 return errorSyntax(HostOnly::tr("No sub-command specified"));
515
516 RTEXITCODE rcExit;
517 if (!strcmp(a->argv[0], "add"))
518 {
519 setCurrentSubcommand(HELP_SCOPE_HOSTONLYNET_ADD);
520 rcExit = handleNetAdd(a);
521 }
522 else if (!strcmp(a->argv[0], "modify"))
523 {
524 setCurrentSubcommand(HELP_SCOPE_HOSTONLYNET_MODIFY);
525 rcExit = handleNetModify(a);
526 }
527 else if (!strcmp(a->argv[0], "remove"))
528 {
529 setCurrentSubcommand(HELP_SCOPE_HOSTONLYNET_REMOVE);
530 rcExit = handleNetRemove(a);
531 }
532 else
533 rcExit = errorSyntax(HostOnly::tr("Unknown sub-command '%s'"), a->argv[0]);
534 return rcExit;
535}
536#endif /* VBOX_WITH_VMNET */
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