VirtualBox

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

Last change on this file since 54407 was 54407, checked in by vboxsync, 10 years ago

Main/DHCPServerImpl: kludge to sneak in dhcp option encoding through
existing API. If the option to set is 0, interpret the value as the
encoded string from getter methods that supplies option code, option
text and its encoding.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 KB
Line 
1/* $Id: DHCPServerImpl.cpp 54407 2015-02-24 00:04:44Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2013 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/cpp/utils.h>
27
28#include <VBox/com/array.h>
29#include <VBox/settings.h>
30
31#include "VirtualBoxImpl.h"
32
33// constructor / destructor
34/////////////////////////////////////////////////////////////////////////////
35const std::string DHCPServerRunner::kDsrKeyGateway = "--gateway";
36const std::string DHCPServerRunner::kDsrKeyLowerIp = "--lower-ip";
37const std::string DHCPServerRunner::kDsrKeyUpperIp = "--upper-ip";
38
39
40struct DHCPServer::Data
41{
42 Data() : enabled(FALSE) {}
43
44 Bstr IPAddress;
45 Bstr lowerIP;
46 Bstr upperIP;
47
48 BOOL enabled;
49 DHCPServerRunner dhcp;
50
51 DhcpOptionMap GlobalDhcpOptions;
52 VmSlot2OptionsMap VmSlot2Options;
53};
54
55
56DHCPServer::DHCPServer()
57 : m(NULL), mVirtualBox(NULL)
58{
59 m = new DHCPServer::Data();
60}
61
62
63DHCPServer::~DHCPServer()
64{
65 if (m)
66 {
67 delete m;
68 m = NULL;
69 }
70}
71
72
73HRESULT DHCPServer::FinalConstruct()
74{
75 return BaseFinalConstruct();
76}
77
78
79void DHCPServer::FinalRelease()
80{
81 uninit ();
82
83 BaseFinalRelease();
84}
85
86
87void DHCPServer::uninit()
88{
89 /* Enclose the state transition Ready->InUninit->NotReady */
90 AutoUninitSpan autoUninitSpan(this);
91 if (autoUninitSpan.uninitDone())
92 return;
93
94 unconst(mVirtualBox) = NULL;
95}
96
97
98HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName)
99{
100 AssertReturn(aName != NULL, E_INVALIDARG);
101
102 AutoInitSpan autoInitSpan(this);
103 AssertReturn(autoInitSpan.isOk(), E_FAIL);
104
105 /* share VirtualBox weakly (parent remains NULL so far) */
106 unconst(mVirtualBox) = aVirtualBox;
107
108 unconst(mName) = aName;
109 m->IPAddress = "0.0.0.0";
110 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = DhcpOptValue("0.0.0.0");
111 m->enabled = FALSE;
112
113 m->lowerIP = "0.0.0.0";
114 m->upperIP = "0.0.0.0";
115
116 /* Confirm a successful initialization */
117 autoInitSpan.setSucceeded();
118
119 return S_OK;
120}
121
122
123HRESULT DHCPServer::init(VirtualBox *aVirtualBox,
124 const settings::DHCPServer &data)
125{
126 /* Enclose the state transition NotReady->InInit->Ready */
127 AutoInitSpan autoInitSpan(this);
128 AssertReturn(autoInitSpan.isOk(), E_FAIL);
129
130 /* share VirtualBox weakly (parent remains NULL so far) */
131 unconst(mVirtualBox) = aVirtualBox;
132
133 unconst(mName) = data.strNetworkName;
134 m->IPAddress = data.strIPAddress;
135 m->enabled = data.fEnabled;
136 m->lowerIP = data.strIPLower;
137 m->upperIP = data.strIPUpper;
138
139 m->GlobalDhcpOptions.clear();
140 m->GlobalDhcpOptions.insert(data.GlobalDhcpOptions.begin(),
141 data.GlobalDhcpOptions.end());
142
143 m->VmSlot2Options.clear();
144 m->VmSlot2Options.insert(data.VmSlot2OptionsM.begin(),
145 data.VmSlot2OptionsM.end());
146
147 autoInitSpan.setSucceeded();
148
149 return S_OK;
150}
151
152
153HRESULT DHCPServer::i_saveSettings(settings::DHCPServer &data)
154{
155 AutoCaller autoCaller(this);
156 if (FAILED(autoCaller.rc())) return autoCaller.rc();
157
158 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
159
160 data.strNetworkName = mName;
161 data.strIPAddress = m->IPAddress;
162
163 data.fEnabled = !!m->enabled;
164 data.strIPLower = m->lowerIP;
165 data.strIPUpper = m->upperIP;
166
167 data.GlobalDhcpOptions.clear();
168 data.GlobalDhcpOptions.insert(m->GlobalDhcpOptions.begin(),
169 m->GlobalDhcpOptions.end());
170
171 data.VmSlot2OptionsM.clear();
172 data.VmSlot2OptionsM.insert(m->VmSlot2Options.begin(),
173 m->VmSlot2Options.end());
174
175 return S_OK;
176}
177
178
179HRESULT DHCPServer::getNetworkName(com::Utf8Str &aName)
180{
181 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
182
183 aName = mName;
184 return S_OK;
185}
186
187
188HRESULT DHCPServer::getEnabled(BOOL *aEnabled)
189{
190 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
191
192 *aEnabled = m->enabled;
193 return S_OK;
194}
195
196
197HRESULT DHCPServer::setEnabled(BOOL aEnabled)
198{
199 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
200 m->enabled = aEnabled;
201
202 // save the global settings; for that we should hold only the VirtualBox lock
203 alock.release();
204 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
205 HRESULT rc = mVirtualBox->i_saveSettings();
206
207 return rc;
208}
209
210
211HRESULT DHCPServer::getIPAddress(com::Utf8Str &aIPAddress)
212{
213 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
214
215 aIPAddress = Utf8Str(m->IPAddress);
216 return S_OK;
217}
218
219
220HRESULT DHCPServer::getNetworkMask(com::Utf8Str &aNetworkMask)
221{
222 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
223
224 aNetworkMask = m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text;
225 return S_OK;
226}
227
228
229HRESULT DHCPServer::getLowerIP(com::Utf8Str &aIPAddress)
230{
231 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
232
233 aIPAddress = Utf8Str(m->lowerIP);
234 return S_OK;
235}
236
237
238HRESULT DHCPServer::getUpperIP(com::Utf8Str &aIPAddress)
239{
240 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
241
242 aIPAddress = Utf8Str(m->upperIP);
243 return S_OK;
244}
245
246
247HRESULT DHCPServer::setConfiguration(const com::Utf8Str &aIPAddress,
248 const com::Utf8Str &aNetworkMask,
249 const com::Utf8Str &aLowerIP,
250 const com::Utf8Str &aUpperIP)
251{
252 AssertReturn(!aIPAddress.isEmpty(), E_INVALIDARG);
253 AssertReturn(!aNetworkMask.isEmpty(), E_INVALIDARG);
254 AssertReturn(!aLowerIP.isEmpty(), E_INVALIDARG);
255 AssertReturn(!aUpperIP.isEmpty(), E_INVALIDARG);
256
257 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
258 m->IPAddress = aIPAddress;
259 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = aNetworkMask;
260
261 m->lowerIP = aLowerIP;
262 m->upperIP = aUpperIP;
263
264 // save the global settings; for that we should hold only the VirtualBox lock
265 alock.release();
266 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
267 return mVirtualBox->i_saveSettings();
268}
269
270
271HRESULT DHCPServer::encodeOption(com::Utf8Str &aEncoded,
272 uint32_t aOptCode, const DhcpOptValue &aOptValue)
273{
274 switch (aOptValue.encoding)
275 {
276 case DhcpOptValue::LEGACY:
277 {
278 /*
279 * This is original encoding which assumed that for each
280 * option we know its format and so we know how option
281 * "value" text is to be interpreted.
282 *
283 * "2:10800" # integer 32
284 * "6:1.2.3.4 8.8.8.8" # array of ip-address
285 */
286 aEncoded = Utf8StrFmt("%d:%s", aOptCode, aOptValue.text.c_str());
287 break;
288 }
289
290 case DhcpOptValue::HEX:
291 {
292 /*
293 * This is a bypass for any option - preformatted value as
294 * hex string with no semantic involved in formatting the
295 * value for the DHCP reply.
296 *
297 * 234=68:65:6c:6c:6f:2c:20:77:6f:72:6c:64
298 */
299 aEncoded = Utf8StrFmt("%d=%s", aOptCode, aOptValue.text.c_str());
300 break;
301 }
302
303 default:
304 {
305 /*
306 * Try to be forward compatible.
307 *
308 * "254@42=i hope you know what this means"
309 */
310 aEncoded = Utf8StrFmt("%d@%d=%s", aOptCode, (int)aOptValue.encoding,
311 aOptValue.text.c_str());
312 break;
313 }
314 }
315
316 return S_OK;
317}
318
319
320int DHCPServer::addOption(DhcpOptionMap &aMap,
321 DhcpOpt_T aOption, const com::Utf8Str &aValue)
322{
323 DhcpOptValue OptValue;
324
325 if (aOption != 0)
326 {
327 OptValue = DhcpOptValue(aValue, DhcpOptValue::LEGACY);
328 }
329 /*
330 * This is a kludge to sneak in option encoding information
331 * through existing API. We use option 0 and supply the real
332 * option/value in the same format that encodeOption() above
333 * produces for getter methods.
334 */
335 else
336 {
337 uint8_t u8Code;
338 uint32_t u32Enc;
339 char *pszNext;
340 int rc;
341
342 rc = RTStrToUInt8Ex(aValue.c_str(), &pszNext, 10, &u8Code);
343 if (!RT_SUCCESS(rc))
344 return VERR_PARSE_ERROR;
345
346 switch (*pszNext)
347 {
348 case ':': /* support legacy format too */
349 {
350 u32Enc = DhcpOptValue::LEGACY;
351 break;
352 }
353
354 case '=':
355 {
356 u32Enc = DhcpOptValue::HEX;
357 break;
358 }
359
360 case '@':
361 {
362 rc = RTStrToUInt32Ex(pszNext + 1, &pszNext, 10, &u32Enc);
363 if (!RT_SUCCESS(rc))
364 return VERR_PARSE_ERROR;
365 if (*pszNext != '=')
366 return VERR_PARSE_ERROR;
367 break;
368 }
369
370 default:
371 return VERR_PARSE_ERROR;
372 }
373
374 aOption = (DhcpOpt_T)u8Code;
375 OptValue = DhcpOptValue(pszNext + 1, (DhcpOptValue::Encoding)u32Enc);
376 }
377
378 aMap[aOption] = OptValue;
379 return VINF_SUCCESS;
380}
381
382
383HRESULT DHCPServer::addGlobalOption(DhcpOpt_T aOption, const com::Utf8Str &aValue)
384{
385 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
386
387 int rc = addOption(m->GlobalDhcpOptions, aOption, aValue);
388 if (!RT_SUCCESS(rc))
389 return E_INVALIDARG;
390
391 /* Indirect way to understand that we're on NAT network */
392 if (aOption == DhcpOpt_Router)
393 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNeedMain, "on");
394
395 alock.release();
396
397 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
398 return mVirtualBox->i_saveSettings();
399}
400
401
402HRESULT DHCPServer::getGlobalOptions(std::vector<com::Utf8Str> &aValues)
403{
404 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
405 aValues.resize(m->GlobalDhcpOptions.size());
406 DhcpOptionMap::const_iterator it;
407 size_t i = 0;
408 for (it = m->GlobalDhcpOptions.begin(); it != m->GlobalDhcpOptions.end(); ++it, ++i)
409 {
410 uint32_t OptCode = (*it).first;
411 const DhcpOptValue &OptValue = (*it).second;
412
413 encodeOption(aValues[i], OptCode, OptValue);
414 }
415
416 return S_OK;
417}
418
419HRESULT DHCPServer::getVmConfigs(std::vector<com::Utf8Str> &aValues)
420{
421 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
422 aValues.resize(m->VmSlot2Options.size());
423 VmSlot2OptionsMap::const_iterator it;
424 size_t i = 0;
425 for (it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it, ++i)
426 {
427 aValues[i] = Utf8StrFmt("[%s]:%d", it->first.VmName.c_str(), it->first.Slot);
428 }
429
430 return S_OK;
431}
432
433
434HRESULT DHCPServer::addVmSlotOption(const com::Utf8Str &aVmName,
435 LONG aSlot,
436 DhcpOpt_T aOption,
437 const com::Utf8Str &aValue)
438{
439 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
440
441 DhcpOptionMap &map = m->VmSlot2Options[VmNameSlotKey(aVmName, aSlot)];
442 int rc = addOption(map, aOption, aValue);
443 if (!RT_SUCCESS(rc))
444 return E_INVALIDARG;
445
446 alock.release();
447
448 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
449 return mVirtualBox->i_saveSettings();
450}
451
452
453HRESULT DHCPServer::removeVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot)
454{
455 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
456 DhcpOptionMap& map = i_findOptMapByVmNameSlot(aVmName, aSlot);
457 map.clear();
458
459 alock.release();
460
461 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
462 return mVirtualBox->i_saveSettings();
463}
464
465/**
466 * this is mapping (vm, slot)
467 */
468HRESULT DHCPServer::getVmSlotOptions(const com::Utf8Str &aVmName,
469 LONG aSlot,
470 std::vector<com::Utf8Str> &aValues)
471{
472
473 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
474 DhcpOptionMap& map = i_findOptMapByVmNameSlot(aVmName, aSlot);
475 aValues.resize(map.size());
476 size_t i = 0;
477 DhcpOptionMap::const_iterator it;
478 for (it = map.begin(); it != map.end(); ++it, ++i)
479 {
480 uint32_t OptCode = (*it).first;
481 const DhcpOptValue &OptValue = (*it).second;
482
483 encodeOption(aValues[i], OptCode, OptValue);
484 }
485
486 return S_OK;
487}
488
489
490HRESULT DHCPServer::getMacOptions(const com::Utf8Str &aMAC, std::vector<com::Utf8Str> &aOption)
491{
492 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
493 HRESULT hrc = S_OK;
494 ComPtr<IMachine> machine;
495 ComPtr<INetworkAdapter> nic;
496 VmSlot2OptionsIterator it;
497 for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
498 {
499 alock.release();
500 hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
501 alock.acquire();
502
503 if (FAILED(hrc))
504 continue;
505
506 alock.release();
507 hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
508 alock.acquire();
509
510 if (FAILED(hrc))
511 continue;
512
513 com::Bstr mac;
514
515 alock.release();
516 hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
517 alock.acquire();
518
519 if (FAILED(hrc)) /* no MAC address ??? */
520 break;
521 if (!RTStrICmp(com::Utf8Str(mac).c_str(), aMAC.c_str()))
522 return getVmSlotOptions(it->first.VmName,
523 it->first.Slot,
524 aOption);
525 } /* end of for */
526
527 return hrc;
528}
529
530HRESULT DHCPServer::getEventSource(ComPtr<IEventSource> &aEventSource)
531{
532 NOREF(aEventSource);
533 ReturnComNotImplemented();
534}
535
536
537HRESULT DHCPServer::start(const com::Utf8Str &aNetworkName,
538 const com::Utf8Str &aTrunkName,
539 const com::Utf8Str &aTrunkType)
540{
541 /* Silently ignore attempts to run disabled servers. */
542 if (!m->enabled)
543 return S_OK;
544
545 /* Commmon Network Settings */
546 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNetwork, aNetworkName.c_str());
547
548 if (!aTrunkName.isEmpty())
549 m->dhcp.setOption(NetworkServiceRunner::kNsrTrunkName, aTrunkName.c_str());
550
551 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyTrunkType, aTrunkType.c_str());
552
553 /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */
554 char strMAC[32];
555 Guid guid;
556 guid.create();
557 RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X",
558 guid.raw()->au8[0],
559 guid.raw()->au8[1],
560 guid.raw()->au8[2]);
561 m->dhcp.setOption(NetworkServiceRunner::kNsrMacAddress, strMAC);
562 m->dhcp.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPAddress).c_str());
563 m->dhcp.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
564 m->dhcp.setOption(DHCPServerRunner::kDsrKeyLowerIp, Utf8Str(m->lowerIP).c_str());
565 m->dhcp.setOption(DHCPServerRunner::kDsrKeyUpperIp, Utf8Str(m->upperIP).c_str());
566
567 /* XXX: This parameters Dhcp Server will fetch via API */
568 return RT_FAILURE(m->dhcp.start()) ? E_FAIL : S_OK;
569 //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
570}
571
572
573HRESULT DHCPServer::stop (void)
574{
575 return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK;
576}
577
578
579DhcpOptionMap& DHCPServer::i_findOptMapByVmNameSlot(const com::Utf8Str& aVmName,
580 LONG aSlot)
581{
582 return m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
583}
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