VirtualBox

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

Last change on this file since 47678 was 46658, checked in by vboxsync, 11 years ago

include VBox/com/EventQueue only if necessary

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