VirtualBox

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

Last change on this file since 78093 was 76592, checked in by vboxsync, 6 years ago

Main: Don't use Logging.h.

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