VirtualBox

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

Last change on this file since 74942 was 72826, checked in by vboxsync, 6 years ago

VBoxManage: test for empty() instead of comparing size() to 0

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

© 2023 Oracle
ContactPrivacy policyTerms of Use