VirtualBox

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

最後變更 在這個檔案從75918是 75918,由 vboxsync 提交於 6 年 前

Main/DHCPServer: (bugref:9288) Renamed '--slot' to '--nic' and made it 1-based instead of 0-based.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 19.1 KB
 
1/* $Id: VBoxManageDHCPServer.cpp 75918 2018-12-03 17:09:43Z 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.alldomusa.eu.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
62typedef std::vector<DhcpOpt_T> DhcpOptIds;
63typedef DhcpOptIds::iterator DhcpOptIdIterator;
64
65struct VmNameSlotKey
66{
67 const std::string VmName;
68 uint8_t u8Slot;
69
70 VmNameSlotKey(const std::string &aVmName, uint8_t aSlot)
71 : VmName(aVmName)
72 , u8Slot(aSlot)
73 {}
74
75 bool operator< (const VmNameSlotKey& that) const
76 {
77 if (VmName == that.VmName)
78 return u8Slot < that.u8Slot;
79 else
80 return VmName < that.VmName;
81 }
82};
83
84typedef std::map<VmNameSlotKey, DhcpOpts> VmSlot2OptionsM;
85typedef VmSlot2OptionsM::iterator VmSlot2OptionsIterator;
86typedef VmSlot2OptionsM::value_type VmSlot2OptionsPair;
87
88typedef std::map<VmNameSlotKey, DhcpOptIds> VmSlot2OptionIdsM;
89typedef VmSlot2OptionIdsM::iterator VmSlot2OptionIdsIterator;
90
91typedef std::vector<VmNameSlotKey> VmConfigs;
92
93static const RTGETOPTDEF g_aDHCPIPOptions[] =
94{
95 { "--netname", 't', RTGETOPT_REQ_STRING }, /* we use 't' instead of 'n' to avoid
96 * 1. the misspelled "-enable" long option to be treated as 'e' (for -enable) + 'n' (for -netname) + "<the_rest_opt>" (for net name)
97 * 2. the misspelled "-netmask" to be treated as 'n' (for -netname) + "<the_rest_opt>" (for net name)
98 */
99 { "-netname", 't', RTGETOPT_REQ_STRING }, // deprecated (if removed check below)
100 { "--ifname", 'f', RTGETOPT_REQ_STRING }, /* we use 'f' instead of 'i' to avoid
101 * 1. the misspelled "-disable" long option to be treated as 'd' (for -disable) + 'i' (for -ifname) + "<the_rest_opt>" (for if name)
102 */
103 { "-ifname", 'f', RTGETOPT_REQ_STRING }, // deprecated
104 { "--ip", 'a', RTGETOPT_REQ_STRING },
105 { "-ip", 'a', RTGETOPT_REQ_STRING }, // deprecated
106 { "--netmask", 'm', RTGETOPT_REQ_STRING },
107 { "-netmask", 'm', RTGETOPT_REQ_STRING }, // deprecated
108 { "--lowerip", 'l', RTGETOPT_REQ_STRING },
109 { "-lowerip", 'l', RTGETOPT_REQ_STRING }, // deprecated
110 { "--upperip", 'u', RTGETOPT_REQ_STRING },
111 { "-upperip", 'u', RTGETOPT_REQ_STRING }, // deprecated
112 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
113 { "-enable", 'e', RTGETOPT_REQ_NOTHING }, // deprecated
114 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
115 { "-disable", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
116 { "--options", 'o', RTGETOPT_REQ_NOTHING },
117 { "--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
118 { "--nic", 'c', RTGETOPT_REQ_UINT8}, /* only with -o and -n */
119 { "--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
120 { "--value", 'p', RTGETOPT_REQ_STRING}, /* only with -i */
121 { "--remove", 'r', RTGETOPT_REQ_NOTHING} /* only with -i */
122};
123
124static RTEXITCODE handleOp(HandlerArg *a, OPCODE enmCode, int iStart)
125{
126 if (a->argc - iStart < 2)
127 return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");
128
129 int index = iStart;
130 HRESULT rc;
131 bool fOptionsRead = false;
132 bool fVmOptionRead = false;
133
134 const char *pszVmName = NULL;
135 const char *pNetName = NULL;
136 const char *pIfName = NULL;
137 const char * pIp = NULL;
138 const char * pNetmask = NULL;
139 const char * pLowerIp = NULL;
140 const char * pUpperIp = NULL;
141
142 uint8_t u8OptId = (uint8_t)~0;
143 uint8_t u8Slot = (uint8_t)~0;
144
145 int enable = -1;
146
147 DhcpOpts GlobalDhcpOptions;
148 DhcpOptIds GlobalDhcpOptions2Delete;
149 VmSlot2OptionsM VmSlot2Options;
150 VmSlot2OptionIdsM VmSlot2Options2Delete;
151 VmConfigs VmConfigs2Delete;
152
153 int c;
154 RTGETOPTUNION ValueUnion;
155 RTGETOPTSTATE GetState;
156 RTGetOptInit(&GetState,
157 a->argc,
158 a->argv,
159 g_aDHCPIPOptions,
160 enmCode != OP_REMOVE ? RT_ELEMENTS(g_aDHCPIPOptions) : 4, /* we use only --netname and --ifname for remove*/
161 index,
162 RTGETOPTINIT_FLAGS_NO_STD_OPTS);
163 while ((c = RTGetOpt(&GetState, &ValueUnion)))
164 {
165 switch (c)
166 {
167 case 't': // --netname
168 if(pNetName)
169 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netname once.");
170 else if (pIfName)
171 return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ifname for identifying the DHCP server.");
172 else
173 {
174 pNetName = ValueUnion.psz;
175 }
176 break;
177 case 'f': // --ifname
178 if(pIfName)
179 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ifname once.");
180 else if (pNetName)
181 return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ipname for identifying the DHCP server.");
182 else
183 {
184 pIfName = ValueUnion.psz;
185 }
186 break;
187 case 'a': // -ip
188 if(pIp)
189 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ip once.");
190 else
191 {
192 pIp = ValueUnion.psz;
193 }
194 break;
195 case 'm': // --netmask
196 if(pNetmask)
197 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netmask once.");
198 else
199 {
200 pNetmask = ValueUnion.psz;
201 }
202 break;
203 case 'l': // --lowerip
204 if(pLowerIp)
205 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --lowerip once.");
206 else
207 {
208 pLowerIp = ValueUnion.psz;
209 }
210 break;
211 case 'u': // --upperip
212 if(pUpperIp)
213 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --upperip once.");
214 else
215 {
216 pUpperIp = ValueUnion.psz;
217 }
218 break;
219 case 'e': // --enable
220 if(enable >= 0)
221 return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
222 else
223 {
224 enable = 1;
225 }
226 break;
227 case 'd': // --disable
228 if(enable >= 0)
229 return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
230 else
231 {
232 enable = 0;
233 }
234 break;
235 case VINF_GETOPT_NOT_OPTION:
236 return errorSyntax(USAGE_DHCPSERVER, "unhandled parameter: %s", ValueUnion.psz);
237 break;
238
239 case 'o': // --options
240 {
241 // {"--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
242 // {"--nic", 'c', RTGETOPT_REQ_UINT8}, /* only with -o and -n*/
243 // {"--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
244 // {"--value", 'p', RTGETOPT_REQ_STRING} /* only with -i */
245 if (fOptionsRead)
246 return errorSyntax(USAGE_DHCPSERVER,
247 "previos option edition wasn't finished");
248 fOptionsRead = true;
249 fVmOptionRead = false; /* we want specify new global or vm option*/
250 u8Slot = (uint8_t)~0;
251 u8OptId = (uint8_t)~0;
252 pszVmName = NULL;
253 } /* end of --options */
254 break;
255
256 case 'n': // --vm-name
257 {
258 if (fVmOptionRead)
259 return errorSyntax(USAGE_DHCPSERVER,
260 "previous vm option edition wasn't finished");
261 else
262 fVmOptionRead = true;
263 u8Slot = (uint8_t)~0; /* clear slor */
264 pszVmName = RTStrDup(ValueUnion.psz);
265 }
266 break; /* end of --vm-name */
267
268 case 'c': // --nic
269 {
270 if (!fVmOptionRead)
271 return errorSyntax(USAGE_DHCPSERVER,
272 "vm name wasn't specified");
273
274 u8Slot = ValueUnion.u8;
275
276 if (u8Slot < 1)
277 return errorSyntax(USAGE_DHCPSERVER,
278 "invalid NIC number: %u", u8Slot);
279 --u8Slot;
280 }
281 break; /* end of --nic */
282
283 case 'i': // --id
284 {
285 if (!fOptionsRead)
286 return errorSyntax(USAGE_DHCPSERVER,
287 "-o wasn't found");
288
289 u8OptId = ValueUnion.u8;
290 }
291 break; /* end of --id */
292
293 case 'p': // --value
294 {
295 if (!fOptionsRead)
296 return errorSyntax(USAGE_DHCPSERVER,
297 "-o wasn't found");
298
299 if (u8OptId == (uint8_t)~0)
300 return errorSyntax(USAGE_DHCPSERVER,
301 "--id wasn't found");
302 if ( fVmOptionRead
303 && u8Slot == (uint8_t)~0)
304 return errorSyntax(USAGE_DHCPSERVER,
305 "--nic wasn't found");
306
307 DhcpOpts &opts = fVmOptionRead ? VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)]
308 : GlobalDhcpOptions;
309 std::string strVal = ValueUnion.psz;
310 opts.push_back(DhcpOptSpec((DhcpOpt_T)u8OptId, strVal));
311
312 }
313 break; // --end of value
314
315 case 'r': /* --remove */
316 {
317 if (!fOptionsRead)
318 return errorSyntax(USAGE_DHCPSERVER,
319 "-o wasn't found");
320
321 if (u8OptId == (uint8_t)~0)
322 return errorSyntax(USAGE_DHCPSERVER,
323 "--id wasn't found");
324 if ( fVmOptionRead
325 && u8Slot == (uint8_t)~0)
326 return errorSyntax(USAGE_DHCPSERVER,
327 "--nic wasn't found");
328
329 DhcpOptIds &optIds = fVmOptionRead ? VmSlot2Options2Delete[VmNameSlotKey(pszVmName, u8Slot)]
330 : GlobalDhcpOptions2Delete;
331 optIds.push_back((DhcpOpt_T)u8OptId);
332 }
333 break; /* --end of remove */
334
335 default:
336 if (c > 0)
337 {
338 if (RT_C_IS_GRAPH(c))
339 return errorSyntax(USAGE_DHCPSERVER, "unhandled option: -%c", c);
340 else
341 return errorSyntax(USAGE_DHCPSERVER, "unhandled option: %i", c);
342 }
343 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
344 return errorSyntax(USAGE_DHCPSERVER, "unknown option: %s", ValueUnion.psz);
345 else if (ValueUnion.pDef)
346 return errorSyntax(USAGE_DHCPSERVER, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
347 else
348 return errorSyntax(USAGE_DHCPSERVER, "%Rrs", c);
349 }
350 }
351
352 if(! pNetName && !pIfName)
353 return errorSyntax(USAGE_DHCPSERVER, "You need to specify either --netname or --ifname to identify the DHCP server");
354
355 if( enmCode != OP_REMOVE
356 && enmCode != OP_RESTART
357 && GlobalDhcpOptions.empty()
358 && VmSlot2Options.empty()
359 && GlobalDhcpOptions2Delete.empty()
360 && VmSlot2Options2Delete.empty())
361 {
362 if(enable < 0 || pIp || pNetmask || pLowerIp || pUpperIp)
363 {
364 if(!pIp)
365 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --ip option");
366
367 if(!pNetmask)
368 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --netmask option");
369
370 if(!pLowerIp)
371 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --lowerip option");
372
373 if(!pUpperIp)
374 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --upperip option");
375 }
376 }
377
378 Bstr NetName;
379 if(!pNetName)
380 {
381 ComPtr<IHost> host;
382 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
383
384 ComPtr<IHostNetworkInterface> hif;
385 CHECK_ERROR(host, FindHostNetworkInterfaceByName(Bstr(pIfName).mutableRaw(), hif.asOutParam()));
386 if (FAILED(rc))
387 return errorArgument("Could not find interface '%s'", pIfName);
388
389 CHECK_ERROR(hif, COMGETTER(NetworkName) (NetName.asOutParam()));
390 if (FAILED(rc))
391 return errorArgument("Could not get network name for the interface '%s'", pIfName);
392 }
393 else
394 {
395 NetName = Bstr(pNetName);
396 }
397
398 ComPtr<IDHCPServer> svr;
399 rc = a->virtualBox->FindDHCPServerByNetworkName(NetName.mutableRaw(), svr.asOutParam());
400 if(enmCode == OP_ADD)
401 {
402 if (SUCCEEDED(rc))
403 return errorArgument("DHCP server already exists");
404
405 CHECK_ERROR(a->virtualBox, CreateDHCPServer(NetName.mutableRaw(), svr.asOutParam()));
406 if (FAILED(rc))
407 return errorArgument("Failed to create the DHCP server");
408 }
409 else if (FAILED(rc))
410 {
411 return errorArgument("DHCP server does not exist");
412 }
413
414 if (enmCode == OP_RESTART)
415 {
416 CHECK_ERROR(svr, Restart());
417 if(FAILED(rc))
418 return errorArgument("Failed to restart server");
419 }
420 else if (enmCode == OP_REMOVE)
421 {
422 CHECK_ERROR(a->virtualBox, RemoveDHCPServer(svr));
423 if(FAILED(rc))
424 return errorArgument("Failed to remove server");
425 }
426 else
427 {
428 if (pIp || pNetmask || pLowerIp || pUpperIp)
429 {
430 CHECK_ERROR(svr, SetConfiguration (
431 Bstr(pIp).mutableRaw(),
432 Bstr(pNetmask).mutableRaw(),
433 Bstr(pLowerIp).mutableRaw(),
434 Bstr(pUpperIp).mutableRaw()));
435 if(FAILED(rc))
436 return errorArgument("Failed to set configuration");
437 }
438
439 if(enable >= 0)
440 {
441 CHECK_ERROR(svr, COMSETTER(Enabled) ((BOOL)enable));
442 }
443
444 /* remove specified options */
445 DhcpOptIdIterator itOptId;
446 for (itOptId = GlobalDhcpOptions2Delete.begin();
447 itOptId != GlobalDhcpOptions2Delete.end();
448 ++itOptId)
449 {
450 CHECK_ERROR(svr, RemoveGlobalOption(*itOptId));
451 }
452 VmSlot2OptionIdsIterator itIdVector;
453 for (itIdVector = VmSlot2Options2Delete.begin();
454 itIdVector != VmSlot2Options2Delete.end();
455 ++itIdVector)
456 {
457 for(itOptId = itIdVector->second.begin();
458 itOptId != itIdVector->second.end();
459 ++itOptId)
460 {
461 CHECK_ERROR(svr,
462 RemoveVmSlotOption(Bstr(itIdVector->first.VmName.c_str()).raw(),
463 itIdVector->first.u8Slot,
464 *itOptId));
465 }
466 }
467
468 /* option processing */
469 DhcpOptIterator itOpt;
470 VmSlot2OptionsIterator it;
471
472 /* Global Options */
473 for(itOpt = GlobalDhcpOptions.begin();
474 itOpt != GlobalDhcpOptions.end();
475 ++itOpt)
476 {
477 CHECK_ERROR(svr,
478 AddGlobalOption(
479 itOpt->first,
480 com::Bstr(itOpt->second.c_str()).raw()));
481 }
482
483 /* heh, vm slot options. */
484
485 for (it = VmSlot2Options.begin();
486 it != VmSlot2Options.end();
487 ++it)
488 {
489 for(itOpt = it->second.begin();
490 itOpt != it->second.end();
491 ++itOpt)
492 {
493 CHECK_ERROR(svr,
494 AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(),
495 it->first.u8Slot,
496 itOpt->first,
497 com::Bstr(itOpt->second.c_str()).raw()));
498 }
499 }
500 }
501
502 return RTEXITCODE_SUCCESS;
503}
504
505
506RTEXITCODE handleDHCPServer(HandlerArg *a)
507{
508 if (a->argc < 1)
509 return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");
510
511 RTEXITCODE rcExit;
512 if (strcmp(a->argv[0], "modify") == 0)
513 rcExit = handleOp(a, OP_MODIFY, 1);
514 else if (strcmp(a->argv[0], "add") == 0)
515 rcExit = handleOp(a, OP_ADD, 1);
516 else if (strcmp(a->argv[0], "remove") == 0)
517 rcExit = handleOp(a, OP_REMOVE, 1);
518 else if (strcmp(a->argv[0], "restart") == 0)
519 rcExit = handleOp(a, OP_RESTART, 1);
520 else
521 rcExit = errorSyntax(USAGE_DHCPSERVER, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
522
523 return rcExit;
524}
525
526#endif /* !VBOX_ONLY_DOCS */
527
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette