VirtualBox

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

Last change on this file since 48096 was 48096, checked in by vboxsync, 12 years ago

VBoxManage/NATNetwork: adds -l(--loopback-4) and -L(--loopback-6)
usage

VBoxManage natnetwork modify -t nat-test-1 -l "127.0.1.3;8"

adds mapping 127.0.1.3 to network id (of nat-test-1) +8

-L adds offset for IPv6 case.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette