VirtualBox

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

Last change on this file since 75648 was 75648, checked in by vboxsync, 7 years ago

Main/DHCPD: bugref:9288 Use new implementation of DHCP server (VCC 10 and GCC 4.4.4 support, other build fixes).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.5 KB
Line 
1/* $Id: DHCPServerImpl.cpp 75648 2018-11-21 18:02:38Z 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.215389.xyz. 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::getGlobalOptions(std::vector<com::Utf8Str> &aValues)
481{
482 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
483 aValues.resize(m->GlobalDhcpOptions.size());
484 settings::DhcpOptionMap::const_iterator it;
485 size_t i = 0;
486 for (it = m->GlobalDhcpOptions.begin(); it != m->GlobalDhcpOptions.end(); ++it, ++i)
487 {
488 uint32_t OptCode = (*it).first;
489 const settings::DhcpOptValue &OptValue = (*it).second;
490
491 encodeOption(aValues[i], OptCode, OptValue);
492 }
493
494 return S_OK;
495}
496
497HRESULT DHCPServer::getVmConfigs(std::vector<com::Utf8Str> &aValues)
498{
499 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
500 aValues.resize(m->VmSlot2Options.size());
501 settings::VmSlot2OptionsMap::const_iterator it;
502 size_t i = 0;
503 for (it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it, ++i)
504 {
505 aValues[i] = Utf8StrFmt("[%s]:%d", it->first.VmName.c_str(), it->first.Slot);
506 }
507
508 return S_OK;
509}
510
511
512HRESULT DHCPServer::addVmSlotOption(const com::Utf8Str &aVmName,
513 LONG aSlot,
514 DhcpOpt_T aOption,
515 const com::Utf8Str &aValue)
516{
517 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
518
519 settings::DhcpOptionMap &map = m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
520 int rc = addOption(map, aOption, aValue);
521 if (!RT_SUCCESS(rc))
522 return E_INVALIDARG;
523
524 alock.release();
525
526 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
527 return mVirtualBox->i_saveSettings();
528}
529
530
531HRESULT DHCPServer::removeVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot)
532{
533 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
534 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
535 map.clear();
536
537 alock.release();
538
539 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
540 return mVirtualBox->i_saveSettings();
541}
542
543/**
544 * this is mapping (vm, slot)
545 */
546HRESULT DHCPServer::getVmSlotOptions(const com::Utf8Str &aVmName,
547 LONG aSlot,
548 std::vector<com::Utf8Str> &aValues)
549{
550
551 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
552 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
553 aValues.resize(map.size());
554 size_t i = 0;
555 settings::DhcpOptionMap::const_iterator it;
556 for (it = map.begin(); it != map.end(); ++it, ++i)
557 {
558 uint32_t OptCode = (*it).first;
559 const settings::DhcpOptValue &OptValue = (*it).second;
560
561 encodeOption(aValues[i], OptCode, OptValue);
562 }
563
564 return S_OK;
565}
566
567
568HRESULT DHCPServer::getMacOptions(const com::Utf8Str &aMAC, std::vector<com::Utf8Str> &aOption)
569{
570 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
571 HRESULT hrc = S_OK;
572 ComPtr<IMachine> machine;
573 ComPtr<INetworkAdapter> nic;
574 settings::VmSlot2OptionsIterator it;
575 for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
576 {
577 alock.release();
578 hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
579 alock.acquire();
580
581 if (FAILED(hrc))
582 continue;
583
584 alock.release();
585 hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
586 alock.acquire();
587
588 if (FAILED(hrc))
589 continue;
590
591 com::Bstr mac;
592
593 alock.release();
594 hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
595 alock.acquire();
596
597 if (FAILED(hrc)) /* no MAC address ??? */
598 break;
599 if (!RTStrICmp(com::Utf8Str(mac).c_str(), aMAC.c_str()))
600 return getVmSlotOptions(it->first.VmName,
601 it->first.Slot,
602 aOption);
603 } /* end of for */
604
605 return hrc;
606}
607
608HRESULT DHCPServer::getEventSource(ComPtr<IEventSource> &aEventSource)
609{
610 NOREF(aEventSource);
611 ReturnComNotImplemented();
612}
613
614
615DECLINLINE(void) addOptionChild(xml::ElementNode *pParent, uint32_t OptCode, const settings::DhcpOptValue &OptValue)
616{
617 xml::ElementNode *pOption = pParent->createChild("Option");
618 pOption->setAttribute("name", OptCode);
619 pOption->setAttribute("encoding", OptValue.encoding);
620 pOption->setAttribute("value", OptValue.text.c_str());
621}
622
623
624HRESULT DHCPServer::restart()
625{
626 if (!m->dhcp.isRunning())
627 return E_FAIL;
628 /*
629 * Disabled servers will be brought down, but won't be restarted.
630 * (see DHCPServer::start)
631 */
632 HRESULT hrc = stop();
633 if (SUCCEEDED(hrc))
634 hrc = start(m->networkName, m->trunkName, m->trunkType);
635 return hrc;
636}
637
638
639HRESULT DHCPServer::start(const com::Utf8Str &aNetworkName,
640 const com::Utf8Str &aTrunkName,
641 const com::Utf8Str &aTrunkType)
642{
643 /* Silently ignore attempts to run disabled servers. */
644 if (!m->enabled)
645 return S_OK;
646
647 /*
648 * @todo: the existing code cannot handle concurrent attempts to start DHCP server.
649 * Note that technically it may receive different parameters from different callers.
650 */
651 m->networkName = aNetworkName;
652 m->trunkName = aTrunkName;
653 m->trunkType = aTrunkType;
654
655 m->dhcp.clearOptions();
656#ifdef VBOX_WITH_DHCPD
657 int rc = RTPathTemp(m->tempConfigFileName, sizeof(m->tempConfigFileName));
658 if (RT_FAILURE(rc))
659 return E_FAIL;
660 rc = RTPathAppend(m->tempConfigFileName, sizeof(m->tempConfigFileName), "dhcp-config-XXXXX.xml");
661 if (RT_FAILURE(rc))
662 {
663 m->tempConfigFileName[0] = '\0';
664 return E_FAIL;
665 }
666 rc = RTFileCreateTemp(m->tempConfigFileName, 0600);
667 if (RT_FAILURE(rc))
668 {
669 m->tempConfigFileName[0] = '\0';
670 return E_FAIL;
671 }
672
673 xml::Document doc;
674 xml::ElementNode *pElmRoot = doc.createRootElement("DHCPServer");
675 pElmRoot->setAttribute("networkName", m->networkName.c_str());
676 if (!m->trunkName.isEmpty())
677 pElmRoot->setAttribute("trunkName", m->trunkName.c_str());
678 pElmRoot->setAttribute("trunkType", m->trunkType.c_str());
679 pElmRoot->setAttribute("IPAddress", Utf8Str(m->IPAddress).c_str());
680 pElmRoot->setAttribute("networkMask", Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
681 pElmRoot->setAttribute("lowerIP", Utf8Str(m->lowerIP).c_str());
682 pElmRoot->setAttribute("upperIP", Utf8Str(m->upperIP).c_str());
683
684 /* Process global options */
685 xml::ElementNode *pOptions = pElmRoot->createChild("Options");
686 // settings::DhcpOptionMap::const_iterator itGlobal;
687 for (settings::DhcpOptionMap::const_iterator it = m->GlobalDhcpOptions.begin();
688 it != m->GlobalDhcpOptions.end();
689 ++it)
690 addOptionChild(pOptions, (*it).first, (*it).second);
691
692 /* Process network-adapter-specific options */
693 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
694 HRESULT hrc = S_OK;
695 ComPtr<IMachine> machine;
696 ComPtr<INetworkAdapter> nic;
697 settings::VmSlot2OptionsIterator it;
698 for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
699 {
700 alock.release();
701 hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
702 alock.acquire();
703
704 if (FAILED(hrc))
705 continue;
706
707 alock.release();
708 hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
709 alock.acquire();
710
711 if (FAILED(hrc))
712 continue;
713
714 com::Bstr mac;
715
716 alock.release();
717 hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
718 alock.acquire();
719
720 if (FAILED(hrc)) /* no MAC address ??? */
721 continue;
722
723 /* Convert MAC address from XXXXXXXXXXXX to XX:XX:XX:XX:XX:XX */
724 Utf8Str strMacWithoutColons(mac);
725 const char *pszSrc = strMacWithoutColons.c_str();
726 RTMAC binaryMac;
727 if (RTStrConvertHexBytes(pszSrc, &binaryMac, sizeof(binaryMac), 0) != VINF_SUCCESS)
728 continue;
729 char szMac[18]; /* "XX:XX:XX:XX:XX:XX" */
730 if (RTStrPrintHexBytes(szMac, sizeof(szMac), &binaryMac, sizeof(binaryMac), RTSTRPRINTHEXBYTES_F_SEP_COLON) != VINF_SUCCESS)
731 continue;
732
733 xml::ElementNode *pMacConfig = pElmRoot->createChild("Config");
734 pMacConfig->setAttribute("MACAddress", szMac);
735
736 com::Utf8Str encodedOption;
737 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(it->first.VmName, it->first.Slot);
738 settings::DhcpOptionMap::const_iterator itAdapterOption;
739 for (itAdapterOption = map.begin(); itAdapterOption != map.end(); ++itAdapterOption)
740 addOptionChild(pMacConfig, (*itAdapterOption).first, (*itAdapterOption).second);
741 }
742
743 xml::XmlFileWriter writer(doc);
744 writer.write(m->tempConfigFileName, true);
745
746 m->dhcp.setOption(DHCPServerRunner::kDsrKeyConfig, m->tempConfigFileName);
747#else /* !VBOX_WITH_DHCPD */
748 /* Commmon Network Settings */
749 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNetwork, aNetworkName.c_str());
750
751 if (!aTrunkName.isEmpty())
752 m->dhcp.setOption(NetworkServiceRunner::kNsrTrunkName, aTrunkName.c_str());
753
754 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyTrunkType, aTrunkType.c_str());
755
756 /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */
757 char strMAC[32];
758 Guid guid;
759 guid.create();
760 RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X",
761 guid.raw()->au8[0],
762 guid.raw()->au8[1],
763 guid.raw()->au8[2]);
764 m->dhcp.setOption(NetworkServiceRunner::kNsrMacAddress, strMAC);
765 m->dhcp.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPAddress).c_str());
766 m->dhcp.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
767 m->dhcp.setOption(DHCPServerRunner::kDsrKeyLowerIp, Utf8Str(m->lowerIP).c_str());
768 m->dhcp.setOption(DHCPServerRunner::kDsrKeyUpperIp, Utf8Str(m->upperIP).c_str());
769#endif /* !VBOX_WITH_DHCPD */
770
771 /* XXX: This parameters Dhcp Server will fetch via API */
772 return RT_FAILURE(m->dhcp.start(!m->router /* KillProcOnExit */)) ? E_FAIL : S_OK;
773 //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
774}
775
776
777HRESULT DHCPServer::stop (void)
778{
779#ifdef VBOX_WITH_DHCPD
780 if (m->tempConfigFileName[0])
781 {
782 RTFileDelete(m->tempConfigFileName);
783 m->tempConfigFileName[0] = 0;
784 }
785#endif /* VBOX_WITH_DHCPD */
786 return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK;
787}
788
789
790settings::DhcpOptionMap &DHCPServer::i_findOptMapByVmNameSlot(const com::Utf8Str &aVmName,
791 LONG aSlot)
792{
793 return m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
794}
Note: See TracBrowser for help on using the repository browser.

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