VirtualBox

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

Last change on this file since 79723 was 79620, checked in by vboxsync, 6 years ago

VBoxManage/dhcpserver, manpage: Build fix. bugref:9288

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.5 KB
Line 
1/* $Id: VBoxManageDHCPServer.cpp 79620 2019-07-09 01:01:48Z 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.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#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_STRING },
233 { "--del-opt", 'D', RTGETOPT_REQ_STRING },
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.c_str()).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
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