VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/DHCPServerImpl.cpp@ 76066

Last change on this file since 76066 was 75819, checked in by vboxsync, 6 years ago

Main/DHCPServer: (bugref:9288) Allow removal of DHCP options, show options when listing DHCP servers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.6 KB
Line 
1/* $Id: DHCPServerImpl.cpp 75819 2018-11-29 16:16:40Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2017 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include <string>
21#include "NetworkServiceRunner.h"
22#include "DHCPServerImpl.h"
23#include "AutoCaller.h"
24#include "Logging.h"
25
26#include <iprt/asm.h>
27#include <iprt/file.h>
28#include <iprt/net.h>
29#include <iprt/path.h>
30#include <iprt/cpp/utils.h>
31#include <iprt/cpp/xml.h>
32
33#include <VBox/com/array.h>
34#include <VBox/settings.h>
35
36#include "VirtualBoxImpl.h"
37
38// constructor / destructor
39/////////////////////////////////////////////////////////////////////////////
40const std::string DHCPServerRunner::kDsrKeyGateway = "--gateway";
41const std::string DHCPServerRunner::kDsrKeyLowerIp = "--lower-ip";
42const std::string DHCPServerRunner::kDsrKeyUpperIp = "--upper-ip";
43const std::string DHCPServerRunner::kDsrKeyConfig = "--config";
44
45
46struct DHCPServer::Data
47{
48 Data()
49 : enabled(FALSE)
50 , router(false)
51 {
52 tempConfigFileName[0] = '\0';
53 }
54
55 Utf8Str IPAddress;
56 Utf8Str lowerIP;
57 Utf8Str upperIP;
58
59 BOOL enabled;
60 bool router;
61 DHCPServerRunner dhcp;
62
63 settings::DhcpOptionMap GlobalDhcpOptions;
64 settings::VmSlot2OptionsMap VmSlot2Options;
65
66 char tempConfigFileName[RTPATH_MAX];
67 com::Utf8Str networkName;
68 com::Utf8Str trunkName;
69 com::Utf8Str trunkType;
70};
71
72
73DHCPServer::DHCPServer()
74 : m(NULL)
75 , mVirtualBox(NULL)
76{
77 m = new DHCPServer::Data();
78}
79
80
81DHCPServer::~DHCPServer()
82{
83 if (m)
84 {
85 delete m;
86 m = NULL;
87 }
88}
89
90
91HRESULT DHCPServer::FinalConstruct()
92{
93 return BaseFinalConstruct();
94}
95
96
97void DHCPServer::FinalRelease()
98{
99 uninit ();
100
101 BaseFinalRelease();
102}
103
104
105void DHCPServer::uninit()
106{
107 /* Enclose the state transition Ready->InUninit->NotReady */
108 AutoUninitSpan autoUninitSpan(this);
109 if (autoUninitSpan.uninitDone())
110 return;
111
112 if (m->dhcp.isRunning())
113 stop();
114
115 unconst(mVirtualBox) = NULL;
116}
117
118
119HRESULT DHCPServer::init(VirtualBox *aVirtualBox, const Utf8Str &aName)
120{
121 AssertReturn(!aName.isEmpty(), E_INVALIDARG);
122
123 AutoInitSpan autoInitSpan(this);
124 AssertReturn(autoInitSpan.isOk(), E_FAIL);
125
126 /* share VirtualBox weakly (parent remains NULL so far) */
127 unconst(mVirtualBox) = aVirtualBox;
128
129 unconst(mName) = aName;
130 m->IPAddress = "0.0.0.0";
131 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = settings::DhcpOptValue("0.0.0.0");
132 m->enabled = FALSE;
133
134 m->lowerIP = "0.0.0.0";
135 m->upperIP = "0.0.0.0";
136
137 /* Confirm a successful initialization */
138 autoInitSpan.setSucceeded();
139
140 return S_OK;
141}
142
143
144HRESULT DHCPServer::init(VirtualBox *aVirtualBox,
145 const settings::DHCPServer &data)
146{
147 /* Enclose the state transition NotReady->InInit->Ready */
148 AutoInitSpan autoInitSpan(this);
149 AssertReturn(autoInitSpan.isOk(), E_FAIL);
150
151 /* share VirtualBox weakly (parent remains NULL so far) */
152 unconst(mVirtualBox) = aVirtualBox;
153
154 unconst(mName) = data.strNetworkName;
155 m->IPAddress = data.strIPAddress;
156 m->enabled = data.fEnabled;
157 m->lowerIP = data.strIPLower;
158 m->upperIP = data.strIPUpper;
159
160 m->GlobalDhcpOptions.clear();
161 m->GlobalDhcpOptions.insert(data.GlobalDhcpOptions.begin(),
162 data.GlobalDhcpOptions.end());
163
164 m->VmSlot2Options.clear();
165 m->VmSlot2Options.insert(data.VmSlot2OptionsM.begin(),
166 data.VmSlot2OptionsM.end());
167
168 autoInitSpan.setSucceeded();
169
170 return S_OK;
171}
172
173
174HRESULT DHCPServer::i_saveSettings(settings::DHCPServer &data)
175{
176 AutoCaller autoCaller(this);
177 if (FAILED(autoCaller.rc())) return autoCaller.rc();
178
179 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
180
181 data.strNetworkName = mName;
182 data.strIPAddress = m->IPAddress;
183
184 data.fEnabled = !!m->enabled;
185 data.strIPLower = m->lowerIP;
186 data.strIPUpper = m->upperIP;
187
188 data.GlobalDhcpOptions.clear();
189 data.GlobalDhcpOptions.insert(m->GlobalDhcpOptions.begin(),
190 m->GlobalDhcpOptions.end());
191
192 data.VmSlot2OptionsM.clear();
193 data.VmSlot2OptionsM.insert(m->VmSlot2Options.begin(),
194 m->VmSlot2Options.end());
195
196 return S_OK;
197}
198
199
200HRESULT DHCPServer::getNetworkName(com::Utf8Str &aName)
201{
202 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
203
204 aName = mName;
205 return S_OK;
206}
207
208
209HRESULT DHCPServer::getEnabled(BOOL *aEnabled)
210{
211 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
212
213 *aEnabled = m->enabled;
214 return S_OK;
215}
216
217
218HRESULT DHCPServer::setEnabled(BOOL aEnabled)
219{
220 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
221 m->enabled = aEnabled;
222
223 // save the global settings; for that we should hold only the VirtualBox lock
224 alock.release();
225 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
226 HRESULT rc = mVirtualBox->i_saveSettings();
227
228 return rc;
229}
230
231
232HRESULT DHCPServer::getIPAddress(com::Utf8Str &aIPAddress)
233{
234 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
235
236 aIPAddress = Utf8Str(m->IPAddress);
237 return S_OK;
238}
239
240
241HRESULT DHCPServer::getNetworkMask(com::Utf8Str &aNetworkMask)
242{
243 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
244
245 aNetworkMask = m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text;
246 return S_OK;
247}
248
249
250HRESULT DHCPServer::getLowerIP(com::Utf8Str &aIPAddress)
251{
252 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
253
254 aIPAddress = Utf8Str(m->lowerIP);
255 return S_OK;
256}
257
258
259HRESULT DHCPServer::getUpperIP(com::Utf8Str &aIPAddress)
260{
261 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
262
263 aIPAddress = Utf8Str(m->upperIP);
264 return S_OK;
265}
266
267
268HRESULT DHCPServer::setConfiguration(const com::Utf8Str &aIPAddress,
269 const com::Utf8Str &aNetworkMask,
270 const com::Utf8Str &aLowerIP,
271 const com::Utf8Str &aUpperIP)
272{
273 RTNETADDRIPV4 IPAddress, NetworkMask, LowerIP, UpperIP;
274
275 int vrc = RTNetStrToIPv4Addr(aIPAddress.c_str(), &IPAddress);
276 if (RT_FAILURE(vrc))
277 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid server address");
278
279 vrc = RTNetStrToIPv4Addr(aNetworkMask.c_str(), &NetworkMask);
280 if (RT_FAILURE(vrc))
281 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid netmask");
282
283 vrc = RTNetStrToIPv4Addr(aLowerIP.c_str(), &LowerIP);
284 if (RT_FAILURE(vrc))
285 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid range lower address");
286
287 vrc = RTNetStrToIPv4Addr(aUpperIP.c_str(), &UpperIP);
288 if (RT_FAILURE(vrc))
289 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid range upper address");
290
291 /*
292 * Insist on continuous mask. May be also accept prefix length
293 * here or address/prefix for aIPAddress?
294 */
295 vrc = RTNetMaskToPrefixIPv4(&NetworkMask, NULL);
296 if (RT_FAILURE(vrc))
297 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid netmask");
298
299 /* It's more convenient to convert to host order once */
300 IPAddress.u = RT_N2H_U32(IPAddress.u);
301 NetworkMask.u = RT_N2H_U32(NetworkMask.u);
302 LowerIP.u = RT_N2H_U32(LowerIP.u);
303 UpperIP.u = RT_N2H_U32(UpperIP.u);
304
305 /*
306 * Addresses must be unicast and from the same network
307 */
308 if ( (IPAddress.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
309 || (IPAddress.u & ~NetworkMask.u) == 0
310 || ((IPAddress.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
311 return mVirtualBox->setError(E_INVALIDARG, "Invalid server address");
312
313 if ( (LowerIP.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
314 || (LowerIP.u & NetworkMask.u) != (IPAddress.u &NetworkMask.u)
315 || (LowerIP.u & ~NetworkMask.u) == 0
316 || ((LowerIP.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
317 return mVirtualBox->setError(E_INVALIDARG, "Invalid range lower address");
318
319 if ( (UpperIP.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
320 || (UpperIP.u & NetworkMask.u) != (IPAddress.u &NetworkMask.u)
321 || (UpperIP.u & ~NetworkMask.u) == 0
322 || ((UpperIP.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
323 return mVirtualBox->setError(E_INVALIDARG, "Invalid range upper address");
324
325 /* The range should be valid ... */
326 if (LowerIP.u > UpperIP.u)
327 return mVirtualBox->setError(E_INVALIDARG, "Invalid range bounds");
328
329 /* ... and shouldn't contain the server's address */
330 if (LowerIP.u <= IPAddress.u && IPAddress.u <= UpperIP.u)
331 return mVirtualBox->setError(E_INVALIDARG, "Server address within range bounds");
332
333 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
334 m->IPAddress = aIPAddress;
335 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = aNetworkMask;
336
337 m->lowerIP = aLowerIP;
338 m->upperIP = aUpperIP;
339
340 // save the global settings; for that we should hold only the VirtualBox lock
341 alock.release();
342 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
343 return mVirtualBox->i_saveSettings();
344}
345
346
347HRESULT DHCPServer::encodeOption(com::Utf8Str &aEncoded,
348 uint32_t aOptCode,
349 const settings::DhcpOptValue &aOptValue)
350{
351 switch (aOptValue.encoding)
352 {
353 case DhcpOptEncoding_Legacy:
354 {
355 /*
356 * This is original encoding which assumed that for each
357 * option we know its format and so we know how option
358 * "value" text is to be interpreted.
359 *
360 * "2:10800" # integer 32
361 * "6:1.2.3.4 8.8.8.8" # array of ip-address
362 */
363 aEncoded = Utf8StrFmt("%d:%s", aOptCode, aOptValue.text.c_str());
364 break;
365 }
366
367 case DhcpOptEncoding_Hex:
368 {
369 /*
370 * This is a bypass for any option - preformatted value as
371 * hex string with no semantic involved in formatting the
372 * value for the DHCP reply.
373 *
374 * 234=68:65:6c:6c:6f:2c:20:77:6f:72:6c:64
375 */
376 aEncoded = Utf8StrFmt("%d=%s", aOptCode, aOptValue.text.c_str());
377 break;
378 }
379
380 default:
381 {
382 /*
383 * Try to be forward compatible.
384 *
385 * "254@42=i hope you know what this means"
386 */
387 aEncoded = Utf8StrFmt("%d@%d=%s", aOptCode, (int)aOptValue.encoding,
388 aOptValue.text.c_str());
389 break;
390 }
391 }
392
393 return S_OK;
394}
395
396
397int DHCPServer::addOption(settings::DhcpOptionMap &aMap,
398 DhcpOpt_T aOption, const com::Utf8Str &aValue)
399{
400 settings::DhcpOptValue OptValue;
401
402 if (aOption != 0)
403 {
404 OptValue = settings::DhcpOptValue(aValue, DhcpOptEncoding_Legacy);
405 }
406 /*
407 * This is a kludge to sneak in option encoding information
408 * through existing API. We use option 0 and supply the real
409 * option/value in the same format that encodeOption() above
410 * produces for getter methods.
411 */
412 else
413 {
414 uint8_t u8Code;
415 char *pszNext;
416 int vrc = RTStrToUInt8Ex(aValue.c_str(), &pszNext, 10, &u8Code);
417 if (!RT_SUCCESS(vrc))
418 return VERR_PARSE_ERROR;
419
420 uint32_t u32Enc;
421 switch (*pszNext)
422 {
423 case ':': /* support legacy format too */
424 {
425 u32Enc = DhcpOptEncoding_Legacy;
426 break;
427 }
428
429 case '=':
430 {
431 u32Enc = DhcpOptEncoding_Hex;
432 break;
433 }
434
435 case '@':
436 {
437 vrc = RTStrToUInt32Ex(pszNext + 1, &pszNext, 10, &u32Enc);
438 if (!RT_SUCCESS(vrc))
439 return VERR_PARSE_ERROR;
440 if (*pszNext != '=')
441 return VERR_PARSE_ERROR;
442 break;
443 }
444
445 default:
446 return VERR_PARSE_ERROR;
447 }
448
449 aOption = (DhcpOpt_T)u8Code;
450 OptValue = settings::DhcpOptValue(pszNext + 1, (DhcpOptEncoding_T)u32Enc);
451 }
452
453 aMap[aOption] = OptValue;
454 return VINF_SUCCESS;
455}
456
457
458HRESULT DHCPServer::addGlobalOption(DhcpOpt_T aOption, const com::Utf8Str &aValue)
459{
460 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
461
462 int rc = addOption(m->GlobalDhcpOptions, aOption, aValue);
463 if (!RT_SUCCESS(rc))
464 return E_INVALIDARG;
465
466 /* Indirect way to understand that we're on NAT network */
467 if (aOption == DhcpOpt_Router)
468 {
469 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNeedMain, "on");
470 m->router = true;
471 }
472
473 alock.release();
474
475 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
476 return mVirtualBox->i_saveSettings();
477}
478
479
480HRESULT DHCPServer::removeGlobalOption(DhcpOpt_T aOption)
481{
482 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
483
484 settings::DhcpOptionMap::size_type cErased = m->GlobalDhcpOptions.erase(aOption);
485 if (!cErased)
486 return E_INVALIDARG;
487
488 alock.release();
489
490 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
491 return mVirtualBox->i_saveSettings();
492}
493
494
495HRESULT DHCPServer::removeGlobalOptions()
496{
497 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
498 m->GlobalDhcpOptions.clear();
499
500 alock.release();
501
502 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
503 return mVirtualBox->i_saveSettings();
504}
505
506
507HRESULT DHCPServer::getGlobalOptions(std::vector<com::Utf8Str> &aValues)
508{
509 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
510 aValues.resize(m->GlobalDhcpOptions.size());
511 settings::DhcpOptionMap::const_iterator it;
512 size_t i = 0;
513 for (it = m->GlobalDhcpOptions.begin(); it != m->GlobalDhcpOptions.end(); ++it, ++i)
514 {
515 uint32_t OptCode = (*it).first;
516 const settings::DhcpOptValue &OptValue = (*it).second;
517
518 encodeOption(aValues[i], OptCode, OptValue);
519 }
520
521 return S_OK;
522}
523
524HRESULT DHCPServer::getVmConfigs(std::vector<com::Utf8Str> &aValues)
525{
526 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
527 aValues.resize(m->VmSlot2Options.size());
528 settings::VmSlot2OptionsMap::const_iterator it;
529 size_t i = 0;
530 for (it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it, ++i)
531 {
532 aValues[i] = Utf8StrFmt("[%s]:%d", it->first.VmName.c_str(), it->first.Slot);
533 }
534
535 return S_OK;
536}
537
538
539HRESULT DHCPServer::addVmSlotOption(const com::Utf8Str &aVmName,
540 LONG aSlot,
541 DhcpOpt_T aOption,
542 const com::Utf8Str &aValue)
543{
544 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
545
546 settings::DhcpOptionMap &map = m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
547 int rc = addOption(map, aOption, aValue);
548 if (!RT_SUCCESS(rc))
549 return E_INVALIDARG;
550
551 alock.release();
552
553 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
554 return mVirtualBox->i_saveSettings();
555}
556
557
558HRESULT DHCPServer::removeVmSlotOption(const com::Utf8Str &aVmName, LONG aSlot, DhcpOpt_T aOption)
559{
560 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
561 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
562 settings::DhcpOptionMap::size_type cErased = map.erase(aOption);
563 if (!cErased)
564 return E_INVALIDARG;
565
566 alock.release();
567
568 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
569 return mVirtualBox->i_saveSettings();
570}
571
572
573HRESULT DHCPServer::removeVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot)
574{
575 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
576 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
577 map.clear();
578
579 alock.release();
580
581 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
582 return mVirtualBox->i_saveSettings();
583}
584
585/**
586 * this is mapping (vm, slot)
587 */
588HRESULT DHCPServer::getVmSlotOptions(const com::Utf8Str &aVmName,
589 LONG aSlot,
590 std::vector<com::Utf8Str> &aValues)
591{
592
593 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
594 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
595 aValues.resize(map.size());
596 size_t i = 0;
597 settings::DhcpOptionMap::const_iterator it;
598 for (it = map.begin(); it != map.end(); ++it, ++i)
599 {
600 uint32_t OptCode = (*it).first;
601 const settings::DhcpOptValue &OptValue = (*it).second;
602
603 encodeOption(aValues[i], OptCode, OptValue);
604 }
605
606 return S_OK;
607}
608
609
610HRESULT DHCPServer::getMacOptions(const com::Utf8Str &aMAC, std::vector<com::Utf8Str> &aOption)
611{
612 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
613 HRESULT hrc = S_OK;
614 ComPtr<IMachine> machine;
615 ComPtr<INetworkAdapter> nic;
616 settings::VmSlot2OptionsIterator it;
617 for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
618 {
619 alock.release();
620 hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
621 alock.acquire();
622
623 if (FAILED(hrc))
624 continue;
625
626 alock.release();
627 hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
628 alock.acquire();
629
630 if (FAILED(hrc))
631 continue;
632
633 com::Bstr mac;
634
635 alock.release();
636 hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
637 alock.acquire();
638
639 if (FAILED(hrc)) /* no MAC address ??? */
640 break;
641 if (!RTStrICmp(com::Utf8Str(mac).c_str(), aMAC.c_str()))
642 return getVmSlotOptions(it->first.VmName,
643 it->first.Slot,
644 aOption);
645 } /* end of for */
646
647 return hrc;
648}
649
650HRESULT DHCPServer::getEventSource(ComPtr<IEventSource> &aEventSource)
651{
652 NOREF(aEventSource);
653 ReturnComNotImplemented();
654}
655
656
657DECLINLINE(void) addOptionChild(xml::ElementNode *pParent, uint32_t OptCode, const settings::DhcpOptValue &OptValue)
658{
659 xml::ElementNode *pOption = pParent->createChild("Option");
660 pOption->setAttribute("name", OptCode);
661 pOption->setAttribute("encoding", OptValue.encoding);
662 pOption->setAttribute("value", OptValue.text.c_str());
663}
664
665
666HRESULT DHCPServer::restart()
667{
668 if (!m->dhcp.isRunning())
669 return E_FAIL;
670 /*
671 * Disabled servers will be brought down, but won't be restarted.
672 * (see DHCPServer::start)
673 */
674 HRESULT hrc = stop();
675 if (SUCCEEDED(hrc))
676 hrc = start(m->networkName, m->trunkName, m->trunkType);
677 return hrc;
678}
679
680
681HRESULT DHCPServer::start(const com::Utf8Str &aNetworkName,
682 const com::Utf8Str &aTrunkName,
683 const com::Utf8Str &aTrunkType)
684{
685 /* Silently ignore attempts to run disabled servers. */
686 if (!m->enabled)
687 return S_OK;
688
689 /*
690 * @todo: the existing code cannot handle concurrent attempts to start DHCP server.
691 * Note that technically it may receive different parameters from different callers.
692 */
693 m->networkName = aNetworkName;
694 m->trunkName = aTrunkName;
695 m->trunkType = aTrunkType;
696
697 m->dhcp.clearOptions();
698#ifdef VBOX_WITH_DHCPD
699 int rc = RTPathTemp(m->tempConfigFileName, sizeof(m->tempConfigFileName));
700 if (RT_FAILURE(rc))
701 return E_FAIL;
702 rc = RTPathAppend(m->tempConfigFileName, sizeof(m->tempConfigFileName), "dhcp-config-XXXXX.xml");
703 if (RT_FAILURE(rc))
704 {
705 m->tempConfigFileName[0] = '\0';
706 return E_FAIL;
707 }
708 rc = RTFileCreateTemp(m->tempConfigFileName, 0600);
709 if (RT_FAILURE(rc))
710 {
711 m->tempConfigFileName[0] = '\0';
712 return E_FAIL;
713 }
714
715 xml::Document doc;
716 xml::ElementNode *pElmRoot = doc.createRootElement("DHCPServer");
717 pElmRoot->setAttribute("networkName", m->networkName.c_str());
718 if (!m->trunkName.isEmpty())
719 pElmRoot->setAttribute("trunkName", m->trunkName.c_str());
720 pElmRoot->setAttribute("trunkType", m->trunkType.c_str());
721 pElmRoot->setAttribute("IPAddress", Utf8Str(m->IPAddress).c_str());
722 pElmRoot->setAttribute("networkMask", Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
723 pElmRoot->setAttribute("lowerIP", Utf8Str(m->lowerIP).c_str());
724 pElmRoot->setAttribute("upperIP", Utf8Str(m->upperIP).c_str());
725
726 /* Process global options */
727 xml::ElementNode *pOptions = pElmRoot->createChild("Options");
728 // settings::DhcpOptionMap::const_iterator itGlobal;
729 for (settings::DhcpOptionMap::const_iterator it = m->GlobalDhcpOptions.begin();
730 it != m->GlobalDhcpOptions.end();
731 ++it)
732 addOptionChild(pOptions, (*it).first, (*it).second);
733
734 /* Process network-adapter-specific options */
735 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
736 HRESULT hrc = S_OK;
737 ComPtr<IMachine> machine;
738 ComPtr<INetworkAdapter> nic;
739 settings::VmSlot2OptionsIterator it;
740 for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
741 {
742 alock.release();
743 hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
744 alock.acquire();
745
746 if (FAILED(hrc))
747 continue;
748
749 alock.release();
750 hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
751 alock.acquire();
752
753 if (FAILED(hrc))
754 continue;
755
756 com::Bstr mac;
757
758 alock.release();
759 hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
760 alock.acquire();
761
762 if (FAILED(hrc)) /* no MAC address ??? */
763 continue;
764
765 /* Convert MAC address from XXXXXXXXXXXX to XX:XX:XX:XX:XX:XX */
766 Utf8Str strMacWithoutColons(mac);
767 const char *pszSrc = strMacWithoutColons.c_str();
768 RTMAC binaryMac;
769 if (RTStrConvertHexBytes(pszSrc, &binaryMac, sizeof(binaryMac), 0) != VINF_SUCCESS)
770 continue;
771 char szMac[18]; /* "XX:XX:XX:XX:XX:XX" */
772 if (RTStrPrintHexBytes(szMac, sizeof(szMac), &binaryMac, sizeof(binaryMac), RTSTRPRINTHEXBYTES_F_SEP_COLON) != VINF_SUCCESS)
773 continue;
774
775 xml::ElementNode *pMacConfig = pElmRoot->createChild("Config");
776 pMacConfig->setAttribute("MACAddress", szMac);
777
778 com::Utf8Str encodedOption;
779 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(it->first.VmName, it->first.Slot);
780 settings::DhcpOptionMap::const_iterator itAdapterOption;
781 for (itAdapterOption = map.begin(); itAdapterOption != map.end(); ++itAdapterOption)
782 addOptionChild(pMacConfig, (*itAdapterOption).first, (*itAdapterOption).second);
783 }
784
785 xml::XmlFileWriter writer(doc);
786 writer.write(m->tempConfigFileName, true);
787
788 m->dhcp.setOption(DHCPServerRunner::kDsrKeyConfig, m->tempConfigFileName);
789#else /* !VBOX_WITH_DHCPD */
790 /* Commmon Network Settings */
791 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNetwork, aNetworkName.c_str());
792
793 if (!aTrunkName.isEmpty())
794 m->dhcp.setOption(NetworkServiceRunner::kNsrTrunkName, aTrunkName.c_str());
795
796 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyTrunkType, aTrunkType.c_str());
797
798 /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */
799 char strMAC[32];
800 Guid guid;
801 guid.create();
802 RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X",
803 guid.raw()->au8[0],
804 guid.raw()->au8[1],
805 guid.raw()->au8[2]);
806 m->dhcp.setOption(NetworkServiceRunner::kNsrMacAddress, strMAC);
807 m->dhcp.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPAddress).c_str());
808 m->dhcp.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
809 m->dhcp.setOption(DHCPServerRunner::kDsrKeyLowerIp, Utf8Str(m->lowerIP).c_str());
810 m->dhcp.setOption(DHCPServerRunner::kDsrKeyUpperIp, Utf8Str(m->upperIP).c_str());
811#endif /* !VBOX_WITH_DHCPD */
812
813 /* XXX: This parameters Dhcp Server will fetch via API */
814 return RT_FAILURE(m->dhcp.start(!m->router /* KillProcOnExit */)) ? E_FAIL : S_OK;
815 //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
816}
817
818
819HRESULT DHCPServer::stop (void)
820{
821#ifdef VBOX_WITH_DHCPD
822 if (m->tempConfigFileName[0])
823 {
824 RTFileDelete(m->tempConfigFileName);
825 m->tempConfigFileName[0] = 0;
826 }
827#endif /* VBOX_WITH_DHCPD */
828 return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK;
829}
830
831
832settings::DhcpOptionMap &DHCPServer::i_findOptMapByVmNameSlot(const com::Utf8Str &aVmName,
833 LONG aSlot)
834{
835 return m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
836}
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