VirtualBox

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

Last change on this file since 56927 was 56118, checked in by vboxsync, 10 years ago

VBoxManage: A quick command handler return-code cleanup that turned out to be rather tedious.

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