VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageNATNetwork.cpp@ 48112

Last change on this file since 48112 was 48105, checked in by vboxsync, 11 years ago

VBoxManage natnetwork help

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/* $Id: VBoxManageNATNetwork.cpp 48105 2013-08-27 19:53:13Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of NAT Network command command.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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* Header Files *
20*******************************************************************************/
21#ifndef VBOX_ONLY_DOCS
22
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#ifndef RT_OS_WINDOWS
31# include <netinet/in.h>
32#endif
33
34#define IPv6
35
36#include <iprt/cdefs.h>
37#include <iprt/cidr.h>
38#include <iprt/param.h>
39#include <iprt/path.h>
40#include <iprt/stream.h>
41#include <iprt/string.h>
42#include <iprt/net.h>
43#include <iprt/getopt.h>
44#include <iprt/ctype.h>
45
46#include <VBox/log.h>
47
48#include <vector>
49#include <string>
50
51#include "VBoxManage.h"
52#include "VBoxPortForwardString.h"
53
54#ifndef VBOX_ONLY_DOCS
55
56using namespace com;
57
58typedef enum enMainOpCodes
59{
60 OP_ADD = 1000,
61 OP_REMOVE,
62 OP_MODIFY,
63 OP_START,
64 OP_STOP
65} OPCODE;
66
67static const RTGETOPTDEF g_aNATNetworkIPOptions[]
68 = {
69 { "--netname", 't', RTGETOPT_REQ_STRING },
70 { "--network", 'n', RTGETOPT_REQ_STRING },
71 { "--dhcp", 'h', RTGETOPT_REQ_BOOL },
72 { "--ipv6", '6', RTGETOPT_REQ_BOOL},
73 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
74 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
75 { "--port-forward-4", 'p', RTGETOPT_REQ_STRING },
76 { "--port-forward-6", 'P', RTGETOPT_REQ_STRING },
77 { "--loopback-4", 'l', RTGETOPT_REQ_STRING },
78 { "--loopback-6", 'L', RTGETOPT_REQ_STRING },
79
80 };
81
82typedef struct PFNAME2DELETE
83{
84 char aszName[PF_NAMELEN];
85 bool fIPv6;
86} PFNAME2DELETE, *PPFNAME2DELETE;
87
88typedef std::vector<PFNAME2DELETE> VPF2DELETE;
89typedef VPF2DELETE::const_iterator VPF2DELETEITERATOR;
90
91typedef std::vector<PORTFORWARDRULE> VPF2ADD;
92typedef VPF2ADD::const_iterator VPF2ADDITERATOR;
93
94typedef std::vector<std::string> LOOPBACK2DELETEADD;
95typedef LOOPBACK2DELETEADD::iterator LOOPBACK2DELETEADDITERATOR;
96
97static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
98{
99 if (a->argc - iStart < 2)
100 return errorSyntax(USAGE_NATNETWORK, "Not enough parameters");
101
102 int index = iStart;
103 HRESULT rc;
104
105 const char *pNetName = NULL;
106 const char *pNetworkCidr = NULL;
107 int enable = -1;
108 int dhcp = -1;
109 int ipv6 = -1;
110
111 VPF2DELETE vPfName2Delete;
112 VPF2ADD vPf2Add;
113
114 LOOPBACK2DELETEADD vLoopback2Delete;
115 LOOPBACK2DELETEADD vLoopback2Add;
116
117 LONG loopback6Offset = 0; /* ignore me */
118
119 int c;
120 RTGETOPTUNION ValueUnion;
121 RTGETOPTSTATE GetState;
122
123 RTGetOptInit(&GetState,
124 a->argc,
125 a->argv,
126 g_aNATNetworkIPOptions,
127 enmCode != OP_REMOVE ? RT_ELEMENTS(g_aNATNetworkIPOptions) : 4, /* we use only --netname and --ifname for remove*/
128 index,
129 RTGETOPTINIT_FLAGS_NO_STD_OPTS);
130 while ((c = RTGetOpt(&GetState, &ValueUnion)))
131 {
132 switch (c)
133 {
134 case 't': // --netname
135 if (pNetName)
136 return errorSyntax(USAGE_NATNETWORK, "You can only specify --netname only once.");
137 else
138 pNetName = ValueUnion.psz;
139 break;
140
141 case 'n': // --network
142 if (pNetworkCidr)
143 return errorSyntax(USAGE_NATNETWORK, "You can only specify --network only once.");
144 else
145 pNetworkCidr = ValueUnion.psz;
146 break;
147
148 case 'e': // --enable
149 if (enable >= 0)
150 return errorSyntax(USAGE_NATNETWORK, "You can specify either --enable or --disable once.");
151 else
152 enable = 1;
153 break;
154
155 case 'd': // --disable
156 if (enable >= 0)
157 return errorSyntax(USAGE_NATNETWORK, "You can specify either --enable or --disable once.");
158 else
159 enable = 0;
160 break;
161
162 case 'h':
163 if (dhcp != -1)
164 return errorSyntax(USAGE_NATNETWORK, "You can specify --dhcp only once.");
165 dhcp = ValueUnion.f;
166 break;
167
168 case '6':
169 if (ipv6 != -1)
170 return errorSyntax(USAGE_NATNETWORK, "You can specify --ipv6 only once.");
171 ipv6 = ValueUnion.f;
172 break;
173
174 case 'L': /* ipv6 loopback */
175 case 'l': /* ipv4 loopback */
176 if (RTStrCmp(ValueUnion.psz, "delete") == 0)
177 {
178 /* deletion */
179 if (enmCode != OP_MODIFY)
180 errorSyntax(USAGE_NATNETWORK,
181 "loopback couldn't be deleted on modified\n");
182 if (c == 'L')
183 loopback6Offset = -1;
184 else
185 {
186 int vrc;
187 RTGETOPTUNION Addr2Delete;
188 vrc = RTGetOptFetchValue(&GetState,
189 &Addr2Delete,
190 RTGETOPT_REQ_STRING);
191 if (RT_FAILURE(vrc))
192 return errorSyntax(USAGE_NATNETWORK,
193 "Not enough parmaters\n");
194
195 vLoopback2Delete.push_back(std::string(Addr2Delete.psz));
196 }
197 }
198 else /* addition */
199 {
200 if (c == 'L')
201 loopback6Offset = ValueUnion.u32;
202 else
203 vLoopback2Add.push_back(std::string(ValueUnion.psz));
204 }
205 break;
206
207 case 'P': /* ipv6 portforwarding*/
208 case 'p': /* ipv4 portforwarding */
209 {
210 if (RTStrCmp(ValueUnion.psz, "delete") != 0)
211 {
212 PORTFORWARDRULE Pfr;
213
214 /* netPfStrToPf will clean up the Pfr */
215 int irc = netPfStrToPf(ValueUnion.psz, (c == 'P'), &Pfr);
216 if (RT_FAILURE(irc))
217 return errorSyntax(USAGE_NATNETWORK,
218 "Invalid port-forward rule %s\n",
219 ValueUnion.psz);
220
221 vPf2Add.push_back(Pfr);
222 }
223 else
224 {
225 int vrc;
226 RTGETOPTUNION NamePf2DeleteUnion;
227 PFNAME2DELETE Name2Delete;
228
229 if (enmCode != OP_MODIFY)
230 return errorSyntax(USAGE_NATNETWORK,
231 "Port-forward could be deleted on modify \n");
232
233 vrc = RTGetOptFetchValue(&GetState,
234 &NamePf2DeleteUnion,
235 RTGETOPT_REQ_STRING);
236 if (RT_FAILURE(vrc))
237 return errorSyntax(USAGE_NATNETWORK,
238 "Not enough parmaters\n");
239
240 if (strlen(NamePf2DeleteUnion.psz) > PF_NAMELEN)
241 return errorSyntax(USAGE_NATNETWORK,
242 "Port-forward rule name is too long\n");
243
244 RT_ZERO(Name2Delete);
245 RTStrCopy(Name2Delete.aszName, PF_NAMELEN, NamePf2DeleteUnion.psz);
246 Name2Delete.fIPv6 = (c == 'P');
247
248 vPfName2Delete.push_back(Name2Delete);
249 }
250 break;
251 }
252
253 case VINF_GETOPT_NOT_OPTION:
254 return errorSyntax(USAGE_NATNETWORK,
255 "unhandled parameter: %s",
256 ValueUnion.psz);
257
258 default:
259 if (c > 0)
260 {
261 if (RT_C_IS_GRAPH(c))
262 return errorSyntax(USAGE_NATNETWORK,
263 "unhandled option: -%c", c);
264 else
265 return errorSyntax(USAGE_NATNETWORK,
266 "unhandled option: %i", c);
267 }
268 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
269 return errorSyntax(USAGE_NATNETWORK,
270 "unknown option: %s", ValueUnion.psz);
271 else if (ValueUnion.pDef)
272 return errorSyntax(USAGE_NATNETWORK,
273 "%s: %Rrs", ValueUnion.pDef->pszLong, c);
274 else
275 return errorSyntax(USAGE_NATNETWORK, "%Rrs", c);
276 }
277 }
278
279 if (!pNetName)
280 return errorSyntax(USAGE_NATNETWORK,
281 "You need to specify the --netname option");
282 /* verification */
283 switch (enmCode)
284 {
285 case OP_ADD:
286 if (!pNetworkCidr)
287 return errorSyntax(USAGE_NATNETWORK,
288 "You need to specify the --network option");
289 break;
290 case OP_MODIFY:
291 case OP_REMOVE:
292 case OP_START:
293 case OP_STOP:
294 break;
295 default:
296 AssertMsgFailedReturn(("Unknown operation (:%d)", enmCode), VERR_NOT_IMPLEMENTED);
297 }
298
299 Bstr NetName;
300 NetName = Bstr(pNetName);
301
302 ComPtr<INATNetwork> net;
303 rc = a->virtualBox->FindNATNetworkByName(NetName.mutableRaw(), net.asOutParam());
304 if (enmCode == OP_ADD)
305 {
306 if (SUCCEEDED(rc))
307 return errorArgument("NATNetwork server already exists");
308
309 CHECK_ERROR(a->virtualBox, CreateNATNetwork(NetName.raw(), net.asOutParam()));
310 if (FAILED(rc))
311 return errorArgument("Failed to create the NAT network service");
312 }
313 else if (FAILED(rc))
314 return errorArgument("NATNetwork server does not exist");
315
316 switch (enmCode)
317 {
318 case OP_ADD:
319 case OP_MODIFY:
320 {
321 if (pNetworkCidr)
322 {
323 CHECK_ERROR(net, COMSETTER(Network)(Bstr(pNetworkCidr).raw()));
324 if (FAILED(rc))
325 return errorArgument("Failed to set configuration");
326 }
327 if (dhcp >= 0)
328 {
329 CHECK_ERROR(net, COMSETTER(NeedDhcpServer) ((BOOL)dhcp));
330 if (FAILED(rc))
331 return errorArgument("Failed to set configuration");
332 }
333
334 if (ipv6 >= 0)
335 {
336 CHECK_ERROR(net, COMSETTER(IPv6Enabled) ((BOOL)ipv6));
337 if (FAILED(rc))
338 return errorArgument("Failed to set configuration");
339 }
340
341 if (!vPfName2Delete.empty())
342 {
343 VPF2DELETEITERATOR it;
344 for (it = vPfName2Delete.begin(); it != vPfName2Delete.end(); ++it)
345 {
346 CHECK_ERROR(net, RemovePortForwardRule((BOOL)(*it).fIPv6,
347 Bstr((*it).aszName).raw()));
348 if (FAILED(rc))
349 return errorArgument("Failed to delete pf");
350 }
351 }
352
353 if (!vPf2Add.empty())
354 {
355 VPF2ADDITERATOR it;
356 for (it = vPf2Add.begin(); it != vPf2Add.end(); ++it)
357 {
358 NATProtocol_T proto = NATProtocol_TCP;
359 if ((*it).iPfrProto == IPPROTO_TCP)
360 proto = NATProtocol_TCP;
361 else if ((*it).iPfrProto == IPPROTO_UDP)
362 proto = NATProtocol_UDP;
363 else
364 continue; /* XXX: warning here. */
365
366 CHECK_ERROR(net, AddPortForwardRule((BOOL)(*it).fPfrIPv6,
367 Bstr((*it).aszPfrName).raw(),
368 proto,
369 Bstr((*it).aszPfrHostAddr).raw(),
370 (*it).u16PfrHostPort,
371 Bstr((*it).aszPfrGuestAddr).raw(),
372 (*it).u16PfrGuestPort));
373 if (FAILED(rc))
374 return errorArgument("Failed to add pf");
375 }
376 }
377
378 if (loopback6Offset)
379 {
380 if (loopback6Offset == -1)
381 loopback6Offset = 0; /* deletion */
382
383 CHECK_ERROR_RET(net, COMSETTER(LoopbackIp6)(loopback6Offset), rc);
384 }
385
386 /* addLocalMapping (hostid, offset) */
387 if (!vLoopback2Add.empty())
388 {
389 /* we're expecting stings 127.0.0.1;5 */
390 LOOPBACK2DELETEADDITERATOR it;
391 for (it = vLoopback2Add.begin();
392 it != vLoopback2Add.end();
393 ++it)
394 {
395 std::string address, strOffset;
396 int pos = it->find(';');
397 LONG lOffset = 0;
398 Bstr bstrAddress;
399
400 AssertReturn(pos != -1, errorArgument("invalid loopback string"));
401
402 address = it->substr(0, pos);
403 strOffset = it->substr(pos + 1);
404
405 lOffset = RTStrToUInt32(strOffset.c_str());
406 AssertReturn(lOffset > 0, errorArgument("invalid loopback string"));
407
408 bstrAddress = Bstr(address.c_str());
409
410 CHECK_ERROR_RET(net, AddLocalMapping(bstrAddress.raw(), lOffset), rc);
411 }
412 }
413
414 if (!vLoopback2Delete.empty())
415 {
416 /* we're expecting stings 127.0.0.1 */
417 LOOPBACK2DELETEADDITERATOR it;
418 for (it = vLoopback2Add.begin();
419 it != vLoopback2Add.end();
420 ++it)
421 {
422 Bstr bstrAddress;
423 bstrAddress = Bstr(it->c_str());
424
425 CHECK_ERROR_RET(net, AddLocalMapping(bstrAddress.raw(), 0), rc);
426 }
427 }
428
429 if (enable >= 0)
430 {
431 CHECK_ERROR(net, COMSETTER(Enabled) ((BOOL)enable));
432 if (FAILED(rc))
433 return errorArgument("Failed to set configuration");
434 }
435 break;
436 }
437 case OP_REMOVE:
438 {
439 CHECK_ERROR(a->virtualBox, RemoveNATNetwork(net));
440 if (FAILED(rc))
441 return errorArgument("Failed to remove nat network");
442 break;
443 }
444 case OP_START:
445 {
446 CHECK_ERROR(net, Start(Bstr("whatever").raw()));
447 if (FAILED(rc))
448 return errorArgument("Failed to start network");
449 break;
450 }
451 case OP_STOP:
452 {
453 CHECK_ERROR(net, Stop());
454 if (FAILED(rc))
455 return errorArgument("Failed to start network");
456 break;
457 }
458 default:;
459 }
460 return 0;
461}
462
463
464int handleNATNetwork(HandlerArg *a)
465{
466 if (a->argc < 1)
467 return errorSyntax(USAGE_NATNETWORK, "Not enough parameters");
468
469 int result;
470 int cProcessed;
471 if (strcmp(a->argv[0], "modify") == 0)
472 result = handleOp(a, OP_MODIFY, 1, &cProcessed);
473 else if (strcmp(a->argv[0], "add") == 0)
474 result = handleOp(a, OP_ADD, 1, &cProcessed);
475 else if (strcmp(a->argv[0], "remove") == 0)
476 result = handleOp(a, OP_REMOVE, 1, &cProcessed);
477 else if (strcmp(a->argv[0], "start") == 0)
478 result = handleOp(a, OP_START, 1, &cProcessed);
479 else if (strcmp(a->argv[0], "stop") == 0)
480 result = handleOp(a, OP_STOP, 1, &cProcessed);
481 else
482 result = errorSyntax(USAGE_NATNETWORK, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
483
484 return result;
485}
486
487#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