VirtualBox

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

Last change on this file since 75814 was 75648, checked in by vboxsync, 6 years ago

Main/DHCPD: bugref:9288 Use new implementation of DHCP server (VCC 10 and GCC 4.4.4 support, other build fixes).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 KB
Line 
1/* $Id: VBoxManageDHCPServer.cpp 75648 2018-11-21 18:02:38Z 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 OP_RESTART
56} OPCODE;
57
58typedef std::pair<DhcpOpt_T, std::string> DhcpOptSpec;
59typedef std::vector<DhcpOptSpec> DhcpOpts;
60typedef DhcpOpts::iterator DhcpOptIterator;
61
62struct VmNameSlotKey
63{
64 const std::string VmName;
65 uint8_t u8Slot;
66
67 VmNameSlotKey(const std::string &aVmName, uint8_t aSlot)
68 : VmName(aVmName)
69 , u8Slot(aSlot)
70 {}
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, DhcpOpts> 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
117static RTEXITCODE handleOp(HandlerArg *a, OPCODE enmCode, int iStart)
118{
119 if (a->argc - iStart < 2)
120 return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");
121
122 int index = iStart;
123 HRESULT rc;
124 bool fOptionsRead = false;
125 bool fVmOptionRead = false;
126
127 const char *pszVmName = NULL;
128 const char *pNetName = NULL;
129 const char *pIfName = NULL;
130 const char * pIp = NULL;
131 const char * pNetmask = NULL;
132 const char * pLowerIp = NULL;
133 const char * pUpperIp = NULL;
134
135 uint8_t u8OptId = (uint8_t)~0;
136 uint8_t u8Slot = (uint8_t)~0;
137
138 int enable = -1;
139
140 DhcpOpts GlobalDhcpOptions;
141 VmSlot2OptionsM VmSlot2Options;
142 VmConfigs VmConfigs2Delete;
143
144 int c;
145 RTGETOPTUNION ValueUnion;
146 RTGETOPTSTATE GetState;
147 RTGetOptInit(&GetState,
148 a->argc,
149 a->argv,
150 g_aDHCPIPOptions,
151 enmCode != OP_REMOVE ? RT_ELEMENTS(g_aDHCPIPOptions) : 4, /* we use only --netname and --ifname for remove*/
152 index,
153 RTGETOPTINIT_FLAGS_NO_STD_OPTS);
154 while ((c = RTGetOpt(&GetState, &ValueUnion)))
155 {
156 switch (c)
157 {
158 case 't': // --netname
159 if(pNetName)
160 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netname once.");
161 else if (pIfName)
162 return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ifname for identifying the DHCP server.");
163 else
164 {
165 pNetName = ValueUnion.psz;
166 }
167 break;
168 case 'f': // --ifname
169 if(pIfName)
170 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ifname once.");
171 else if (pNetName)
172 return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ipname for identifying the DHCP server.");
173 else
174 {
175 pIfName = ValueUnion.psz;
176 }
177 break;
178 case 'a': // -ip
179 if(pIp)
180 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ip once.");
181 else
182 {
183 pIp = ValueUnion.psz;
184 }
185 break;
186 case 'm': // --netmask
187 if(pNetmask)
188 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netmask once.");
189 else
190 {
191 pNetmask = ValueUnion.psz;
192 }
193 break;
194 case 'l': // --lowerip
195 if(pLowerIp)
196 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --lowerip once.");
197 else
198 {
199 pLowerIp = ValueUnion.psz;
200 }
201 break;
202 case 'u': // --upperip
203 if(pUpperIp)
204 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --upperip once.");
205 else
206 {
207 pUpperIp = ValueUnion.psz;
208 }
209 break;
210 case 'e': // --enable
211 if(enable >= 0)
212 return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
213 else
214 {
215 enable = 1;
216 }
217 break;
218 case 'd': // --disable
219 if(enable >= 0)
220 return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
221 else
222 {
223 enable = 0;
224 }
225 break;
226 case VINF_GETOPT_NOT_OPTION:
227 return errorSyntax(USAGE_DHCPSERVER, "unhandled parameter: %s", ValueUnion.psz);
228 break;
229
230 case 'o': // --options
231 {
232 // {"--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
233 // {"--slot", 's', RTGETOPT_REQ_UINT8}, /* only with -o and -n*/
234 // {"--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
235 // {"--value", 'p', RTGETOPT_REQ_STRING} /* only with -i */
236 if (fOptionsRead)
237 return errorSyntax(USAGE_DHCPSERVER,
238 "previos option edition wasn't finished");
239 fOptionsRead = true;
240 fVmOptionRead = false; /* we want specify new global or vm option*/
241 u8Slot = (uint8_t)~0;
242 u8OptId = (uint8_t)~0;
243 pszVmName = NULL;
244 } /* end of --options */
245 break;
246
247 case 'n': // --vm-name
248 {
249 if (fVmOptionRead)
250 return errorSyntax(USAGE_DHCPSERVER,
251 "previous vm option edition wasn't finished");
252 else
253 fVmOptionRead = true;
254 u8Slot = (uint8_t)~0; /* clear slor */
255 pszVmName = RTStrDup(ValueUnion.psz);
256 }
257 break; /* end of --vm-name */
258
259 case 's': // --slot
260 {
261 if (!fVmOptionRead)
262 return errorSyntax(USAGE_DHCPSERVER,
263 "vm name wasn't specified");
264
265 u8Slot = ValueUnion.u8;
266 }
267 break; /* end of --slot */
268
269 case 'i': // --id
270 {
271 if (!fOptionsRead)
272 return errorSyntax(USAGE_DHCPSERVER,
273 "-o wasn't found");
274
275 u8OptId = ValueUnion.u8;
276 }
277 break; /* end of --id */
278
279 case 'p': // --value
280 {
281 if (!fOptionsRead)
282 return errorSyntax(USAGE_DHCPSERVER,
283 "-o wasn't found");
284
285 if (u8OptId == (uint8_t)~0)
286 return errorSyntax(USAGE_DHCPSERVER,
287 "--id wasn't found");
288 if ( fVmOptionRead
289 && u8Slot == (uint8_t)~0)
290 return errorSyntax(USAGE_DHCPSERVER,
291 "--slot wasn't found");
292
293 DhcpOpts &opts = fVmOptionRead ? VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)]
294 : GlobalDhcpOptions;
295 std::string strVal = ValueUnion.psz;
296 opts.push_back(DhcpOptSpec((DhcpOpt_T)u8OptId, strVal));
297
298 }
299 break; // --end of value
300
301 default:
302 if (c > 0)
303 {
304 if (RT_C_IS_GRAPH(c))
305 return errorSyntax(USAGE_DHCPSERVER, "unhandled option: -%c", c);
306 else
307 return errorSyntax(USAGE_DHCPSERVER, "unhandled option: %i", c);
308 }
309 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
310 return errorSyntax(USAGE_DHCPSERVER, "unknown option: %s", ValueUnion.psz);
311 else if (ValueUnion.pDef)
312 return errorSyntax(USAGE_DHCPSERVER, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
313 else
314 return errorSyntax(USAGE_DHCPSERVER, "%Rrs", c);
315 }
316 }
317
318 if(! pNetName && !pIfName)
319 return errorSyntax(USAGE_DHCPSERVER, "You need to specify either --netname or --ifname to identify the DHCP server");
320
321 if( enmCode != OP_REMOVE
322 && enmCode != OP_RESTART
323 && GlobalDhcpOptions.empty()
324 && VmSlot2Options.empty())
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_RESTART)
379 {
380 CHECK_ERROR(svr, Restart());
381 if(FAILED(rc))
382 return errorArgument("Failed to restart server");
383 }
384 else if (enmCode == OP_REMOVE)
385 {
386 CHECK_ERROR(a->virtualBox, RemoveDHCPServer(svr));
387 if(FAILED(rc))
388 return errorArgument("Failed to remove server");
389 }
390 else
391 {
392 if (pIp || pNetmask || pLowerIp || pUpperIp)
393 {
394 CHECK_ERROR(svr, SetConfiguration (
395 Bstr(pIp).mutableRaw(),
396 Bstr(pNetmask).mutableRaw(),
397 Bstr(pLowerIp).mutableRaw(),
398 Bstr(pUpperIp).mutableRaw()));
399 if(FAILED(rc))
400 return errorArgument("Failed to set configuration");
401 }
402
403 if(enable >= 0)
404 {
405 CHECK_ERROR(svr, COMSETTER(Enabled) ((BOOL)enable));
406 }
407
408 /* option processing */
409 DhcpOptIterator itOpt;
410 VmSlot2OptionsIterator it;
411
412 /* Global Options */
413 for(itOpt = GlobalDhcpOptions.begin();
414 itOpt != GlobalDhcpOptions.end();
415 ++itOpt)
416 {
417 CHECK_ERROR(svr,
418 AddGlobalOption(
419 itOpt->first,
420 com::Bstr(itOpt->second.c_str()).raw()));
421 }
422
423 /* heh, vm slot options. */
424
425 for (it = VmSlot2Options.begin();
426 it != VmSlot2Options.end();
427 ++it)
428 {
429 for(itOpt = it->second.begin();
430 itOpt != it->second.end();
431 ++itOpt)
432 {
433 CHECK_ERROR(svr,
434 AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(),
435 it->first.u8Slot,
436 itOpt->first,
437 com::Bstr(itOpt->second.c_str()).raw()));
438 }
439 }
440 }
441
442 return RTEXITCODE_SUCCESS;
443}
444
445
446RTEXITCODE handleDHCPServer(HandlerArg *a)
447{
448 if (a->argc < 1)
449 return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");
450
451 RTEXITCODE rcExit;
452 if (strcmp(a->argv[0], "modify") == 0)
453 rcExit = handleOp(a, OP_MODIFY, 1);
454 else if (strcmp(a->argv[0], "add") == 0)
455 rcExit = handleOp(a, OP_ADD, 1);
456 else if (strcmp(a->argv[0], "remove") == 0)
457 rcExit = handleOp(a, OP_REMOVE, 1);
458 else if (strcmp(a->argv[0], "restart") == 0)
459 rcExit = handleOp(a, OP_RESTART, 1);
460 else
461 rcExit = errorSyntax(USAGE_DHCPSERVER, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
462
463 return rcExit;
464}
465
466#endif /* !VBOX_ONLY_DOCS */
467
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