VirtualBox

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

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

Main/DHCPServer,Dhcpd,VBoxManage: Added --log option to the DHCP server so we can start logging early. Added log rotation and limits. Put the config file next to the log and leases file. Validate DHCP options by reusing the parser code from the server, adding a bunch more DHCP options to the parser. Removed legacy and hardcoded configuration options from the dhcp server, it's all config file now. Fixed a bug in the option parsing of the VBoxManage dhcpserver add/modify commands. bugref:9288

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 27.5 KB
 
1/* $Id: VBoxManageDHCPServer.cpp 79761 2019-07-14 03:18:41Z 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 DECLCALLBACK(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 { "--server-ip", 'a', RTGETOPT_REQ_STRING },
215 { "--ip", 'a', RTGETOPT_REQ_STRING }, // deprecated
216 { "-ip", 'a', RTGETOPT_REQ_STRING }, // deprecated
217 { "--netmask", 'm', RTGETOPT_REQ_STRING },
218 { "-netmask", 'm', RTGETOPT_REQ_STRING }, // deprecated
219 { "--lower-ip", 'l', RTGETOPT_REQ_STRING },
220 { "--lowerip", 'l', RTGETOPT_REQ_STRING },
221 { "-lowerip", 'l', RTGETOPT_REQ_STRING }, // deprecated
222 { "--upper-ip", 'u', RTGETOPT_REQ_STRING },
223 { "--upperip", 'u', RTGETOPT_REQ_STRING },
224 { "-upperip", 'u', RTGETOPT_REQ_STRING }, // deprecated
225 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
226 { "-enable", 'e', RTGETOPT_REQ_NOTHING }, // deprecated
227 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
228 { "-disable", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
229 { "--global", 'g', RTGETOPT_REQ_NOTHING },
230 { "--vm", 'M', RTGETOPT_REQ_STRING },
231 { "--nic", 'n', RTGETOPT_REQ_UINT8 },
232 { "--add-opt", 'A', RTGETOPT_REQ_UINT8 },
233 { "--del-opt", 'D', RTGETOPT_REQ_UINT8 },
234 { "--id", 'i', RTGETOPT_REQ_UINT8 }, // obsolete, backwards compatibility only.
235 { "--value", 'p', RTGETOPT_REQ_STRING }, // obsolete, backwards compatibility only.
236 { "--remove", 'r', RTGETOPT_REQ_NOTHING }, // obsolete, backwards compatibility only.
237 { "--options", 'o', RTGETOPT_REQ_NOTHING }, // obsolete legacy, ignored
238
239 };
240
241 const char *pszServerIp = NULL;
242 const char *pszNetmask = NULL;
243 const char *pszLowerIp = NULL;
244 const char *pszUpperIp = NULL;
245 int fEnabled = -1;
246
247 DhcpOpts GlobalDhcpOptions;
248 DhcpOptIds GlobalDhcpOptions2Delete;
249 VmSlot2OptionsM VmSlot2Options;
250 VmSlot2OptionIdsM VmSlot2Options2Delete;
251
252 const char *pszVmName = NULL;
253 uint8_t u8Slot = 0;
254 DhcpOpts *pScopeOptions = &GlobalDhcpOptions;
255 DhcpOptIds *pScopeOptions2Delete = &GlobalDhcpOptions2Delete;
256
257 bool fNeedValueOrRemove = false; /* Only used with --id; remove in 6.1+ */
258 uint8_t u8OptId = 0; /* Only used too keep --id for following --value/--remove. remove in 6.1+ */
259
260 RTGETOPTSTATE GetState;
261 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
262 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
263
264 RTGETOPTUNION ValueUnion;
265 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
266 {
267 switch (vrc)
268 {
269 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
270 case 'a': // --server-ip
271 pszServerIp = ValueUnion.psz;
272 break;
273 case 'm': // --netmask
274 pszNetmask = ValueUnion.psz;
275 break;
276 case 'l': // --lower-ip
277 pszLowerIp = ValueUnion.psz;
278 break;
279 case 'u': // --upper-ip
280 pszUpperIp = ValueUnion.psz;
281 break;
282 case 'e': // --enable
283 fEnabled = 1;
284 break;
285 case 'd': // --disable
286 fEnabled = 0;
287 break;
288
289 case 'g': // --global Sets the option scope to 'global'.
290 if (fNeedValueOrRemove)
291 return errorSyntax("Incomplete option sequence preseeding '--global'");
292 pScopeOptions = &GlobalDhcpOptions;
293 pScopeOptions2Delete = &GlobalDhcpOptions2Delete;
294 break;
295
296 case 'M': // --vm Sets the option scope to ValueUnion.psz + 0.
297 if (fNeedValueOrRemove)
298 return errorSyntax("Incomplete option sequence preseeding '--vm'");
299 pszVmName = ValueUnion.psz;
300 u8Slot = 0;
301 pScopeOptions = &VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)];
302 pScopeOptions2Delete = &VmSlot2Options2Delete[VmNameSlotKey(pszVmName, u8Slot)];
303 break;
304
305 case 'n': // --nic Sets the option scope to pszVmName + (ValueUnion.u8 - 1).
306 if (!pszVmName)
307 return errorSyntax("--nic option requires a --vm preceeding selecting the VM it should apply to");
308 if (fNeedValueOrRemove)
309 return errorSyntax("Incomplete option sequence preseeding '--nic=%u", ValueUnion.u8);
310 u8Slot = ValueUnion.u8;
311 if (u8Slot < 1)
312 return errorSyntax("invalid NIC number: %u", u8Slot);
313 --u8Slot;
314 pScopeOptions = &VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)];
315 pScopeOptions2Delete = &VmSlot2Options2Delete[VmNameSlotKey(pszVmName, u8Slot)];
316 break;
317
318 case 'A': // --add-opt num hexvalue
319 {
320 uint8_t const idAddOpt = ValueUnion.u8;
321 vrc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_STRING);
322 if (RT_FAILURE(vrc))
323 return errorFetchValue(1, "--add-opt", vrc, &ValueUnion);
324 pScopeOptions->push_back(DhcpOptSpec((DhcpOpt_T)idAddOpt, Utf8Str(ValueUnion.psz)));
325 break;
326 }
327
328 case 'D': // --del-opt num
329 if (pCtx->pCmdDef->fSubcommandScope == HELP_SCOPE_DHCPSERVER_ADD)
330 return errorSyntax("--del-opt does not apply to the 'add' subcommand");
331 pScopeOptions2Delete->push_back((DhcpOpt_T)ValueUnion.u8);
332 break;
333
334 /*
335 * For backwards compatibility. Remove in 6.1 or later.
336 */
337
338 case 'o': // --options - obsolete, ignored.
339 break;
340
341 case 'i': // --id
342 if (fNeedValueOrRemove)
343 return errorSyntax("Incomplete option sequence preseeding '--id=%u", ValueUnion.u8);
344 u8OptId = ValueUnion.u8;
345 fNeedValueOrRemove = true;
346 break;
347
348 case 'p': // --value
349 if (!fNeedValueOrRemove)
350 return errorSyntax("--value without --id=dhcp-opt-no");
351 pScopeOptions->push_back(DhcpOptSpec((DhcpOpt_T)u8OptId, Utf8Str(ValueUnion.psz)));
352 fNeedValueOrRemove = false;
353 break;
354
355 case 'r': // --remove
356 if (pCtx->pCmdDef->fSubcommandScope == HELP_SCOPE_DHCPSERVER_ADD)
357 return errorSyntax("--remove does not apply to the 'add' subcommand");
358 if (!fNeedValueOrRemove)
359 return errorSyntax("--remove without --id=dhcp-opt-no");
360 pScopeOptions2Delete->push_back((DhcpOpt_T)u8OptId);
361 /** @todo remove from pScopeOptions */
362 fNeedValueOrRemove = false;
363 break;
364
365 default:
366 return errorGetOpt(vrc, &ValueUnion);
367 }
368 }
369
370 /*
371 * Ensure we've got mandatory options and supply defaults
372 * where needed (modify case)
373 */
374 if (!pCtx->pszNetwork && !pCtx->pszInterface)
375 return errorSyntax("You need to specify either --network or --interface to identify the DHCP server");
376
377 if (pCtx->pCmdDef->fSubcommandScope == HELP_SCOPE_DHCPSERVER_ADD)
378 {
379 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
380 if (!pszServerIp)
381 rcExit = errorSyntax("Missing required option: --ip");
382 if (!pszNetmask)
383 rcExit = errorSyntax("Missing required option: --netmask");
384 if (!pszLowerIp)
385 rcExit = errorSyntax("Missing required option: --lowerip");
386 if (!pszUpperIp)
387 rcExit = errorSyntax("Missing required option: --upperip");
388 if (rcExit != RTEXITCODE_SUCCESS)
389 return rcExit;
390 }
391
392 /*
393 * Find or create the server.
394 */
395 HRESULT rc;
396 Bstr NetName;
397 if (!pCtx->pszNetwork)
398 {
399 ComPtr<IHost> host;
400 CHECK_ERROR(pCtx->pArg->virtualBox, COMGETTER(Host)(host.asOutParam()));
401
402 ComPtr<IHostNetworkInterface> hif;
403 CHECK_ERROR(host, FindHostNetworkInterfaceByName(Bstr(pCtx->pszInterface).mutableRaw(), hif.asOutParam()));
404 if (FAILED(rc))
405 return errorArgument("Could not find interface '%s'", pCtx->pszInterface);
406
407 CHECK_ERROR(hif, COMGETTER(NetworkName) (NetName.asOutParam()));
408 if (FAILED(rc))
409 return errorArgument("Could not get network name for the interface '%s'", pCtx->pszInterface);
410 }
411 else
412 {
413 NetName = Bstr(pCtx->pszNetwork);
414 }
415
416 ComPtr<IDHCPServer> svr;
417 rc = pCtx->pArg->virtualBox->FindDHCPServerByNetworkName(NetName.mutableRaw(), svr.asOutParam());
418 if (pCtx->pCmdDef->fSubcommandScope == HELP_SCOPE_DHCPSERVER_ADD)
419 {
420 if (SUCCEEDED(rc))
421 return errorArgument("DHCP server already exists");
422
423 CHECK_ERROR(pCtx->pArg->virtualBox, CreateDHCPServer(NetName.mutableRaw(), svr.asOutParam()));
424 if (FAILED(rc))
425 return errorArgument("Failed to create the DHCP server");
426 }
427 else if (FAILED(rc))
428 return errorArgument("DHCP server does not exist");
429
430 /*
431 * Apply settings.
432 */
433 HRESULT hrc;
434 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
435 if (pszServerIp || pszNetmask || pszLowerIp || pszUpperIp)
436 {
437 Bstr bstrServerIp(pszServerIp);
438 Bstr bstrNetmask(pszNetmask);
439 Bstr bstrLowerIp(pszLowerIp);
440 Bstr bstrUpperIp(pszUpperIp);
441
442 if (!pszServerIp)
443 {
444 CHECK_ERROR2_RET(hrc, svr, COMGETTER(IPAddress)(bstrServerIp.asOutParam()), RTEXITCODE_FAILURE);
445 }
446 if (!pszNetmask)
447 {
448 CHECK_ERROR2_RET(hrc, svr, COMGETTER(NetworkMask)(bstrNetmask.asOutParam()), RTEXITCODE_FAILURE);
449 }
450 if (!pszLowerIp)
451 {
452 CHECK_ERROR2_RET(hrc, svr, COMGETTER(LowerIP)(bstrLowerIp.asOutParam()), RTEXITCODE_FAILURE);
453 }
454 if (!pszUpperIp)
455 {
456 CHECK_ERROR2_RET(hrc, svr, COMGETTER(UpperIP)(bstrUpperIp.asOutParam()), RTEXITCODE_FAILURE);
457 }
458
459 CHECK_ERROR2_STMT(hrc, svr, SetConfiguration(bstrServerIp.raw(), bstrNetmask.raw(), bstrLowerIp.raw(), bstrUpperIp.raw()),
460 rcExit = errorArgument("Failed to set configuration (%ls, %ls, %ls, %ls)", bstrServerIp.raw(),
461 bstrNetmask.raw(), bstrLowerIp.raw(), bstrUpperIp.raw()));
462 }
463
464 if (fEnabled >= 0)
465 {
466 CHECK_ERROR2_STMT(hrc, svr, COMSETTER(Enabled)((BOOL)fEnabled), rcExit = RTEXITCODE_FAILURE);
467 }
468
469 /* Remove options: */
470 for (DhcpOptIdIterator itOptId = GlobalDhcpOptions2Delete.begin(); itOptId != GlobalDhcpOptions2Delete.end(); ++itOptId)
471 {
472 CHECK_ERROR2_STMT(hrc, svr, RemoveGlobalOption(*itOptId), rcExit = RTEXITCODE_FAILURE);
473 }
474
475 for (VmSlot2OptionIdsIterator itIdVector = VmSlot2Options2Delete.begin();
476 itIdVector != VmSlot2Options2Delete.end(); ++itIdVector)
477 {
478 for (DhcpOptIdIterator itOptId = itIdVector->second.begin(); itOptId != itIdVector->second.end(); ++itOptId)
479 {
480 CHECK_ERROR2_STMT(hrc, svr, RemoveVmSlotOption(Bstr(itIdVector->first.VmName.c_str()).raw(),
481 itIdVector->first.u8Slot, *itOptId),
482 rcExit = RTEXITCODE_FAILURE);
483 }
484 }
485
486 /* Global Options */
487 for (DhcpOptIterator itOpt = GlobalDhcpOptions.begin(); itOpt != GlobalDhcpOptions.end(); ++itOpt)
488 {
489 CHECK_ERROR2_STMT(hrc, svr, AddGlobalOption(itOpt->first, com::Bstr(itOpt->second.c_str()).raw()),
490 rcExit = RTEXITCODE_FAILURE);
491 }
492
493 /* VM slot options. */
494 for (VmSlot2OptionsIterator it = VmSlot2Options.begin(); it != VmSlot2Options.end(); ++it)
495 {
496 for (DhcpOptIterator itOpt = it->second.begin(); itOpt != it->second.end(); ++itOpt)
497 {
498 CHECK_ERROR2_STMT(hrc, svr, AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(), it->first.u8Slot, itOpt->first,
499 com::Bstr(itOpt->second).raw()),
500 rcExit = RTEXITCODE_FAILURE);
501 }
502 }
503
504 return rcExit;
505}
506
507
508/**
509 * Handles the 'remove' subcommand.
510 */
511static DECLCALLBACK(RTEXITCODE) dhcpdHandleRemove(PDHCPDCMDCTX pCtx, int argc, char **argv)
512{
513 /*
514 * Parse the command line.
515 */
516 static const RTGETOPTDEF s_aOptions[] =
517 {
518 DHCPD_CMD_COMMON_OPTION_DEFS(),
519 };
520
521 RTGETOPTSTATE GetState;
522 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
523 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
524
525 RTGETOPTUNION ValueUnion;
526 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
527 {
528 switch (vrc)
529 {
530 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
531 default:
532 return errorGetOpt(vrc, &ValueUnion);
533 }
534 }
535
536 /*
537 * Locate the server and perform the requested operation.
538 */
539 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
540 if (ptrDHCPServer.isNotNull())
541 {
542 HRESULT hrc;
543 CHECK_ERROR2(hrc, pCtx->pArg->virtualBox, RemoveDHCPServer(ptrDHCPServer));
544 if (SUCCEEDED(hrc))
545 return RTEXITCODE_SUCCESS;
546 errorArgument("Failed to remove server");
547 }
548 return RTEXITCODE_FAILURE;
549}
550
551
552/**
553 * Handles the 'restart' subcommand.
554 */
555static DECLCALLBACK(RTEXITCODE) dhcpdHandleRestart(PDHCPDCMDCTX pCtx, int argc, char **argv)
556{
557 /*
558 * Parse the command line.
559 */
560 static const RTGETOPTDEF s_aOptions[] =
561 {
562 DHCPD_CMD_COMMON_OPTION_DEFS(),
563 };
564
565 RTGETOPTSTATE GetState;
566 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
567 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
568
569 RTGETOPTUNION ValueUnion;
570 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
571 {
572 switch (vrc)
573 {
574 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
575 default:
576 return errorGetOpt(vrc, &ValueUnion);
577 }
578 }
579
580 /*
581 * Locate the server and perform the requested operation.
582 */
583 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
584 if (ptrDHCPServer.isNotNull())
585 {
586 HRESULT hrc;
587 CHECK_ERROR2(hrc, ptrDHCPServer, Restart());
588 if (SUCCEEDED(hrc))
589 return RTEXITCODE_SUCCESS;
590 errorArgument("Failed to restart server");
591 }
592 return RTEXITCODE_FAILURE;
593}
594
595
596/**
597 * Handles the 'findlease' subcommand.
598 */
599static DECLCALLBACK(RTEXITCODE) dhcpdHandleFindLease(PDHCPDCMDCTX pCtx, int argc, char **argv)
600{
601 /*
602 * Parse the command line.
603 */
604 static const RTGETOPTDEF s_aOptions[] =
605 {
606 DHCPD_CMD_COMMON_OPTION_DEFS(),
607 { "--mac-address", 'm', RTGETOPT_REQ_MACADDR },
608
609 };
610
611 bool fHaveMacAddress = false;
612 RTMAC MacAddress = { { 0, 0, 0, 0, 0, 0 } };
613
614 RTGETOPTSTATE GetState;
615 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
616 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
617
618 RTGETOPTUNION ValueUnion;
619 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
620 {
621 switch (vrc)
622 {
623 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
624
625 case 'm': // --mac-address
626 fHaveMacAddress = true;
627 MacAddress = ValueUnion.MacAddr;
628 break;
629
630 default:
631 return errorGetOpt(vrc, &ValueUnion);
632 }
633 }
634
635 if (!fHaveMacAddress)
636 return errorSyntax("You need to specify a MAC address too look for");
637
638 /*
639 * Locate the server and perform the requested operation.
640 */
641 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
642 if (ptrDHCPServer.isNull())
643 return RTEXITCODE_FAILURE;
644
645 char szMac[32];
646 RTStrPrintf(szMac, sizeof(szMac), "%RTmac", &MacAddress);
647 Bstr bstrAddress;
648 Bstr bstrState;
649 LONG64 secIssued = 0;
650 LONG64 secExpire = 0;
651 HRESULT hrc;
652 CHECK_ERROR2(hrc, ptrDHCPServer, FindLeaseByMAC(Bstr(szMac).raw(), 0 /*type*/,
653 bstrAddress.asOutParam(), bstrState.asOutParam(), &secIssued, &secExpire));
654 if (SUCCEEDED(hrc))
655 {
656 RTTIMESPEC TimeSpec;
657 int64_t cSecLeftToLive = secExpire - RTTimeSpecGetSeconds(RTTimeNow(&TimeSpec));
658 RTTIME Time;
659 char szIssued[RTTIME_STR_LEN];
660 RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetSeconds(&TimeSpec, secIssued)), szIssued, sizeof(szIssued), 0);
661 char szExpire[RTTIME_STR_LEN];
662 RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetSeconds(&TimeSpec, secExpire)), szExpire, sizeof(szExpire), 0);
663
664 RTPrintf("IP Address: %ls\n"
665 "MAC Address: %RTmac\n"
666 "State: %ls\n"
667 "Issued: %s (%RU64)\n"
668 "Expire: %s (%RU64)\n"
669 "TTL: %RU64 sec, currently %RU64 sec left\n",
670 bstrAddress.raw(),
671 &MacAddress,
672 bstrState.raw(),
673 szIssued, secIssued,
674 szExpire, secExpire,
675 secExpire >= secIssued ? secExpire - secIssued : 0, cSecLeftToLive > 0 ? cSecLeftToLive : 0);
676 return RTEXITCODE_SUCCESS;
677 }
678 return RTEXITCODE_FAILURE;
679}
680
681
682/**
683 * Handles the 'dhcpserver' command.
684 */
685RTEXITCODE handleDHCPServer(HandlerArg *pArg)
686{
687 /*
688 * Command definitions.
689 */
690 static const DHCPDCMDDEF s_aCmdDefs[] =
691 {
692 { "add", dhcpdHandleAddAndModify, HELP_SCOPE_DHCPSERVER_ADD },
693 { "modify", dhcpdHandleAddAndModify, HELP_SCOPE_DHCPSERVER_MODIFY },
694 { "remove", dhcpdHandleRemove, HELP_SCOPE_DHCPSERVER_REMOVE },
695 { "restart", dhcpdHandleRestart, HELP_SCOPE_DHCPSERVER_RESTART },
696 { "findlease", dhcpdHandleFindLease, HELP_SCOPE_DHCPSERVER_FINDLEASE },
697 };
698
699 /*
700 * VBoxManage dhcpserver [common-options] subcommand ...
701 */
702 DHCPDCMDCTX CmdCtx;
703 CmdCtx.pArg = pArg;
704 CmdCtx.pCmdDef = NULL;
705 CmdCtx.pszInterface = NULL;
706 CmdCtx.pszNetwork = NULL;
707
708 static const RTGETOPTDEF s_CommonOptions[] = { DHCPD_CMD_COMMON_OPTION_DEFS() };
709 RTGETOPTSTATE GetState;
710 int vrc = RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_CommonOptions, RT_ELEMENTS(s_CommonOptions), 0,
711 0 /* No sorting! */);
712 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
713
714 RTGETOPTUNION ValueUnion;
715 while ((vrc = RTGetOpt(&GetState, &ValueUnion)) != 0)
716 {
717 switch (vrc)
718 {
719 DHCPD_CMD_COMMON_OPTION_CASES(&CmdCtx, vrc, &ValueUnion);
720
721 case VINF_GETOPT_NOT_OPTION:
722 {
723 const char *pszCmd = ValueUnion.psz;
724 uint32_t iCmd;
725 for (iCmd = 0; iCmd < RT_ELEMENTS(s_aCmdDefs); iCmd++)
726 if (strcmp(s_aCmdDefs[iCmd].pszName, pszCmd) == 0)
727 {
728 CmdCtx.pCmdDef = &s_aCmdDefs[iCmd];
729 setCurrentSubcommand(s_aCmdDefs[iCmd].fSubcommandScope);
730 return s_aCmdDefs[iCmd].pfnHandler(&CmdCtx, pArg->argc - GetState.iNext + 1,
731 &pArg->argv[GetState.iNext - 1]);
732 }
733 return errorUnknownSubcommand(pszCmd);
734 }
735
736 default:
737 return errorGetOpt(vrc, &ValueUnion);
738 }
739 }
740 return errorNoSubcommand();
741}
742
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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