VirtualBox

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

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

VBoxManage/dhcpserver: More code cleanups, untested. bugref:9288

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 27.0 KB
 
1/* $Id: VBoxManageDHCPServer.cpp 79617 2019-07-09 00:38:17Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of dhcpserver command.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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#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
28#include <iprt/cidr.h>
29#include <iprt/param.h>
30#include <iprt/path.h>
31#include <iprt/stream.h>
32#include <iprt/string.h>
33#include <iprt/net.h>
34#include <iprt/getopt.h>
35#include <iprt/ctype.h>
36
37#include <VBox/log.h>
38
39#include "VBoxManage.h"
40
41#include <vector>
42#include <map>
43
44using namespace com;
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50#define DHCPD_CMD_COMMON_OPT_NETWORK 999 /**< The --network / --netname option number. */
51#define DHCPD_CMD_COMMON_OPT_INTERFACE 998 /**< The --interface / --ifname option number. */
52/** Common option definitions. */
53#define DHCPD_CMD_COMMON_OPTION_DEFS() \
54 { "--network", DHCPD_CMD_COMMON_OPT_NETWORK, RTGETOPT_REQ_STRING }, \
55 { "--netname", DHCPD_CMD_COMMON_OPT_NETWORK, RTGETOPT_REQ_STRING }, /* legacy */ \
56 { "--interface", DHCPD_CMD_COMMON_OPT_INTERFACE, RTGETOPT_REQ_STRING }, \
57 { "--ifname", DHCPD_CMD_COMMON_OPT_INTERFACE, RTGETOPT_REQ_STRING } /* legacy */
58
59/** Handles common options in the typical option parsing switch. */
60#define DHCPD_CMD_COMMON_OPTION_CASES(a_pCtx, a_ch, a_pValueUnion) \
61 case DHCPD_CMD_COMMON_OPT_NETWORK: \
62 if ((a_pCtx)->pszInterface != NULL) \
63 return errorSyntax("Either --network or --interface, not both"); \
64 (a_pCtx)->pszNetwork = ValueUnion.psz; \
65 break; \
66 case DHCPD_CMD_COMMON_OPT_INTERFACE: \
67 if ((a_pCtx)->pszNetwork != NULL) \
68 return errorSyntax("Either --interface or --network, not both"); \
69 (a_pCtx)->pszInterface = ValueUnion.psz; \
70 break
71
72
73/*********************************************************************************************************************************
74* Structures and Typedefs *
75*********************************************************************************************************************************/
76/** Pointer to a dhcpserver command context. */
77typedef struct DHCPDCMDCTX *PDHCPDCMDCTX;
78
79/**
80 * Definition of a dhcpserver command, with handler and various flags.
81 */
82typedef struct DHCPDCMDDEF
83{
84 /** The command name. */
85 const char *pszName;
86
87 /**
88 * Actual command handler callback.
89 *
90 * @param pCtx Pointer to command context to use.
91 */
92 DECLR3CALLBACKMEMBER(RTEXITCODE, pfnHandler, (PDHCPDCMDCTX pCtx, int argc, char **argv));
93
94 /** The sub-command scope flags. */
95 uint64_t fSubcommandScope;
96} DHCPDCMDDEF;
97/** Pointer to a const dhcpserver command definition. */
98typedef DHCPDCMDDEF const *PCDHCPDCMDDEF;
99
100/**
101 * dhcpserver command context (mainly for carrying common options and such).
102 */
103typedef struct DHCPDCMDCTX
104{
105 /** The handler arguments from the main() function. */
106 HandlerArg *pArg;
107 /** Pointer to the command definition. */
108 PCDHCPDCMDDEF pCmdDef;
109 /** The network name. */
110 const char *pszNetwork;
111 /** The (trunk) interface name. */
112 const char *pszInterface;
113} DHCPDCMDCTX;
114
115typedef std::pair<DhcpOpt_T, Utf8Str> DhcpOptSpec;
116typedef std::vector<DhcpOptSpec> DhcpOpts;
117typedef DhcpOpts::iterator DhcpOptIterator;
118
119typedef std::vector<DhcpOpt_T> DhcpOptIds;
120typedef DhcpOptIds::iterator DhcpOptIdIterator;
121
122struct VmNameSlotKey
123{
124 const Utf8Str VmName;
125 uint8_t u8Slot;
126
127 VmNameSlotKey(const Utf8Str &aVmName, uint8_t aSlot)
128 : VmName(aVmName)
129 , u8Slot(aSlot)
130 {}
131
132 bool operator<(const VmNameSlotKey& that) const
133 {
134 if (VmName == that.VmName)
135 return u8Slot < that.u8Slot;
136 return VmName < that.VmName;
137 }
138};
139
140typedef std::map<VmNameSlotKey, DhcpOpts> VmSlot2OptionsM;
141typedef VmSlot2OptionsM::iterator VmSlot2OptionsIterator;
142typedef VmSlot2OptionsM::value_type VmSlot2OptionsPair;
143
144typedef std::map<VmNameSlotKey, DhcpOptIds> VmSlot2OptionIdsM;
145typedef VmSlot2OptionIdsM::iterator VmSlot2OptionIdsIterator;
146
147
148
149/**
150 * Helper that find the DHCP server instance.
151 *
152 * @returns The DHCP server instance. NULL if failed (complaining done).
153 * @param pCtx The DHCP server command context.
154 */
155static ComPtr<IDHCPServer> dhcpdFindServer(PDHCPDCMDCTX pCtx)
156{
157 ComPtr<IDHCPServer> ptrRet;
158 if (pCtx->pszNetwork || pCtx->pszInterface)
159 {
160 Assert(pCtx->pszNetwork == NULL || pCtx->pszInterface == NULL);
161
162 /*
163 * We need a network name to find the DHCP server. So, if interface is
164 * given we have to look it up.
165 */
166 HRESULT hrc;
167 Bstr bstrNetName(pCtx->pszNetwork);
168 if (!pCtx->pszNetwork)
169 {
170 ComPtr<IHost> ptrIHost;
171 CHECK_ERROR2_RET(hrc, pCtx->pArg->virtualBox, COMGETTER(Host)(ptrIHost.asOutParam()), ptrRet);
172
173 Bstr bstrInterface(pCtx->pszInterface);
174 ComPtr<IHostNetworkInterface> ptrIHostIf;
175 CHECK_ERROR2(hrc, ptrIHost, FindHostNetworkInterfaceByName(bstrInterface.raw(), ptrIHostIf.asOutParam()));
176 if (FAILED(hrc))
177 {
178 errorArgument("Failed to locate host-only interface '%s'", pCtx->pszInterface);
179 return ptrRet;
180 }
181
182 CHECK_ERROR2_RET(hrc, ptrIHostIf, COMGETTER(NetworkName)(bstrNetName.asOutParam()), ptrRet);
183 }
184
185 /*
186 * Now, try locate the server
187 */
188 hrc = pCtx->pArg->virtualBox->FindDHCPServerByNetworkName(bstrNetName.raw(), ptrRet.asOutParam());
189 if (SUCCEEDED(hrc))
190 return ptrRet;
191 if (pCtx->pszNetwork)
192 errorArgument("Failed to find DHCP server for network '%s'", pCtx->pszNetwork);
193 else
194 errorArgument("Failed to find DHCP server for host-only interface '%s' (network '%ls')",
195 pCtx->pszInterface, bstrNetName.raw());
196 }
197 else
198 errorSyntax("You need to specify either --network or --interface to identify the DHCP server");
199 return ptrRet;
200}
201
202
203/**
204 * Handles the 'add' and 'modify' subcommands.
205 */
206static RTEXITCODE dhcpdHandleAddAndModify(PDHCPDCMDCTX pCtx, int argc, char **argv)
207{
208 /*
209 * Parse options.
210 */
211 static const RTGETOPTDEF s_aOptions[] =
212 {
213 DHCPD_CMD_COMMON_OPTION_DEFS(),
214 { "--ip", 'a', RTGETOPT_REQ_STRING },
215 { "-ip", 'a', RTGETOPT_REQ_STRING }, // deprecated
216 { "--netmask", 'm', RTGETOPT_REQ_STRING },
217 { "-netmask", 'm', RTGETOPT_REQ_STRING }, // deprecated
218 { "--lowerip", 'l', RTGETOPT_REQ_STRING },
219 { "-lowerip", 'l', RTGETOPT_REQ_STRING }, // deprecated
220 { "--upperip", 'u', RTGETOPT_REQ_STRING },
221 { "-upperip", 'u', RTGETOPT_REQ_STRING }, // deprecated
222 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
223 { "-enable", 'e', RTGETOPT_REQ_NOTHING }, // deprecated
224 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
225 { "-disable", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
226 { "--global", 'g', RTGETOPT_REQ_NOTHING },
227 { "--vm", 'M', RTGETOPT_REQ_STRING },
228 { "--nic", 'n', RTGETOPT_REQ_UINT8 },
229 { "--add-opt", 'A', RTGETOPT_REQ_STRING },
230 { "--del-opt", 'D', RTGETOPT_REQ_STRING },
231 { "--id", 'i', RTGETOPT_REQ_UINT8 }, // obsolete, backwards compatibility only.
232 { "--value", 'p', RTGETOPT_REQ_STRING }, // obsolete, backwards compatibility only.
233 { "--remove", 'r', RTGETOPT_REQ_NOTHING }, // obsolete, backwards compatibility only.
234 { "--options", 'o', RTGETOPT_REQ_NOTHING }, // obsolete legacy, ignored
235
236 };
237
238 const char *pszDhcpdIp = NULL;
239 const char *pszNetmask = NULL;
240 const char *pszLowerIp = NULL;
241 const char *pszUpperIp = NULL;
242 int fEnabled = -1;
243
244 DhcpOpts GlobalDhcpOptions;
245 DhcpOptIds GlobalDhcpOptions2Delete;
246 VmSlot2OptionsM VmSlot2Options;
247 VmSlot2OptionIdsM VmSlot2Options2Delete;
248
249 const char *pszVmName = NULL;
250 uint8_t u8Slot = 0;
251 DhcpOpts *pScopeOptions = &GlobalDhcpOptions;
252 DhcpOptIds *pScopeOptions2Delete = &GlobalDhcpOptions2Delete;
253
254 bool fNeedValueOrRemove = false; /* Only used with --id; remove in 6.1+ */
255 uint8_t u8OptId = 0; /* Only used too keep --id for following --value/--remove. remove in 6.1+ */
256
257 RTGETOPTSTATE GetState;
258 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
259 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
260
261 RTGETOPTUNION ValueUnion;
262 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
263 {
264 switch (vrc)
265 {
266 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
267 case 'a': // -ip
268 pszDhcpdIp = ValueUnion.psz;
269 break;
270 case 'm': // --netmask
271 pszNetmask = ValueUnion.psz;
272 break;
273 case 'l': // --lowerip
274 pszLowerIp = ValueUnion.psz;
275 break;
276 case 'u': // --upperip
277 pszUpperIp = ValueUnion.psz;
278 break;
279 case 'e': // --enable
280 fEnabled = 1;
281 break;
282 case 'd': // --disable
283 fEnabled = 0;
284 break;
285
286 case 'g': // --global Sets the option scope to 'global'.
287 if (fNeedValueOrRemove)
288 return errorSyntax("Incomplete option sequence preseeding '--global'");
289 pScopeOptions = &GlobalDhcpOptions;
290 pScopeOptions2Delete = &GlobalDhcpOptions2Delete;
291 break;
292
293 case 'M': // --vm Sets the option scope to ValueUnion.psz + 0.
294 if (fNeedValueOrRemove)
295 return errorSyntax("Incomplete option sequence preseeding '--vm'");
296 pszVmName = ValueUnion.psz;
297 u8Slot = 0;
298 pScopeOptions = &VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)];
299 pScopeOptions2Delete = &VmSlot2Options2Delete[VmNameSlotKey(pszVmName, u8Slot)];
300 break;
301
302 case 'n': // --nic Sets the option scope to pszVmName + (ValueUnion.u8 - 1).
303 if (!pszVmName)
304 return errorSyntax("--nic option requires a --vm preceeding selecting the VM it should apply to");
305 if (fNeedValueOrRemove)
306 return errorSyntax("Incomplete option sequence preseeding '--nic=%u", ValueUnion.u8);
307 u8Slot = ValueUnion.u8;
308 if (u8Slot < 1)
309 return errorSyntax("invalid NIC number: %u", u8Slot);
310 --u8Slot;
311 pScopeOptions = &VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)];
312 pScopeOptions2Delete = &VmSlot2Options2Delete[VmNameSlotKey(pszVmName, u8Slot)];
313 break;
314
315 case 'A': // --add-opt num hexvalue
316 {
317 uint8_t const idAddOpt = ValueUnion.u8;
318 vrc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_STRING);
319 if (RT_FAILURE(vrc))
320 return errorFetchValue(1, "--add-opt", vrc, &ValueUnion);
321 pScopeOptions->push_back(DhcpOptSpec((DhcpOpt_T)idAddOpt, Utf8Str(ValueUnion.psz)));
322 break;
323 }
324
325 case 'D': // --del-opt num
326 if (pCtx->pCmdDef->fSubcommandScope == HELP_SCOPE_DHCPSERVER_ADD)
327 return errorSyntax("--del-opt does not apply to the 'add' subcommand");
328 pScopeOptions2Delete->push_back((DhcpOpt_T)ValueUnion.u8);
329 break;
330
331 /*
332 * For backwards compatibility. Remove in 6.1 or later.
333 */
334
335 case 'o': // --options - obsolete, ignored.
336 break;
337
338 case 'i': // --id
339 if (fNeedValueOrRemove)
340 return errorSyntax("Incomplete option sequence preseeding '--id=%u", ValueUnion.u8);
341 u8OptId = ValueUnion.u8;
342 fNeedValueOrRemove = true;
343 break;
344
345 case 'p': // --value
346 if (!fNeedValueOrRemove)
347 return errorSyntax("--value without --id=dhcp-opt-no");
348 pScopeOptions->push_back(DhcpOptSpec((DhcpOpt_T)u8OptId, Utf8Str(ValueUnion.psz)));
349 fNeedValueOrRemove = false;
350 break;
351
352 case 'r': // --remove
353 if (pCtx->pCmdDef->fSubcommandScope == HELP_SCOPE_DHCPSERVER_ADD)
354 return errorSyntax("--remove does not apply to the 'add' subcommand");
355 if (!fNeedValueOrRemove)
356 return errorSyntax("--remove without --id=dhcp-opt-no");
357 pScopeOptions2Delete->push_back((DhcpOpt_T)u8OptId);
358 /** @todo remove from pScopeOptions */
359 fNeedValueOrRemove = false;
360 break;
361
362 default:
363 return errorGetOpt(vrc, &ValueUnion);
364 }
365 }
366
367 /*
368 * Ensure we've got mandatory options and supply defaults
369 * where needed (modify case)
370 */
371 if (!pCtx->pszNetwork && !pCtx->pszInterface)
372 return errorSyntax("You need to specify either --network or --interface to identify the DHCP server");
373
374 if (pCtx->pCmdDef->fSubcommandScope == HELP_SCOPE_DHCPSERVER_ADD)
375 {
376 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
377 if (!pszDhcpdIp)
378 rcExit = errorSyntax("Missing required option: --ip");
379 if (!pszNetmask)
380 rcExit = errorSyntax("Missing required option: --netmask");
381 if (!pszLowerIp)
382 rcExit = errorSyntax("Missing required option: --lowerip");
383 if (!pszUpperIp)
384 rcExit = errorSyntax("Missing required option: --upperip");
385 if (rcExit != RTEXITCODE_SUCCESS)
386 return rcExit;
387 }
388
389 /*
390 * Find or create the server.
391 */
392 HRESULT rc;
393 Bstr NetName;
394 if (!pCtx->pszNetwork)
395 {
396 ComPtr<IHost> host;
397 CHECK_ERROR(pCtx->pArg->virtualBox, COMGETTER(Host)(host.asOutParam()));
398
399 ComPtr<IHostNetworkInterface> hif;
400 CHECK_ERROR(host, FindHostNetworkInterfaceByName(Bstr(pCtx->pszInterface).mutableRaw(), hif.asOutParam()));
401 if (FAILED(rc))
402 return errorArgument("Could not find interface '%s'", pCtx->pszInterface);
403
404 CHECK_ERROR(hif, COMGETTER(NetworkName) (NetName.asOutParam()));
405 if (FAILED(rc))
406 return errorArgument("Could not get network name for the interface '%s'", pCtx->pszInterface);
407 }
408 else
409 {
410 NetName = Bstr(pCtx->pszNetwork);
411 }
412
413 ComPtr<IDHCPServer> svr;
414 rc = pCtx->pArg->virtualBox->FindDHCPServerByNetworkName(NetName.mutableRaw(), svr.asOutParam());
415 if (pCtx->pCmdDef->fSubcommandScope == HELP_SCOPE_DHCPSERVER_ADD)
416 {
417 if (SUCCEEDED(rc))
418 return errorArgument("DHCP server already exists");
419
420 CHECK_ERROR(pCtx->pArg->virtualBox, CreateDHCPServer(NetName.mutableRaw(), svr.asOutParam()));
421 if (FAILED(rc))
422 return errorArgument("Failed to create the DHCP server");
423 }
424 else if (FAILED(rc))
425 return errorArgument("DHCP server does not exist");
426
427 /*
428 * Apply settings.
429 */
430 HRESULT hrc;
431 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
432 if (pszDhcpdIp || pszNetmask || pszLowerIp || pszUpperIp)
433 {
434 Bstr bstrDhcpdIp(pszDhcpdIp);
435 Bstr bstrNetmask(pszNetmask);
436 Bstr bstrLowerIp(pszLowerIp);
437 Bstr bstrUpperIp(pszUpperIp);
438
439 if (!pszDhcpdIp)
440 {
441 CHECK_ERROR2_RET(hrc, svr, COMGETTER(IPAddress)(bstrDhcpdIp.asOutParam()), RTEXITCODE_FAILURE);
442 }
443 if (!pszNetmask)
444 {
445 CHECK_ERROR2_RET(hrc, svr, COMGETTER(NetworkMask)(bstrNetmask.asOutParam()), RTEXITCODE_FAILURE);
446 }
447 if (!pszLowerIp)
448 {
449 CHECK_ERROR2_RET(hrc, svr, COMGETTER(LowerIP)(bstrNetmask.asOutParam()), RTEXITCODE_FAILURE);
450 }
451 if (!pszUpperIp)
452 {
453 CHECK_ERROR2_RET(hrc, svr, COMGETTER(UpperIP)(bstrNetmask.asOutParam()), RTEXITCODE_FAILURE);
454 }
455
456 CHECK_ERROR2_STMT(hrc, svr, SetConfiguration(bstrDhcpdIp.raw(), bstrNetmask.raw(), bstrLowerIp.raw(), bstrUpperIp.raw()),
457 rcExit = errorArgument("Failed to set configuration"));
458 }
459
460 if (fEnabled >= 0)
461 {
462 CHECK_ERROR2_STMT(hrc, svr, COMSETTER(Enabled)((BOOL)fEnabled), rcExit = RTEXITCODE_FAILURE);
463 }
464
465 /* Remove options: */
466 for (DhcpOptIdIterator itOptId = GlobalDhcpOptions2Delete.begin(); itOptId != GlobalDhcpOptions2Delete.end(); ++itOptId)
467 {
468 CHECK_ERROR2_STMT(hrc, svr, RemoveGlobalOption(*itOptId), rcExit = RTEXITCODE_FAILURE);
469 }
470
471 for (VmSlot2OptionIdsIterator itIdVector = VmSlot2Options2Delete.begin();
472 itIdVector != VmSlot2Options2Delete.end(); ++itIdVector)
473 {
474 for (DhcpOptIdIterator itOptId = itIdVector->second.begin(); itOptId != itIdVector->second.end(); ++itOptId)
475 {
476 CHECK_ERROR2_STMT(hrc, svr, RemoveVmSlotOption(Bstr(itIdVector->first.VmName.c_str()).raw(),
477 itIdVector->first.u8Slot, *itOptId),
478 rcExit = RTEXITCODE_FAILURE);
479 }
480 }
481
482 /* Global Options */
483 for (DhcpOptIterator itOpt = GlobalDhcpOptions.begin(); itOpt != GlobalDhcpOptions.end(); ++itOpt)
484 {
485 CHECK_ERROR2_STMT(hrc, svr, AddGlobalOption(itOpt->first, com::Bstr(itOpt->second.c_str()).raw()),
486 rcExit = RTEXITCODE_FAILURE);
487 }
488
489 /* VM slot options. */
490 for (VmSlot2OptionsIterator it = VmSlot2Options.begin(); it != VmSlot2Options.end(); ++it)
491 {
492 for (DhcpOptIterator itOpt = it->second.begin(); itOpt != it->second.end(); ++itOpt)
493 {
494 CHECK_ERROR2_STMT(hrc, svr, AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(), it->first.u8Slot, itOpt->first,
495 com::Bstr(itOpt->second.c_str()).raw()),
496 rcExit = RTEXITCODE_FAILURE);
497 }
498 }
499
500 return rcExit;
501}
502
503
504/**
505 * Handles the 'remove' subcommand.
506 */
507static RTEXITCODE dhcpdHandleRemove(PDHCPDCMDCTX pCtx, int argc, char **argv)
508{
509 /*
510 * Parse the command line.
511 */
512 static const RTGETOPTDEF s_aOptions[] =
513 {
514 DHCPD_CMD_COMMON_OPTION_DEFS(),
515 };
516
517 RTGETOPTSTATE GetState;
518 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
519 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
520
521 RTGETOPTUNION ValueUnion;
522 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
523 {
524 switch (vrc)
525 {
526 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
527 default:
528 return errorGetOpt(vrc, &ValueUnion);
529 }
530 }
531
532 /*
533 * Locate the server and perform the requested operation.
534 */
535 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
536 if (ptrDHCPServer.isNotNull())
537 {
538 HRESULT hrc;
539 CHECK_ERROR2(hrc, pCtx->pArg->virtualBox, RemoveDHCPServer(ptrDHCPServer));
540 if (SUCCEEDED(hrc))
541 return RTEXITCODE_SUCCESS;
542 errorArgument("Failed to remove server");
543 }
544 return RTEXITCODE_FAILURE;
545}
546
547
548/**
549 * Handles the 'restart' subcommand.
550 */
551static RTEXITCODE dhcpdHandleRestart(PDHCPDCMDCTX pCtx, int argc, char **argv)
552{
553 /*
554 * Parse the command line.
555 */
556 static const RTGETOPTDEF s_aOptions[] =
557 {
558 DHCPD_CMD_COMMON_OPTION_DEFS(),
559 };
560
561 RTGETOPTSTATE GetState;
562 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
563 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
564
565 RTGETOPTUNION ValueUnion;
566 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
567 {
568 switch (vrc)
569 {
570 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
571 default:
572 return errorGetOpt(vrc, &ValueUnion);
573 }
574 }
575
576 /*
577 * Locate the server and perform the requested operation.
578 */
579 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
580 if (ptrDHCPServer.isNotNull())
581 {
582 HRESULT hrc;
583 CHECK_ERROR2(hrc, ptrDHCPServer, Restart());
584 if (SUCCEEDED(hrc))
585 return RTEXITCODE_SUCCESS;
586 errorArgument("Failed to restart server");
587 }
588 return RTEXITCODE_FAILURE;
589}
590
591
592/**
593 * Handles the 'findlease' subcommand.
594 */
595static RTEXITCODE dhcpdHandleFindLease(PDHCPDCMDCTX pCtx, int argc, char **argv)
596{
597 /*
598 * Parse the command line.
599 */
600 static const RTGETOPTDEF s_aOptions[] =
601 {
602 DHCPD_CMD_COMMON_OPTION_DEFS(),
603 { "--mac-address", 'm', RTGETOPT_REQ_MACADDR },
604
605 };
606
607 bool fHaveMacAddress = false;
608 RTMAC MacAddress = { { 0, 0, 0, 0, 0, 0 } };
609
610 RTGETOPTSTATE GetState;
611 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
612 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
613
614 RTGETOPTUNION ValueUnion;
615 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
616 {
617 switch (vrc)
618 {
619 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
620
621 case 'm': // --mac-address
622 fHaveMacAddress = true;
623 MacAddress = ValueUnion.MacAddr;
624 break;
625
626 default:
627 return errorGetOpt(vrc, &ValueUnion);
628 }
629 }
630
631 if (!fHaveMacAddress)
632 return errorSyntax("You need to specify a MAC address too look for");
633
634 /*
635 * Locate the server and perform the requested operation.
636 */
637 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
638 if (ptrDHCPServer.isNull())
639 return RTEXITCODE_FAILURE;
640
641 char szMac[32];
642 RTStrPrintf(szMac, sizeof(szMac), "%RTmac", &MacAddress);
643 Bstr bstrAddress;
644 Bstr bstrState;
645 LONG64 secIssued = 0;
646 LONG64 secExpire = 0;
647 HRESULT hrc;
648 CHECK_ERROR2(hrc, ptrDHCPServer, FindLeaseByMAC(Bstr(szMac).raw(), 0 /*type*/,
649 bstrAddress.asOutParam(), bstrState.asOutParam(), &secIssued, &secExpire));
650 if (SUCCEEDED(hrc))
651 {
652 RTTIMESPEC TimeSpec;
653 int64_t cSecLeftToLive = secExpire - RTTimeSpecGetSeconds(RTTimeNow(&TimeSpec));
654 RTTIME Time;
655 char szIssued[RTTIME_STR_LEN];
656 RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetSeconds(&TimeSpec, secIssued)), szIssued, sizeof(szIssued), 0);
657 char szExpire[RTTIME_STR_LEN];
658 RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetSeconds(&TimeSpec, secExpire)), szExpire, sizeof(szExpire), 0);
659
660 RTPrintf("IP Address: %ls\n"
661 "MAC Address: %RTmac\n"
662 "State: %ls\n"
663 "Issued: %s (%RU64)\n"
664 "Expire: %s (%RU64)\n"
665 "TTL: %RU64 sec, currently %RU64 sec left\n",
666 bstrAddress.raw(),
667 &MacAddress,
668 bstrState.raw(),
669 szIssued, secIssued,
670 szExpire, secExpire,
671 secExpire >= secIssued ? secExpire - secIssued : 0, cSecLeftToLive > 0 ? cSecLeftToLive : 0);
672 return RTEXITCODE_SUCCESS;
673 }
674 return RTEXITCODE_FAILURE;
675}
676
677
678/**
679 * Handles the 'dhcpserver' command.
680 */
681RTEXITCODE handleDHCPServer(HandlerArg *pArg)
682{
683 /*
684 * Command definitions.
685 */
686 static const DHCPDCMDDEF s_aCmdDefs[] =
687 {
688 { "add", dhcpdHandleAddAndModify, HELP_SCOPE_DHCPSERVER_ADD },
689 { "modify", dhcpdHandleAddAndModify, HELP_SCOPE_DHCPSERVER_MODIFY },
690 { "remove", dhcpdHandleRemove, HELP_SCOPE_DHCPSERVER_REMOVE },
691 { "restart", dhcpdHandleRestart, HELP_SCOPE_DHCPSERVER_RESTART },
692 { "findlease", dhcpdHandleFindLease, HELP_SCOPE_DHCPSERVER_FINDLEASE },
693 };
694
695 /*
696 * VBoxManage dhcpserver [common-options] subcommand ...
697 */
698 DHCPDCMDCTX CmdCtx;
699 CmdCtx.pArg = pArg;
700 CmdCtx.pCmdDef = NULL;
701 CmdCtx.pszInterface = NULL;
702 CmdCtx.pszNetwork = NULL;
703
704 static const RTGETOPTDEF s_CommonOptions[] = { DHCPD_CMD_COMMON_OPTION_DEFS() };
705 RTGETOPTSTATE GetState;
706 int vrc = RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_CommonOptions, RT_ELEMENTS(s_CommonOptions), 0,
707 0 /* No sorting! */);
708 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
709
710 RTGETOPTUNION ValueUnion;
711 while ((vrc = RTGetOpt(&GetState, &ValueUnion)) != 0)
712 {
713 switch (vrc)
714 {
715 DHCPD_CMD_COMMON_OPTION_CASES(&CmdCtx, vrc, &ValueUnion);
716
717 case VINF_GETOPT_NOT_OPTION:
718 {
719 const char *pszCmd = ValueUnion.psz;
720 uint32_t iCmd;
721 for (iCmd = 0; iCmd < RT_ELEMENTS(s_aCmdDefs); iCmd++)
722 if (strcmp(s_aCmdDefs[iCmd].pszName, pszCmd) == 0)
723 {
724 CmdCtx.pCmdDef = &s_aCmdDefs[iCmd];
725 setCurrentSubcommand(s_aCmdDefs[iCmd].fSubcommandScope);
726 return s_aCmdDefs[iCmd].pfnHandler(&CmdCtx, pArg->argc - GetState.iNext + 1,
727 &pArg->argv[GetState.iNext - 1]);
728 }
729 return errorUnknownSubcommand(pszCmd);
730 }
731
732 default:
733 return errorGetOpt(vrc, &ValueUnion);
734 }
735 }
736 return errorNoSubcommand();
737}
738
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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