VirtualBox

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

Last change on this file since 48854 was 48405, checked in by vboxsync, 11 years ago

NAT/Loopback mapping: changes semantically unrelated symbol ";" with more expressive "=" for map opperation.

VBoxManage natnework modify -t nat-test-1 -l "127.0.1.3=8"

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