VirtualBox

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

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

VBoxManage/dhcpserver: Code cleanups, untested. bugref:9288

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 26.9 KB
 
1/* $Id: VBoxManageDHCPServer.cpp 79616 2019-07-09 00:28: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 <string>
42#include <vector>
43#include <map>
44
45using namespace com;
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51#define DHCPD_CMD_COMMON_OPT_NETWORK 999 /**< The --network / --netname option number. */
52#define DHCPD_CMD_COMMON_OPT_INTERFACE 998 /**< The --interface / --ifname option number. */
53/** Common option definitions. */
54#define DHCPD_CMD_COMMON_OPTION_DEFS() \
55 { "--network", DHCPD_CMD_COMMON_OPT_NETWORK, RTGETOPT_REQ_STRING }, \
56 { "--netname", DHCPD_CMD_COMMON_OPT_NETWORK, RTGETOPT_REQ_STRING }, /* legacy */ \
57 { "--interface", DHCPD_CMD_COMMON_OPT_INTERFACE, RTGETOPT_REQ_STRING }, \
58 { "--ifname", DHCPD_CMD_COMMON_OPT_INTERFACE, RTGETOPT_REQ_STRING } /* legacy */
59
60/** Handles common options in the typical option parsing switch. */
61#define DHCPD_CMD_COMMON_OPTION_CASES(a_pCtx, a_ch, a_pValueUnion) \
62 case DHCPD_CMD_COMMON_OPT_NETWORK: \
63 if ((a_pCtx)->pszInterface != NULL) \
64 return errorSyntax("Either --network or --interface, not both"); \
65 (a_pCtx)->pszNetwork = ValueUnion.psz; \
66 break; \
67 case DHCPD_CMD_COMMON_OPT_INTERFACE: \
68 if ((a_pCtx)->pszNetwork != NULL) \
69 return errorSyntax("Either --interface or --network, not both"); \
70 (a_pCtx)->pszInterface = ValueUnion.psz; \
71 break
72
73
74/*********************************************************************************************************************************
75* Structures and Typedefs *
76*********************************************************************************************************************************/
77/**
78 * Definition of a dhcpserver command, with handler and various flags.
79 */
80typedef struct DHCPDCMDDEF
81{
82 /** The command name. */
83 const char *pszName;
84
85 /**
86 * Actual command handler callback.
87 *
88 * @param pCtx Pointer to command context to use.
89 */
90 DECLR3CALLBACKMEMBER(RTEXITCODE, pfnHandler, (struct DHCPDCMDCTX *pCtx, int argc, char **argv));
91
92 /** The sub-command scope flags. */
93 uint64_t fSubcommandScope;
94} DHCPDCMDDEF;
95/** Pointer to a const dhcpserver command definition. */
96typedef DHCPDCMDDEF const *PCDHCPDCMDDEF;
97
98/**
99 * dhcpserver command context (mainly for carrying common options and such).
100 */
101typedef struct DHCPDCMDCTX
102{
103 /** The handler arguments from the main() function. */
104 HandlerArg *pArg;
105 /** Pointer to the command definition. */
106 PCDHCPDCMDDEF pCmdDef;
107 /** The network name. */
108 const char *pszNetwork;
109 /** The (trunk) interface name. */
110 const char *pszInterface;
111} DHCPDCMDCTX;
112/** Pointer to a dhcpserver command context. */
113typedef DHCPDCMDCTX *PDHCPDCMDCTX;
114
115typedef std::pair<DhcpOpt_T, std::string> 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 std::string VmName;
125 uint8_t u8Slot;
126
127 VmNameSlotKey(const std::string &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, std::string(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, std::string(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 CHECK_ERROR2_RET(hrc, svr, COMGETTER(IPAddress)(bstrDhcpdIp.asOutParam()), RTEXITCODE_FAILURE);
441 if (!pszNetmask)
442 CHECK_ERROR2_RET(hrc, svr, COMGETTER(NetworkMask)(bstrNetmask.asOutParam()), RTEXITCODE_FAILURE);
443 if (!pszLowerIp)
444 CHECK_ERROR2_RET(hrc, svr, COMGETTER(LowerIP)(bstrNetmask.asOutParam()), RTEXITCODE_FAILURE);
445 if (!pszUpperIp)
446 CHECK_ERROR2_RET(hrc, svr, COMGETTER(UpperIP)(bstrNetmask.asOutParam()), RTEXITCODE_FAILURE);
447
448 CHECK_ERROR2_STMT(hrc, svr, SetConfiguration(bstrDhcpdIp.raw(), bstrNetmask.raw(), bstrLowerIp.raw(), bstrUpperIp.raw()),
449 rcExit = errorArgument("Failed to set configuration"));
450 }
451
452 if (fEnabled >= 0)
453 CHECK_ERROR2_STMT(hrc, svr, COMSETTER(Enabled)((BOOL)fEnabled), rcExit = RTEXITCODE_FAILURE);
454
455 /* Remove options: */
456 for (DhcpOptIdIterator itOptId = GlobalDhcpOptions2Delete.begin(); itOptId != GlobalDhcpOptions2Delete.end(); ++itOptId)
457 CHECK_ERROR2_STMT(hrc, svr, RemoveGlobalOption(*itOptId), rcExit = RTEXITCODE_FAILURE);
458
459 for (VmSlot2OptionIdsIterator itIdVector = VmSlot2Options2Delete.begin();
460 itIdVector != VmSlot2Options2Delete.end(); ++itIdVector)
461 for (DhcpOptIdIterator itOptId = itIdVector->second.begin(); itOptId != itIdVector->second.end(); ++itOptId)
462 CHECK_ERROR2_STMT(hrc, svr, RemoveVmSlotOption(Bstr(itIdVector->first.VmName.c_str()).raw(),
463 itIdVector->first.u8Slot, *itOptId),
464 rcExit = RTEXITCODE_FAILURE);
465
466 /* Global Options */
467 for (DhcpOptIterator itOpt = GlobalDhcpOptions.begin(); itOpt != GlobalDhcpOptions.end(); ++itOpt)
468 CHECK_ERROR2_STMT(hrc, svr, AddGlobalOption(itOpt->first, com::Bstr(itOpt->second.c_str()).raw()),
469 rcExit = RTEXITCODE_FAILURE);
470
471 /* VM slot options. */
472 for (VmSlot2OptionsIterator it = VmSlot2Options.begin(); it != VmSlot2Options.end(); ++it)
473 for (DhcpOptIterator itOpt = it->second.begin(); itOpt != it->second.end(); ++itOpt)
474 CHECK_ERROR2_STMT(hrc, svr, AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(), it->first.u8Slot, itOpt->first,
475 com::Bstr(itOpt->second.c_str()).raw()),
476 rcExit = RTEXITCODE_FAILURE);
477
478 return rcExit;
479}
480
481
482/**
483 * Handles the 'remove' subcommand.
484 */
485static RTEXITCODE dhcpdHandleRemove(PDHCPDCMDCTX pCtx, int argc, char **argv)
486{
487 /*
488 * Parse the command line.
489 */
490 static const RTGETOPTDEF s_aOptions[] =
491 {
492 DHCPD_CMD_COMMON_OPTION_DEFS(),
493 };
494
495 RTGETOPTSTATE GetState;
496 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
497 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
498
499 RTGETOPTUNION ValueUnion;
500 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
501 {
502 switch (vrc)
503 {
504 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
505 default:
506 return errorGetOpt(vrc, &ValueUnion);
507 }
508 }
509
510 /*
511 * Locate the server and perform the requested operation.
512 */
513 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
514 if (ptrDHCPServer.isNotNull())
515 {
516 HRESULT hrc;
517 CHECK_ERROR2(hrc, pCtx->pArg->virtualBox, RemoveDHCPServer(ptrDHCPServer));
518 if (SUCCEEDED(hrc))
519 return RTEXITCODE_SUCCESS;
520 errorArgument("Failed to remove server");
521 }
522 return RTEXITCODE_FAILURE;
523}
524
525
526/**
527 * Handles the 'restart' subcommand.
528 */
529static RTEXITCODE dhcpdHandleRestart(PDHCPDCMDCTX pCtx, int argc, char **argv)
530{
531 /*
532 * Parse the command line.
533 */
534 static const RTGETOPTDEF s_aOptions[] =
535 {
536 DHCPD_CMD_COMMON_OPTION_DEFS(),
537 };
538
539 RTGETOPTSTATE GetState;
540 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
541 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
542
543 RTGETOPTUNION ValueUnion;
544 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
545 {
546 switch (vrc)
547 {
548 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
549 default:
550 return errorGetOpt(vrc, &ValueUnion);
551 }
552 }
553
554 /*
555 * Locate the server and perform the requested operation.
556 */
557 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
558 if (ptrDHCPServer.isNotNull())
559 {
560 HRESULT hrc;
561 CHECK_ERROR2(hrc, ptrDHCPServer, Restart());
562 if (SUCCEEDED(hrc))
563 return RTEXITCODE_SUCCESS;
564 errorArgument("Failed to restart server");
565 }
566 return RTEXITCODE_FAILURE;
567}
568
569
570/**
571 * Handles the 'findlease' subcommand.
572 */
573static RTEXITCODE dhcpdHandleFindLease(PDHCPDCMDCTX pCtx, int argc, char **argv)
574{
575 /*
576 * Parse the command line.
577 */
578 static const RTGETOPTDEF s_aOptions[] =
579 {
580 DHCPD_CMD_COMMON_OPTION_DEFS(),
581 { "--mac-address", 'm', RTGETOPT_REQ_MACADDR },
582
583 };
584
585 bool fHaveMacAddress = false;
586 RTMAC MacAddress = { { 0, 0, 0, 0, 0, 0 } };
587
588 RTGETOPTSTATE GetState;
589 int vrc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
590 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
591
592 RTGETOPTUNION ValueUnion;
593 while ((vrc = RTGetOpt(&GetState, &ValueUnion)))
594 {
595 switch (vrc)
596 {
597 DHCPD_CMD_COMMON_OPTION_CASES(pCtx, vrc, &ValueUnion);
598
599 case 'm': // --mac-address
600 fHaveMacAddress = true;
601 MacAddress = ValueUnion.MacAddr;
602 break;
603
604 default:
605 return errorGetOpt(vrc, &ValueUnion);
606 }
607 }
608
609 if (!fHaveMacAddress)
610 return errorSyntax("You need to specify a MAC address too look for");
611
612 /*
613 * Locate the server and perform the requested operation.
614 */
615 ComPtr<IDHCPServer> ptrDHCPServer = dhcpdFindServer(pCtx);
616 if (ptrDHCPServer.isNull())
617 return RTEXITCODE_FAILURE;
618
619 char szMac[32];
620 RTStrPrintf(szMac, sizeof(szMac), "%RTmac", &MacAddress);
621 Bstr bstrAddress;
622 Bstr bstrState;
623 LONG64 secIssued = 0;
624 LONG64 secExpire = 0;
625 HRESULT hrc;
626 CHECK_ERROR2(hrc, ptrDHCPServer, FindLeaseByMAC(Bstr(szMac).raw(), 0 /*type*/,
627 bstrAddress.asOutParam(), bstrState.asOutParam(), &secIssued, &secExpire));
628 if (SUCCEEDED(hrc))
629 {
630 RTTIMESPEC TimeSpec;
631 int64_t cSecLeftToLive = secExpire - RTTimeSpecGetSeconds(RTTimeNow(&TimeSpec));
632 RTTIME Time;
633 char szIssued[RTTIME_STR_LEN];
634 RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetSeconds(&TimeSpec, secIssued)), szIssued, sizeof(szIssued), 0);
635 char szExpire[RTTIME_STR_LEN];
636 RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetSeconds(&TimeSpec, secExpire)), szExpire, sizeof(szExpire), 0);
637
638 RTPrintf("IP Address: %ls\n"
639 "MAC Address: %RTmac\n"
640 "State: %ls\n"
641 "Issued: %s (%RU64)\n"
642 "Expire: %s (%RU64)\n"
643 "TTL: %RU64 sec, currently %RU64 sec left\n",
644 bstrAddress.raw(),
645 &MacAddress,
646 bstrState.raw(),
647 szIssued, secIssued,
648 szExpire, secExpire,
649 secExpire >= secIssued ? secExpire - secIssued : 0, cSecLeftToLive > 0 ? cSecLeftToLive : 0);
650 return RTEXITCODE_SUCCESS;
651 }
652 return RTEXITCODE_FAILURE;
653}
654
655
656/**
657 * Handles the 'dhcpserver' command.
658 */
659RTEXITCODE handleDHCPServer(HandlerArg *pArg)
660{
661 /*
662 * Command definitions.
663 */
664 static const DHCPDCMDDEF s_aCmdDefs[] =
665 {
666 { "add", dhcpdHandleAddAndModify, HELP_SCOPE_DHCPSERVER_ADD },
667 { "modify", dhcpdHandleAddAndModify, HELP_SCOPE_DHCPSERVER_MODIFY },
668 { "remove", dhcpdHandleRemove, HELP_SCOPE_DHCPSERVER_REMOVE },
669 { "restart", dhcpdHandleRestart, HELP_SCOPE_DHCPSERVER_RESTART },
670 { "findlease", dhcpdHandleFindLease, HELP_SCOPE_DHCPSERVER_FINDLEASE },
671 };
672
673 /*
674 * VBoxManage dhcpserver [common-options] subcommand ...
675 */
676 DHCPDCMDCTX CmdCtx;
677 CmdCtx.pArg = pArg;
678 CmdCtx.pCmdDef = NULL;
679 CmdCtx.pszInterface = NULL;
680 CmdCtx.pszNetwork = NULL;
681
682 static const RTGETOPTDEF s_CommonOptions[] = { DHCPD_CMD_COMMON_OPTION_DEFS() };
683 RTGETOPTSTATE GetState;
684 int vrc = RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_CommonOptions, RT_ELEMENTS(s_CommonOptions), 0,
685 0 /* No sorting! */);
686 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
687
688 RTGETOPTUNION ValueUnion;
689 while ((vrc = RTGetOpt(&GetState, &ValueUnion)) != 0)
690 {
691 switch (vrc)
692 {
693 DHCPD_CMD_COMMON_OPTION_CASES(&CmdCtx, vrc, &ValueUnion);
694
695 case VINF_GETOPT_NOT_OPTION:
696 {
697 const char *pszCmd = ValueUnion.psz;
698 uint32_t iCmd;
699 for (iCmd = 0; iCmd < RT_ELEMENTS(s_aCmdDefs); iCmd++)
700 if (strcmp(s_aCmdDefs[iCmd].pszName, pszCmd) == 0)
701 {
702 CmdCtx.pCmdDef = &s_aCmdDefs[iCmd];
703 setCurrentSubcommand(s_aCmdDefs[iCmd].fSubcommandScope);
704 return s_aCmdDefs[iCmd].pfnHandler(&CmdCtx, pArg->argc - GetState.iNext + 1,
705 &pArg->argv[GetState.iNext - 1]);
706 }
707 return errorUnknownSubcommand(pszCmd);
708 }
709
710 default:
711 return errorGetOpt(vrc, &ValueUnion);
712 }
713 }
714 return errorNoSubcommand();
715}
716
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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