VirtualBox

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

Last change on this file since 92432 was 92372, checked in by vboxsync, 3 years ago

Main: bugref:1909: Added translation marks around messages of VBoxManage output

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