VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageDHCPServer.cpp@ 49762

Last change on this file since 49762 was 48776, checked in by vboxsync, 11 years ago

warning

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
Line 
1/* $Id: VBoxManageDHCPServer.cpp 48776 2013-09-30 20:44:32Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of dhcpserver command.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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#include <VBox/com/com.h>
23#include <VBox/com/array.h>
24#include <VBox/com/ErrorInfo.h>
25#include <VBox/com/errorprint.h>
26#include <VBox/com/VirtualBox.h>
27#endif /* !VBOX_ONLY_DOCS */
28
29#include <iprt/cidr.h>
30#include <iprt/param.h>
31#include <iprt/path.h>
32#include <iprt/stream.h>
33#include <iprt/string.h>
34#include <iprt/net.h>
35#include <iprt/getopt.h>
36#include <iprt/ctype.h>
37
38#include <VBox/log.h>
39
40#include "VBoxManage.h"
41
42#include <string>
43#include <vector>
44#include <map>
45
46#ifndef VBOX_ONLY_DOCS
47using namespace com;
48
49typedef enum enMainOpCodes
50{
51 OP_ADD = 1000,
52 OP_REMOVE,
53 OP_MODIFY
54} OPCODE;
55
56typedef std::map<DhcpOpt_T, std::string> DhcpOptMap;
57typedef DhcpOptMap::iterator DhcpOptIterator;
58typedef DhcpOptMap::value_type DhcpOptValuePair;
59
60struct VmNameSlotKey;
61typedef struct VmNameSlotKey VmNameSlotKey;
62
63struct VmNameSlotKey
64{
65 std::string VmName;
66 uint8_t u8Slot;
67
68 VmNameSlotKey(std::string aVmName, uint8_t aSlot) :
69 VmName(aVmName),
70 u8Slot(aSlot) {}
71
72 bool operator< (const VmNameSlotKey& that) const
73 {
74 if (VmName == that.VmName)
75 return u8Slot < that.u8Slot;
76 else
77 return VmName < that.VmName;
78 }
79};
80
81typedef std::map<VmNameSlotKey, DhcpOptMap> VmSlot2OptionsM;
82typedef VmSlot2OptionsM::iterator VmSlot2OptionsIterator;
83typedef VmSlot2OptionsM::value_type VmSlot2OptionsPair;
84
85typedef std::vector<VmNameSlotKey> VmConfigs;
86
87static const RTGETOPTDEF g_aDHCPIPOptions[]
88 = {
89 { "--netname", 't', RTGETOPT_REQ_STRING }, /* we use 't' instead of 'n' to avoid
90 * 1. the misspelled "-enable" long option to be treated as 'e' (for -enable) + 'n' (for -netname) + "<the_rest_opt>" (for net name)
91 * 2. the misspelled "-netmask" to be treated as 'n' (for -netname) + "<the_rest_opt>" (for net name)
92 */
93 { "-netname", 't', RTGETOPT_REQ_STRING }, // deprecated (if removed check below)
94 { "--ifname", 'f', RTGETOPT_REQ_STRING }, /* we use 'f' instead of 'i' to avoid
95 * 1. the misspelled "-disable" long option to be treated as 'd' (for -disable) + 'i' (for -ifname) + "<the_rest_opt>" (for if name)
96 */
97 { "-ifname", 'f', RTGETOPT_REQ_STRING }, // deprecated
98 { "--ip", 'a', RTGETOPT_REQ_STRING },
99 { "-ip", 'a', RTGETOPT_REQ_STRING }, // deprecated
100 { "--netmask", 'm', RTGETOPT_REQ_STRING },
101 { "-netmask", 'm', RTGETOPT_REQ_STRING }, // deprecated
102 { "--lowerip", 'l', RTGETOPT_REQ_STRING },
103 { "-lowerip", 'l', RTGETOPT_REQ_STRING }, // deprecated
104 { "--upperip", 'u', RTGETOPT_REQ_STRING },
105 { "-upperip", 'u', RTGETOPT_REQ_STRING }, // deprecated
106 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
107 { "-enable", 'e', RTGETOPT_REQ_NOTHING }, // deprecated
108 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
109 { "-disable", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
110 { "--options", 'o', RTGETOPT_REQ_NOTHING },
111 {"--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
112 {"--slot", 's', RTGETOPT_REQ_UINT8}, /* only with -o and -n */
113 {"--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
114 {"--value", 'p', RTGETOPT_REQ_STRING} /* only with -i */
115
116 };
117
118static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
119{
120 if (a->argc - iStart < 2)
121 return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");
122
123 int index = iStart;
124 HRESULT rc;
125 bool fOptionsRead = false;
126 bool fVmOptionRead = false;
127
128 const char *pszVmName = NULL;
129 const char *pNetName = NULL;
130 const char *pIfName = NULL;
131 const char * pIp = NULL;
132 const char * pNetmask = NULL;
133 const char * pLowerIp = NULL;
134 const char * pUpperIp = NULL;
135
136 uint8_t u8OptId = (uint8_t)~0;
137 uint8_t u8Slot = (uint8_t)~0;
138
139 int enable = -1;
140
141 DhcpOptMap GlobalDhcpOptions;
142 VmSlot2OptionsM VmSlot2Options;
143 VmConfigs VmConfigs2Delete;
144
145 int c;
146 RTGETOPTUNION ValueUnion;
147 RTGETOPTSTATE GetState;
148 RTGetOptInit(&GetState,
149 a->argc,
150 a->argv,
151 g_aDHCPIPOptions,
152 enmCode != OP_REMOVE ? RT_ELEMENTS(g_aDHCPIPOptions) : 4, /* we use only --netname and --ifname for remove*/
153 index,
154 RTGETOPTINIT_FLAGS_NO_STD_OPTS);
155 while ((c = RTGetOpt(&GetState, &ValueUnion)))
156 {
157 switch (c)
158 {
159 case 't': // --netname
160 if(pNetName)
161 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netname once.");
162 else if (pIfName)
163 return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ifname for identifying the DHCP server.");
164 else
165 {
166 pNetName = ValueUnion.psz;
167 }
168 break;
169 case 'f': // --ifname
170 if(pIfName)
171 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ifname once.");
172 else if (pNetName)
173 return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ipname for identifying the DHCP server.");
174 else
175 {
176 pIfName = ValueUnion.psz;
177 }
178 break;
179 case 'a': // -ip
180 if(pIp)
181 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ip once.");
182 else
183 {
184 pIp = ValueUnion.psz;
185 }
186 break;
187 case 'm': // --netmask
188 if(pNetmask)
189 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netmask once.");
190 else
191 {
192 pNetmask = ValueUnion.psz;
193 }
194 break;
195 case 'l': // --lowerip
196 if(pLowerIp)
197 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --lowerip once.");
198 else
199 {
200 pLowerIp = ValueUnion.psz;
201 }
202 break;
203 case 'u': // --upperip
204 if(pUpperIp)
205 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --upperip once.");
206 else
207 {
208 pUpperIp = ValueUnion.psz;
209 }
210 break;
211 case 'e': // --enable
212 if(enable >= 0)
213 return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
214 else
215 {
216 enable = 1;
217 }
218 break;
219 case 'd': // --disable
220 if(enable >= 0)
221 return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
222 else
223 {
224 enable = 0;
225 }
226 break;
227 case VINF_GETOPT_NOT_OPTION:
228 return errorSyntax(USAGE_DHCPSERVER, "unhandled parameter: %s", ValueUnion.psz);
229 break;
230
231 case 'o': // --options
232 {
233 // {"--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
234 // {"--slot", 's', RTGETOPT_REQ_UINT8}, /* only with -o and -n*/
235 // {"--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
236 // {"--value", 'p', RTGETOPT_REQ_STRING} /* only with -i */
237 if (fOptionsRead)
238 return errorSyntax(USAGE_DHCPSERVER,
239 "previos option edition wasn't finished");
240 fOptionsRead = true;
241 fVmOptionRead = false; /* we want specify new global or vm option*/
242 u8Slot = (uint8_t)~0;
243 u8OptId = (uint8_t)~0;
244 pszVmName = NULL;
245 } /* end of --options */
246 break;
247
248 case 'n': // --vm-name
249 {
250 if (fVmOptionRead)
251 return errorSyntax(USAGE_DHCPSERVER,
252 "previous vm option edition wasn't finished");
253 else
254 fVmOptionRead = true;
255 u8Slot = (uint8_t)~0; /* clear slor */
256 pszVmName = RTStrDup(ValueUnion.psz);
257 }
258 break; /* end of --vm-name */
259
260 case 's': // --slot
261 {
262 if (!fVmOptionRead)
263 return errorSyntax(USAGE_DHCPSERVER,
264 "vm name wasn't specified");
265
266 u8Slot = ValueUnion.u8;
267 }
268 break; /* end of --slot */
269
270 case 'i': // --id
271 {
272 if (!fOptionsRead)
273 return errorSyntax(USAGE_DHCPSERVER,
274 "-o wasn't found");
275
276 u8OptId = ValueUnion.u8;
277 }
278 break; /* end of --id */
279
280 case 'p': // --value
281 {
282 if (!fOptionsRead)
283 return errorSyntax(USAGE_DHCPSERVER,
284 "-o wasn't found");
285
286 if (u8OptId == (uint8_t)~0)
287 return errorSyntax(USAGE_DHCPSERVER,
288 "--id wasn't found");
289 if ( fVmOptionRead
290 && u8Slot == (uint8_t)~0)
291 return errorSyntax(USAGE_DHCPSERVER,
292 "--slot wasn't found");
293
294 DhcpOptMap& map = fVmOptionRead ? VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)]
295 : GlobalDhcpOptions;
296 std::string strVal = ValueUnion.psz;
297 map.insert(DhcpOptValuePair((DhcpOpt_T)u8OptId, strVal));
298
299 }
300 break; // --end of value
301
302 default:
303 if (c > 0)
304 {
305 if (RT_C_IS_GRAPH(c))
306 return errorSyntax(USAGE_DHCPSERVER, "unhandled option: -%c", c);
307 else
308 return errorSyntax(USAGE_DHCPSERVER, "unhandled option: %i", c);
309 }
310 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
311 return errorSyntax(USAGE_DHCPSERVER, "unknown option: %s", ValueUnion.psz);
312 else if (ValueUnion.pDef)
313 return errorSyntax(USAGE_DHCPSERVER, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
314 else
315 return errorSyntax(USAGE_DHCPSERVER, "%Rrs", c);
316 }
317 }
318
319 if(! pNetName && !pIfName)
320 return errorSyntax(USAGE_DHCPSERVER, "You need to specify either --netname or --ifname to identify the DHCP server");
321
322 if( enmCode != OP_REMOVE
323 && GlobalDhcpOptions.size() == 0
324 && VmSlot2Options.size() == 0)
325 {
326 if(enable < 0 || pIp || pNetmask || pLowerIp || pUpperIp)
327 {
328 if(!pIp)
329 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --ip option");
330
331 if(!pNetmask)
332 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --netmask option");
333
334 if(!pLowerIp)
335 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --lowerip option");
336
337 if(!pUpperIp)
338 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --upperip option");
339 }
340 }
341
342 Bstr NetName;
343 if(!pNetName)
344 {
345 ComPtr<IHost> host;
346 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
347
348 ComPtr<IHostNetworkInterface> hif;
349 CHECK_ERROR(host, FindHostNetworkInterfaceByName(Bstr(pIfName).mutableRaw(), hif.asOutParam()));
350 if (FAILED(rc))
351 return errorArgument("Could not find interface '%s'", pIfName);
352
353 CHECK_ERROR(hif, COMGETTER(NetworkName) (NetName.asOutParam()));
354 if (FAILED(rc))
355 return errorArgument("Could not get network name for the interface '%s'", pIfName);
356 }
357 else
358 {
359 NetName = Bstr(pNetName);
360 }
361
362 ComPtr<IDHCPServer> svr;
363 rc = a->virtualBox->FindDHCPServerByNetworkName(NetName.mutableRaw(), svr.asOutParam());
364 if(enmCode == OP_ADD)
365 {
366 if (SUCCEEDED(rc))
367 return errorArgument("DHCP server already exists");
368
369 CHECK_ERROR(a->virtualBox, CreateDHCPServer(NetName.mutableRaw(), svr.asOutParam()));
370 if (FAILED(rc))
371 return errorArgument("Failed to create the DHCP server");
372 }
373 else if (FAILED(rc))
374 {
375 return errorArgument("DHCP server does not exist");
376 }
377
378 if(enmCode != OP_REMOVE)
379 {
380 if (pIp || pNetmask || pLowerIp || pUpperIp)
381 {
382 CHECK_ERROR(svr, SetConfiguration (
383 Bstr(pIp).mutableRaw(),
384 Bstr(pNetmask).mutableRaw(),
385 Bstr(pLowerIp).mutableRaw(),
386 Bstr(pUpperIp).mutableRaw()));
387 if(FAILED(rc))
388 return errorArgument("Failed to set configuration");
389 }
390
391 if(enable >= 0)
392 {
393 CHECK_ERROR(svr, COMSETTER(Enabled) ((BOOL)enable));
394 }
395
396 /* option processing */
397 DhcpOptIterator itOpt;
398 VmSlot2OptionsIterator it;
399
400 /* Global Options */
401 for(itOpt = GlobalDhcpOptions.begin();
402 itOpt != GlobalDhcpOptions.end();
403 ++itOpt)
404 {
405 CHECK_ERROR(svr,
406 AddGlobalOption(
407 itOpt->first,
408 com::Bstr(itOpt->second.c_str()).raw()));
409 }
410
411 /* heh, vm slot options. */
412
413 for (it = VmSlot2Options.begin();
414 it != VmSlot2Options.end();
415 ++it)
416 {
417 for(itOpt = it->second.begin();
418 itOpt != it->second.end();
419 ++itOpt)
420 {
421 CHECK_ERROR(svr,
422 AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(),
423 it->first.u8Slot,
424 itOpt->first,
425 com::Bstr(itOpt->second.c_str()).raw()));
426 }
427 }
428 }
429 else
430 {
431 CHECK_ERROR(a->virtualBox, RemoveDHCPServer(svr));
432 if(FAILED(rc))
433 return errorArgument("Failed to remove server");
434 }
435
436 return 0;
437}
438
439
440int handleDHCPServer(HandlerArg *a)
441{
442 if (a->argc < 1)
443 return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");
444
445 int result;
446 int cProcessed;
447 if (strcmp(a->argv[0], "modify") == 0)
448 result = handleOp(a, OP_MODIFY, 1, &cProcessed);
449 else if (strcmp(a->argv[0], "add") == 0)
450 result = handleOp(a, OP_ADD, 1, &cProcessed);
451 else if (strcmp(a->argv[0], "remove") == 0)
452 result = handleOp(a, OP_REMOVE, 1, &cProcessed);
453 else
454 result = errorSyntax(USAGE_DHCPSERVER, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
455
456 return result;
457}
458
459#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