VirtualBox

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

Last change on this file since 76240 was 76190, checked in by vboxsync, 6 years ago

Main/DHCPServer: (bugref:9288) Added --comment command line option to simplify identification of VBoxNetDHCP instanced in the process list

  • 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 76190 2018-12-12 16:58:55Z 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";
44const std::string DHCPServerRunner::kDsrKeyComment = "--comment";
45
46
47struct DHCPServer::Data
48{
49 Data()
50 : enabled(FALSE)
51 , router(false)
52 {
53 tempConfigFileName[0] = '\0';
54 }
55
56 Utf8Str IPAddress;
57 Utf8Str lowerIP;
58 Utf8Str upperIP;
59
60 BOOL enabled;
61 bool router;
62 DHCPServerRunner dhcp;
63
64 settings::DhcpOptionMap GlobalDhcpOptions;
65 settings::VmSlot2OptionsMap VmSlot2Options;
66
67 char tempConfigFileName[RTPATH_MAX];
68 com::Utf8Str networkName;
69 com::Utf8Str trunkName;
70 com::Utf8Str trunkType;
71};
72
73
74DHCPServer::DHCPServer()
75 : m(NULL)
76 , mVirtualBox(NULL)
77{
78 m = new DHCPServer::Data();
79}
80
81
82DHCPServer::~DHCPServer()
83{
84 if (m)
85 {
86 delete m;
87 m = NULL;
88 }
89}
90
91
92HRESULT DHCPServer::FinalConstruct()
93{
94 return BaseFinalConstruct();
95}
96
97
98void DHCPServer::FinalRelease()
99{
100 uninit ();
101
102 BaseFinalRelease();
103}
104
105
106void DHCPServer::uninit()
107{
108 /* Enclose the state transition Ready->InUninit->NotReady */
109 AutoUninitSpan autoUninitSpan(this);
110 if (autoUninitSpan.uninitDone())
111 return;
112
113 if (m->dhcp.isRunning())
114 stop();
115
116 unconst(mVirtualBox) = NULL;
117}
118
119
120HRESULT DHCPServer::init(VirtualBox *aVirtualBox, const Utf8Str &aName)
121{
122 AssertReturn(!aName.isEmpty(), E_INVALIDARG);
123
124 AutoInitSpan autoInitSpan(this);
125 AssertReturn(autoInitSpan.isOk(), E_FAIL);
126
127 /* share VirtualBox weakly (parent remains NULL so far) */
128 unconst(mVirtualBox) = aVirtualBox;
129
130 unconst(mName) = aName;
131 m->IPAddress = "0.0.0.0";
132 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = settings::DhcpOptValue("0.0.0.0");
133 m->enabled = FALSE;
134
135 m->lowerIP = "0.0.0.0";
136 m->upperIP = "0.0.0.0";
137
138 /* Confirm a successful initialization */
139 autoInitSpan.setSucceeded();
140
141 return S_OK;
142}
143
144
145HRESULT DHCPServer::init(VirtualBox *aVirtualBox,
146 const settings::DHCPServer &data)
147{
148 /* Enclose the state transition NotReady->InInit->Ready */
149 AutoInitSpan autoInitSpan(this);
150 AssertReturn(autoInitSpan.isOk(), E_FAIL);
151
152 /* share VirtualBox weakly (parent remains NULL so far) */
153 unconst(mVirtualBox) = aVirtualBox;
154
155 unconst(mName) = data.strNetworkName;
156 m->IPAddress = data.strIPAddress;
157 m->enabled = data.fEnabled;
158 m->lowerIP = data.strIPLower;
159 m->upperIP = data.strIPUpper;
160
161 m->GlobalDhcpOptions.clear();
162 m->GlobalDhcpOptions.insert(data.GlobalDhcpOptions.begin(),
163 data.GlobalDhcpOptions.end());
164
165 m->VmSlot2Options.clear();
166 m->VmSlot2Options.insert(data.VmSlot2OptionsM.begin(),
167 data.VmSlot2OptionsM.end());
168
169 autoInitSpan.setSucceeded();
170
171 return S_OK;
172}
173
174
175HRESULT DHCPServer::i_saveSettings(settings::DHCPServer &data)
176{
177 AutoCaller autoCaller(this);
178 if (FAILED(autoCaller.rc())) return autoCaller.rc();
179
180 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
181
182 data.strNetworkName = mName;
183 data.strIPAddress = m->IPAddress;
184
185 data.fEnabled = !!m->enabled;
186 data.strIPLower = m->lowerIP;
187 data.strIPUpper = m->upperIP;
188
189 data.GlobalDhcpOptions.clear();
190 data.GlobalDhcpOptions.insert(m->GlobalDhcpOptions.begin(),
191 m->GlobalDhcpOptions.end());
192
193 data.VmSlot2OptionsM.clear();
194 data.VmSlot2OptionsM.insert(m->VmSlot2Options.begin(),
195 m->VmSlot2Options.end());
196
197 return S_OK;
198}
199
200
201HRESULT DHCPServer::getNetworkName(com::Utf8Str &aName)
202{
203 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
204
205 aName = mName;
206 return S_OK;
207}
208
209
210HRESULT DHCPServer::getEnabled(BOOL *aEnabled)
211{
212 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
213
214 *aEnabled = m->enabled;
215 return S_OK;
216}
217
218
219HRESULT DHCPServer::setEnabled(BOOL aEnabled)
220{
221 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
222 m->enabled = aEnabled;
223
224 // save the global settings; for that we should hold only the VirtualBox lock
225 alock.release();
226 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
227 HRESULT rc = mVirtualBox->i_saveSettings();
228
229 return rc;
230}
231
232
233HRESULT DHCPServer::getIPAddress(com::Utf8Str &aIPAddress)
234{
235 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
236
237 aIPAddress = Utf8Str(m->IPAddress);
238 return S_OK;
239}
240
241
242HRESULT DHCPServer::getNetworkMask(com::Utf8Str &aNetworkMask)
243{
244 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
245
246 aNetworkMask = m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text;
247 return S_OK;
248}
249
250
251HRESULT DHCPServer::getLowerIP(com::Utf8Str &aIPAddress)
252{
253 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
254
255 aIPAddress = Utf8Str(m->lowerIP);
256 return S_OK;
257}
258
259
260HRESULT DHCPServer::getUpperIP(com::Utf8Str &aIPAddress)
261{
262 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
263
264 aIPAddress = Utf8Str(m->upperIP);
265 return S_OK;
266}
267
268
269HRESULT DHCPServer::setConfiguration(const com::Utf8Str &aIPAddress,
270 const com::Utf8Str &aNetworkMask,
271 const com::Utf8Str &aLowerIP,
272 const com::Utf8Str &aUpperIP)
273{
274 RTNETADDRIPV4 IPAddress, NetworkMask, LowerIP, UpperIP;
275
276 int vrc = RTNetStrToIPv4Addr(aIPAddress.c_str(), &IPAddress);
277 if (RT_FAILURE(vrc))
278 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid server address");
279
280 vrc = RTNetStrToIPv4Addr(aNetworkMask.c_str(), &NetworkMask);
281 if (RT_FAILURE(vrc))
282 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid netmask");
283
284 vrc = RTNetStrToIPv4Addr(aLowerIP.c_str(), &LowerIP);
285 if (RT_FAILURE(vrc))
286 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid range lower address");
287
288 vrc = RTNetStrToIPv4Addr(aUpperIP.c_str(), &UpperIP);
289 if (RT_FAILURE(vrc))
290 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid range upper address");
291
292 /*
293 * Insist on continuous mask. May be also accept prefix length
294 * here or address/prefix for aIPAddress?
295 */
296 vrc = RTNetMaskToPrefixIPv4(&NetworkMask, NULL);
297 if (RT_FAILURE(vrc))
298 return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid netmask");
299
300 /* It's more convenient to convert to host order once */
301 IPAddress.u = RT_N2H_U32(IPAddress.u);
302 NetworkMask.u = RT_N2H_U32(NetworkMask.u);
303 LowerIP.u = RT_N2H_U32(LowerIP.u);
304 UpperIP.u = RT_N2H_U32(UpperIP.u);
305
306 /*
307 * Addresses must be unicast and from the same network
308 */
309 if ( (IPAddress.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
310 || (IPAddress.u & ~NetworkMask.u) == 0
311 || ((IPAddress.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
312 return mVirtualBox->setError(E_INVALIDARG, "Invalid server address");
313
314 if ( (LowerIP.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
315 || (LowerIP.u & NetworkMask.u) != (IPAddress.u &NetworkMask.u)
316 || (LowerIP.u & ~NetworkMask.u) == 0
317 || ((LowerIP.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
318 return mVirtualBox->setError(E_INVALIDARG, "Invalid range lower address");
319
320 if ( (UpperIP.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
321 || (UpperIP.u & NetworkMask.u) != (IPAddress.u &NetworkMask.u)
322 || (UpperIP.u & ~NetworkMask.u) == 0
323 || ((UpperIP.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
324 return mVirtualBox->setError(E_INVALIDARG, "Invalid range upper address");
325
326 /* The range should be valid ... */
327 if (LowerIP.u > UpperIP.u)
328 return mVirtualBox->setError(E_INVALIDARG, "Invalid range bounds");
329
330 /* ... and shouldn't contain the server's address */
331 if (LowerIP.u <= IPAddress.u && IPAddress.u <= UpperIP.u)
332 return mVirtualBox->setError(E_INVALIDARG, "Server address within range bounds");
333
334 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
335 m->IPAddress = aIPAddress;
336 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = aNetworkMask;
337
338 m->lowerIP = aLowerIP;
339 m->upperIP = aUpperIP;
340
341 // save the global settings; for that we should hold only the VirtualBox lock
342 alock.release();
343 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
344 return mVirtualBox->i_saveSettings();
345}
346
347
348HRESULT DHCPServer::encodeOption(com::Utf8Str &aEncoded,
349 uint32_t aOptCode,
350 const settings::DhcpOptValue &aOptValue)
351{
352 switch (aOptValue.encoding)
353 {
354 case DhcpOptEncoding_Legacy:
355 {
356 /*
357 * This is original encoding which assumed that for each
358 * option we know its format and so we know how option
359 * "value" text is to be interpreted.
360 *
361 * "2:10800" # integer 32
362 * "6:1.2.3.4 8.8.8.8" # array of ip-address
363 */
364 aEncoded = Utf8StrFmt("%d:%s", aOptCode, aOptValue.text.c_str());
365 break;
366 }
367
368 case DhcpOptEncoding_Hex:
369 {
370 /*
371 * This is a bypass for any option - preformatted value as
372 * hex string with no semantic involved in formatting the
373 * value for the DHCP reply.
374 *
375 * 234=68:65:6c:6c:6f:2c:20:77:6f:72:6c:64
376 */
377 aEncoded = Utf8StrFmt("%d=%s", aOptCode, aOptValue.text.c_str());
378 break;
379 }
380
381 default:
382 {
383 /*
384 * Try to be forward compatible.
385 *
386 * "254@42=i hope you know what this means"
387 */
388 aEncoded = Utf8StrFmt("%d@%d=%s", aOptCode, (int)aOptValue.encoding,
389 aOptValue.text.c_str());
390 break;
391 }
392 }
393
394 return S_OK;
395}
396
397
398int DHCPServer::addOption(settings::DhcpOptionMap &aMap,
399 DhcpOpt_T aOption, const com::Utf8Str &aValue)
400{
401 settings::DhcpOptValue OptValue;
402
403 if (aOption != 0)
404 {
405 OptValue = settings::DhcpOptValue(aValue, DhcpOptEncoding_Legacy);
406 }
407 /*
408 * This is a kludge to sneak in option encoding information
409 * through existing API. We use option 0 and supply the real
410 * option/value in the same format that encodeOption() above
411 * produces for getter methods.
412 */
413 else
414 {
415 uint8_t u8Code;
416 char *pszNext;
417 int vrc = RTStrToUInt8Ex(aValue.c_str(), &pszNext, 10, &u8Code);
418 if (!RT_SUCCESS(vrc))
419 return VERR_PARSE_ERROR;
420
421 uint32_t u32Enc;
422 switch (*pszNext)
423 {
424 case ':': /* support legacy format too */
425 {
426 u32Enc = DhcpOptEncoding_Legacy;
427 break;
428 }
429
430 case '=':
431 {
432 u32Enc = DhcpOptEncoding_Hex;
433 break;
434 }
435
436 case '@':
437 {
438 vrc = RTStrToUInt32Ex(pszNext + 1, &pszNext, 10, &u32Enc);
439 if (!RT_SUCCESS(vrc))
440 return VERR_PARSE_ERROR;
441 if (*pszNext != '=')
442 return VERR_PARSE_ERROR;
443 break;
444 }
445
446 default:
447 return VERR_PARSE_ERROR;
448 }
449
450 aOption = (DhcpOpt_T)u8Code;
451 OptValue = settings::DhcpOptValue(pszNext + 1, (DhcpOptEncoding_T)u32Enc);
452 }
453
454 aMap[aOption] = OptValue;
455 return VINF_SUCCESS;
456}
457
458
459HRESULT DHCPServer::addGlobalOption(DhcpOpt_T aOption, const com::Utf8Str &aValue)
460{
461 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
462
463 int rc = addOption(m->GlobalDhcpOptions, aOption, aValue);
464 if (!RT_SUCCESS(rc))
465 return E_INVALIDARG;
466
467 /* Indirect way to understand that we're on NAT network */
468 if (aOption == DhcpOpt_Router)
469 {
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 m->dhcp.setOption(DHCPServerRunner::kDsrKeyComment, m->networkName.c_str());
790#else /* !VBOX_WITH_DHCPD */
791 /* Main is needed for NATNetwork */
792 if (m->router)
793 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNeedMain, "on");
794
795 /* Commmon Network Settings */
796 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNetwork, aNetworkName.c_str());
797
798 if (!aTrunkName.isEmpty())
799 m->dhcp.setOption(NetworkServiceRunner::kNsrTrunkName, aTrunkName.c_str());
800
801 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyTrunkType, aTrunkType.c_str());
802
803 /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */
804 char strMAC[32];
805 Guid guid;
806 guid.create();
807 RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X",
808 guid.raw()->au8[0],
809 guid.raw()->au8[1],
810 guid.raw()->au8[2]);
811 m->dhcp.setOption(NetworkServiceRunner::kNsrMacAddress, strMAC);
812 m->dhcp.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPAddress).c_str());
813 m->dhcp.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
814 m->dhcp.setOption(DHCPServerRunner::kDsrKeyLowerIp, Utf8Str(m->lowerIP).c_str());
815 m->dhcp.setOption(DHCPServerRunner::kDsrKeyUpperIp, Utf8Str(m->upperIP).c_str());
816#endif /* !VBOX_WITH_DHCPD */
817
818 /* XXX: This parameters Dhcp Server will fetch via API */
819 return RT_FAILURE(m->dhcp.start(!m->router /* KillProcOnExit */)) ? E_FAIL : S_OK;
820 //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
821}
822
823
824HRESULT DHCPServer::stop (void)
825{
826#ifdef VBOX_WITH_DHCPD
827 if (m->tempConfigFileName[0])
828 {
829 RTFileDelete(m->tempConfigFileName);
830 m->tempConfigFileName[0] = 0;
831 }
832#endif /* VBOX_WITH_DHCPD */
833 return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK;
834}
835
836
837settings::DhcpOptionMap &DHCPServer::i_findOptMapByVmNameSlot(const com::Utf8Str &aVmName,
838 LONG aSlot)
839{
840 return m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
841}
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