VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/DHCPConfigImpl.cpp@ 79812

Last change on this file since 79812 was 79800, checked in by vboxsync, 5 years ago

Dhcpd,Main: Working on extending the DHCP server end to cope with new configuration features in IDHCPServer. bugref:9288

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.2 KB
Line 
1/* $Id: DHCPConfigImpl.cpp 79800 2019-07-16 00:06:00Z vboxsync $ */
2/** @file
3 * VirtualBox Main - IDHCPConfig, IDHCPConfigGlobal, IDHCPConfigGroup, IDHCPConfigIndividual 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
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MAIN_DHCPCONFIG
23#include "DHCPConfigImpl.h"
24#include "LoggingNew.h"
25
26#include <iprt/ctype.h>
27#include <iprt/errcore.h>
28#include <iprt/net.h>
29#include <iprt/cpp/utils.h>
30#include <iprt/cpp/xml.h>
31
32#include <VBox/com/array.h>
33#include <VBox/settings.h>
34
35#include "AutoCaller.h"
36#include "DHCPServerImpl.h"
37#include "MachineImpl.h"
38#include "VirtualBoxImpl.h"
39
40#include "../../NetworkServices/Dhcpd/DhcpOptions.h"
41
42
43
44/*********************************************************************************************************************************
45* DHCPConfig Implementation *
46*********************************************************************************************************************************/
47
48HRESULT DHCPConfig::i_initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent)
49{
50 unconst(m_pVirtualBox) = a_pVirtualBox;
51 unconst(m_pParent) = a_pParent;
52 return S_OK;
53}
54
55
56HRESULT DHCPConfig::i_initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPConfig &rConfig)
57{
58 unconst(m_pVirtualBox) = a_pVirtualBox;
59 unconst(m_pParent) = a_pParent;
60
61 m_secMinLeaseTime = rConfig.secMinLeaseTime;
62 m_secDefaultLeaseTime = rConfig.secDefaultLeaseTime;
63 m_secMaxLeaseTime = rConfig.secMaxLeaseTime;
64
65 for (settings::DhcpOptionMap::const_iterator it = rConfig.mapOptions.begin(); it != rConfig.mapOptions.end(); ++it)
66 {
67 try
68 {
69 m_OptionMap[it->first] = settings::DhcpOptValue(it->second.strValue, it->second.enmEncoding);
70 }
71 catch (std::bad_alloc &)
72 {
73 return E_OUTOFMEMORY;
74 }
75 }
76
77 return S_OK;
78}
79
80
81HRESULT DHCPConfig::i_saveSettings(settings::DHCPConfig &a_rDst)
82{
83 /* lease times */
84 a_rDst.secMinLeaseTime = m_secMinLeaseTime;
85 a_rDst.secDefaultLeaseTime = m_secDefaultLeaseTime;
86 a_rDst.secMaxLeaseTime = m_secMaxLeaseTime;
87
88 /* Options: */
89 try
90 {
91 a_rDst.mapOptions = m_OptionMap;
92 }
93 catch (std::bad_alloc &)
94 {
95 return E_OUTOFMEMORY;
96 }
97 return S_OK;
98}
99
100
101HRESULT DHCPConfig::i_getScope(DHCPConfigScope_T *aScope)
102{
103 /* No locking needed. */
104 *aScope = m_enmScope;
105 return S_OK;
106}
107
108
109HRESULT DHCPConfig::i_getMinLeaseTime(ULONG *aMinLeaseTime)
110{
111 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
112 *aMinLeaseTime = m_secMinLeaseTime;
113 return S_OK;
114}
115
116
117HRESULT DHCPConfig::i_setMinLeaseTime(ULONG aMinLeaseTime)
118{
119 {
120 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
121 m_secMinLeaseTime = aMinLeaseTime;
122 }
123 return i_doWriteConfig();
124}
125
126
127HRESULT DHCPConfig::i_getDefaultLeaseTime(ULONG *aDefaultLeaseTime)
128{
129 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
130 *aDefaultLeaseTime = m_secDefaultLeaseTime;
131 return S_OK;
132}
133
134
135HRESULT DHCPConfig::i_setDefaultLeaseTime(ULONG aDefaultLeaseTime)
136{
137 {
138 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
139 m_secDefaultLeaseTime = aDefaultLeaseTime;
140 }
141 return i_doWriteConfig();
142}
143
144
145HRESULT DHCPConfig::i_getMaxLeaseTime(ULONG *aMaxLeaseTime)
146{
147 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
148 *aMaxLeaseTime = m_secMaxLeaseTime;
149 return S_OK;
150}
151
152
153HRESULT DHCPConfig::i_setMaxLeaseTime(ULONG aMaxLeaseTime)
154{
155 {
156 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
157 m_secMaxLeaseTime = aMaxLeaseTime;
158 }
159 return i_doWriteConfig();
160}
161
162
163HRESULT DHCPConfig::i_setOption(DhcpOpt_T aOption, DHCPOptionEncoding_T aEncoding, const com::Utf8Str &aValue)
164{
165 /*
166 * Validate the option as there is no point in allowing the user to set
167 * something that the DHCP server does not grok. It will only lead to
168 * startup failures an no DHCP. We share this code with the server.
169 */
170 DhcpOption *pParsed = NULL;
171 int rc = VINF_SUCCESS;
172 try
173 {
174 pParsed = DhcpOption::parse((uint8_t)aOption, aEncoding, aValue.c_str(), &rc);
175 }
176 catch (std::bad_alloc &)
177 {
178 return E_OUTOFMEMORY;
179 }
180 if (pParsed)
181 {
182 delete pParsed;
183
184 /*
185 * Add/change it.
186 */
187 {
188 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
189 try
190 {
191 m_OptionMap[aOption] = settings::DhcpOptValue(aValue, aEncoding);
192 }
193 catch (std::bad_alloc &)
194 {
195 return E_OUTOFMEMORY;
196 }
197 }
198 i_doWriteConfig();
199 return S_OK;
200 }
201
202 if (rc == VERR_WRONG_TYPE)
203 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Unsupported encoding %d (option %d, value %s)"),
204 (int)aEncoding, (int)aOption, aValue.c_str());
205 if (rc == VERR_NOT_SUPPORTED)
206 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Unsupported option %d (encoding %d, value %s)"),
207 (int)aOption, (int)aEncoding, aValue.c_str());
208 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Malformed option %d value '%s' (encoding %d, rc=%Rrc)"),
209 (int)aOption, aValue.c_str(), (int)aEncoding, rc);
210}
211
212
213HRESULT DHCPConfig::i_removeOption(DhcpOpt_T aOption)
214{
215 {
216 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
217 settings::DhcpOptionMap::iterator it = m_OptionMap.find(aOption);
218 if (it != m_OptionMap.end())
219 m_OptionMap.erase(it);
220 else
221 return m_pHack->setError(VBOX_E_OBJECT_NOT_FOUND, m_pHack->tr("DHCP option %u was not found"), aOption);
222 }
223 return i_doWriteConfig();
224}
225
226
227HRESULT DHCPConfig::i_removeAllOptions()
228{
229 {
230 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
231 m_OptionMap.erase(m_OptionMap.begin(), m_OptionMap.end());
232 }
233 return i_doWriteConfig();
234}
235
236
237HRESULT DHCPConfig::i_getOption(DhcpOpt_T aOption, DHCPOptionEncoding_T *aEncoding, com::Utf8Str &aValue)
238{
239 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
240 settings::DhcpOptionMap::const_iterator it = m_OptionMap.find(aOption);
241 if (it != m_OptionMap.end())
242 {
243 *aEncoding = it->second.enmEncoding;
244 return aValue.assignEx(it->second.strValue);
245 }
246 return m_pHack->setError(VBOX_E_OBJECT_NOT_FOUND, m_pHack->tr("DHCP option %u was not found"), aOption);
247}
248
249
250HRESULT DHCPConfig::i_getAllOptions(std::vector<DhcpOpt_T> &aOptions, std::vector<DHCPOptionEncoding_T> &aEncodings,
251 std::vector<com::Utf8Str> &aValues)
252{
253 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
254 try
255 {
256 aOptions.resize(m_OptionMap.size());
257 aEncodings.resize(m_OptionMap.size());
258 aValues.resize(m_OptionMap.size());
259 size_t i = 0;
260 for (settings::DhcpOptionMap::iterator it = m_OptionMap.begin(); it != m_OptionMap.end(); ++it, i++)
261 {
262 aOptions[i] = it->first;
263 aEncodings[i] = it->second.enmEncoding;
264 aValues[i] = it->second.strValue;
265 }
266 }
267 catch (std::bad_alloc &)
268 {
269 return E_OUTOFMEMORY;
270 }
271 return S_OK;
272}
273
274
275HRESULT DHCPConfig::i_remove()
276{
277 return m_pParent->i_removeConfig(this, m_enmScope);
278}
279
280
281
282/**
283 * Causes the global VirtualBox configuration file to be written
284 *
285 * @returns COM status code.
286 *
287 * @note Must hold no locks when this is called!
288 * @note Public because DHCPGroupCondition needs to call it too.
289 */
290HRESULT DHCPConfig::i_doWriteConfig()
291{
292 AssertPtrReturn(m_pVirtualBox, E_FAIL);
293
294 AutoWriteLock alock(m_pVirtualBox COMMA_LOCKVAL_SRC_POS);
295 return m_pVirtualBox->i_saveSettings();
296}
297
298
299/**
300 * Produces the Dhcpd configuration.
301 *
302 * The base class only saves DHCP options.
303 *
304 * @param pElmConfig The element where to put the configuration.
305 * @throws std::bad_alloc
306 */
307void DHCPConfig::i_writeDhcpdConfig(xml::ElementNode *pElmConfig)
308{
309 if (m_secMinLeaseTime > 0 )
310 pElmConfig->setAttribute("secMinLeaseTime", (uint32_t)m_secMinLeaseTime);
311 if (m_secDefaultLeaseTime > 0 )
312 pElmConfig->setAttribute("secDefaultLeaseTime", (uint32_t)m_secDefaultLeaseTime);
313 if (m_secMaxLeaseTime > 0 )
314 pElmConfig->setAttribute("secMaxLeaseTime", (uint32_t)m_secMaxLeaseTime);
315
316 for (settings::DhcpOptionMap::const_iterator it = m_OptionMap.begin(); it != m_OptionMap.end(); ++it)
317 {
318 xml::ElementNode *pOption = pElmConfig->createChild("Option");
319 pOption->setAttribute("name", (int)it->first);
320 pOption->setAttribute("encoding", it->second.enmEncoding);
321 pOption->setAttribute("value", it->second.strValue);
322 }
323}
324
325
326
327/*********************************************************************************************************************************
328* DHCPGlobalConfig Implementation *
329*********************************************************************************************************************************/
330#undef LOG_GROUP
331#define LOG_GROUP LOG_GROUP_MAIN_DHCPGLOBALCONFIG
332
333HRESULT DHCPGlobalConfig::initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent)
334{
335 AutoInitSpan autoInitSpan(this);
336 AssertReturn(autoInitSpan.isOk(), E_FAIL);
337
338 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
339 if (SUCCEEDED(hrc))
340 hrc = i_setOption(DhcpOpt_SubnetMask, DHCPOptionEncoding_Normal, "0.0.0.0");
341
342 if (SUCCEEDED(hrc))
343 autoInitSpan.setSucceeded();
344 return hrc;
345}
346
347
348HRESULT DHCPGlobalConfig::initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPConfig &rConfig)
349{
350 AutoInitSpan autoInitSpan(this);
351 AssertReturn(autoInitSpan.isOk(), E_FAIL);
352
353 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
354 if (SUCCEEDED(hrc))
355 autoInitSpan.setSucceeded();
356 else
357 autoInitSpan.setFailed(hrc);
358 return hrc;
359}
360
361
362void DHCPGlobalConfig::uninit()
363{
364 AutoUninitSpan autoUninitSpan(this);
365 if (!autoUninitSpan.uninitDone())
366 autoUninitSpan.setSucceeded();
367}
368
369
370HRESULT DHCPGlobalConfig::i_saveSettings(settings::DHCPConfig &a_rDst)
371{
372 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
373
374 return DHCPConfig::i_saveSettings(a_rDst);
375}
376
377
378/**
379 * For getting the network mask option value (IDHCPServer::netmask attrib).
380 *
381 * @returns COM status code.
382 * @param a_rDst Where to return it.
383 * @throws nothing
384 */
385HRESULT DHCPGlobalConfig::i_getNetworkMask(com::Utf8Str &a_rDst)
386{
387 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
388 settings::DhcpOptionMap::const_iterator it = m_OptionMap.find(DhcpOpt_SubnetMask);
389 if (it != m_OptionMap.end())
390 {
391 if (it->second.enmEncoding == DHCPOptionEncoding_Normal)
392 return a_rDst.assignEx(it->second.strValue);
393 return setError(VBOX_E_OBJECT_NOT_FOUND, tr("DHCP option DhcpOpt_SubnetMask is not in a legacy encoding"));
394 }
395 return setError(VBOX_E_OBJECT_NOT_FOUND, tr("DHCP option DhcpOpt_SubnetMask was not found"));
396}
397
398
399/**
400 * For setting the network mask option value (IDHCPServer::netmask attrib).
401 *
402 * @returns COM status code.
403 * @param a_rSrc The new value.
404 * @throws nothing
405 */
406HRESULT DHCPGlobalConfig::i_setNetworkMask(const com::Utf8Str &a_rSrc)
407{
408 /* Validate it before setting it: */
409 RTNETADDRIPV4 AddrIgnored;
410 int vrc = RTNetStrToIPv4Addr(a_rSrc.c_str(), &AddrIgnored);
411 if (RT_FAILURE(vrc))
412 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid IPv4 netmask '%s': %Rrc"), a_rSrc.c_str(), vrc);
413
414 return i_setOption(DhcpOpt_SubnetMask, DHCPOptionEncoding_Normal, a_rSrc);
415}
416
417
418/**
419 * Overriden to ensure the sanity of the DhcpOpt_SubnetMask option.
420 */
421HRESULT DHCPGlobalConfig::i_setOption(DhcpOpt_T aOption, DHCPOptionEncoding_T aEncoding, const com::Utf8Str &aValue)
422{
423 if (aOption != DhcpOpt_SubnetMask || aEncoding == DHCPOptionEncoding_Normal)
424 return DHCPConfig::i_setOption(aOption, aEncoding, aValue);
425 return setError(E_FAIL, tr("DhcpOpt_SubnetMask must use DHCPOptionEncoding_Normal as it is reflected by IDHCPServer::networkMask"));
426}
427
428
429/**
430 * Overriden to ensure the sanity of the DhcpOpt_SubnetMask option.
431 */
432HRESULT DHCPGlobalConfig::i_removeOption(DhcpOpt_T aOption)
433{
434 if (aOption != DhcpOpt_SubnetMask)
435 return DHCPConfig::i_removeOption(aOption);
436 return setError(E_FAIL, tr("DhcpOpt_SubnetMask cannot be removed as it reflects IDHCPServer::networkMask"));
437}
438
439
440/**
441 * Overriden to preserve the DhcpOpt_SubnetMask option.
442 */
443HRESULT DHCPGlobalConfig::i_removeAllOptions()
444{
445 {
446 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
447 settings::DhcpOptionMap::iterator it = m_OptionMap.find(DhcpOpt_SubnetMask);
448 m_OptionMap.erase(m_OptionMap.begin(), it);
449 if (it != m_OptionMap.end())
450 {
451 ++it;
452 if (it != m_OptionMap.end())
453 m_OptionMap.erase(it, m_OptionMap.end());
454 }
455 }
456
457 return i_doWriteConfig();
458}
459
460
461/**
462 * Overriden to prevent removal.
463 */
464HRESULT DHCPGlobalConfig::i_remove()
465{
466 return setError(E_ACCESSDENIED, tr("Cannot delete the global config"));
467}
468
469
470
471/*********************************************************************************************************************************
472* DHCPGroupCondition Implementation *
473*********************************************************************************************************************************/
474#undef LOG_GROUP
475#define LOG_GROUP LOG_GROUP_MAIN_DHCPGROUPCONDITION
476
477HRESULT DHCPGroupCondition::initWithDefaults(DHCPGroupConfig *a_pParent, bool a_fInclusive, DHCPGroupConditionType_T a_enmType,
478 const com::Utf8Str a_strValue)
479{
480 AutoInitSpan autoInitSpan(this);
481 AssertReturn(autoInitSpan.isOk(), E_FAIL);
482
483 m_pParent = a_pParent;
484 m_fInclusive = a_fInclusive;
485 m_enmType = a_enmType;
486 HRESULT hrc = m_strValue.assignEx(a_strValue);
487
488 if (SUCCEEDED(hrc))
489 autoInitSpan.setSucceeded();
490 else
491 autoInitSpan.setFailed(hrc);
492 return hrc;
493}
494
495
496HRESULT DHCPGroupCondition::initWithSettings(DHCPGroupConfig *a_pParent, const settings::DHCPGroupCondition &a_rSrc)
497{
498 return initWithDefaults(a_pParent, a_rSrc.fInclusive, a_rSrc.enmType, a_rSrc.strValue);
499}
500
501
502void DHCPGroupCondition::uninit()
503{
504 AutoUninitSpan autoUninitSpan(this);
505 if (!autoUninitSpan.uninitDone())
506 autoUninitSpan.setSucceeded();
507}
508
509
510HRESULT DHCPGroupCondition::i_saveSettings(settings::DHCPGroupCondition &a_rDst)
511{
512 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
513
514 a_rDst.fInclusive = m_fInclusive;
515 a_rDst.enmType = m_enmType;
516 return a_rDst.strValue.assignEx(m_strValue);
517}
518
519
520/**
521 * Worker for validating the condition value according to the given type.
522 *
523 * @returns COM status code.
524 * @param enmType The condition type.
525 * @param strValue The condition value.
526 * @param pErrorDst The object to use for reporting errors.
527 */
528/*static*/ HRESULT DHCPGroupCondition::i_validateTypeAndValue(DHCPGroupConditionType_T enmType, com::Utf8Str const &strValue,
529 VirtualBoxBase *pErrorDst)
530{
531 switch (enmType)
532 {
533 case DHCPGroupConditionType_MAC:
534 {
535 RTMAC MACAddress;
536 int vrc = RTNetStrToMacAddr(strValue.c_str(), &MACAddress);
537 if (RT_SUCCESS(vrc))
538 return S_OK;
539 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Not a valid MAC address: %s"), strValue.c_str());
540 }
541
542 case DHCPGroupConditionType_MACWildcard:
543 {
544 /* This must be colon separated double xdigit bytes. Single bytes
545 shorthand or raw hexstrings won't match anything. For reasons of
546 simplicity, '?' can only be used to match xdigits, '*' must match 1+
547 chars. */
548 /** @todo test this properly... */
549 const char *psz = strValue.c_str();
550 size_t off = 0;
551 unsigned cPairsLeft = 6;
552 bool fSeenAsterisk = false;
553 for (;;)
554 {
555 char ch = psz[off++];
556 if (RT_C_IS_XDIGIT(ch) || ch == '?')
557 {
558 ch = psz[off++];
559 if (RT_C_IS_XDIGIT(ch) || ch == '?')
560 {
561 ch = psz[off++];
562 cPairsLeft -= 1;
563 if (cPairsLeft == 0)
564 {
565 if (!ch)
566 return S_OK;
567 return pErrorDst->setError(E_INVALIDARG,
568 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
569 psz, off - 1);
570 }
571 if (ch == ':' || ch == '*')
572 continue;
573 if (ch == '\0' && fSeenAsterisk)
574 return S_OK;
575 return pErrorDst->setError(E_INVALIDARG,
576 pErrorDst->tr("Malformed MAC wildcard address: %s (offset %zu)"),
577 psz, off - 1);
578 }
579
580 if (ch == '*')
581 {
582 fSeenAsterisk = true;
583 do
584 ch = psz[off++];
585 while (ch == '*');
586 if (ch == '\0')
587 return S_OK;
588 cPairsLeft -= 1;
589 if (cPairsLeft == 0)
590 return pErrorDst->setError(E_INVALIDARG,
591 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
592 psz, off - 1);
593 if (ch == ':')
594 continue;
595 }
596 else
597 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Malformed MAC wildcard address: %s (offset %zu)"),
598 psz, off - 1);
599 }
600 else if (ch == '*')
601 {
602 fSeenAsterisk = true;
603 do
604 ch = psz[off++];
605 while (ch == '*');
606 if (ch == '\0')
607 return S_OK;
608 if (ch == ':')
609 {
610 cPairsLeft -= 1;
611 if (cPairsLeft == 0)
612 return pErrorDst->setError(E_INVALIDARG,
613 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
614 psz, off - 1);
615 continue;
616 }
617
618 }
619 else
620 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Malformed MAC wildcard address: %s (offset %zu)"),
621 psz, off - 1);
622
623 /* Pick up after '*' in the two cases above: ch is not ':' or '\0'. */
624 Assert(ch != ':' && ch != '\0');
625 if (RT_C_IS_XDIGIT(ch) || ch == '?')
626 {
627 ch = psz[off++];
628 if (RT_C_IS_XDIGIT(ch) || ch == '?' || ch == '*')
629 {
630 off -= 2;
631 continue;
632 }
633 if (ch == ':')
634 {
635 ch = psz[off++];
636 if (ch == '\0')
637 return S_OK;
638 cPairsLeft -= 1;
639 if (cPairsLeft == 0)
640 return pErrorDst->setError(E_INVALIDARG,
641 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
642 psz, off - 1);
643 continue;
644 }
645 if (ch == '\0')
646 return S_OK;
647 return pErrorDst->setError(E_INVALIDARG,
648 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
649 psz, off - 1);
650 }
651 return pErrorDst->setError(E_INVALIDARG,
652 pErrorDst->tr("Malformed MAC wildcard address: %s (offset %zu)"),
653 psz, off - 1);
654 }
655 break;
656 }
657
658 case DHCPGroupConditionType_vendorClassID:
659 case DHCPGroupConditionType_vendorClassIDWildcard:
660 case DHCPGroupConditionType_userClassID:
661 case DHCPGroupConditionType_userClassIDWildcard:
662 if (strValue.length() == 0)
663 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Value cannot be empty"));
664 if (strValue.length() < 255)
665 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Value is too long: %zu bytes"), strValue.length());
666 break;
667
668 default:
669 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Invalid condition type: %d"), enmType);
670 }
671
672 return S_OK;
673}
674
675
676HRESULT DHCPGroupCondition::getInclusive(BOOL *aInclusive)
677{
678 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
679 *aInclusive = m_fInclusive;
680 return S_OK;
681}
682
683
684HRESULT DHCPGroupCondition::setInclusive(BOOL aInclusive)
685{
686 {
687 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
688 if ((aInclusive != FALSE) == m_fInclusive)
689 return S_OK;
690 m_fInclusive = aInclusive != FALSE;
691 }
692 return m_pParent->i_doWriteConfig();
693}
694
695
696HRESULT DHCPGroupCondition::getType(DHCPGroupConditionType_T *aType)
697{
698 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
699 *aType = m_enmType;
700 return S_OK;
701}
702
703
704HRESULT DHCPGroupCondition::setType(DHCPGroupConditionType_T aType)
705{
706 {
707 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
708 if (aType == m_enmType)
709 return S_OK;
710 HRESULT hrc = i_validateTypeAndValue(aType, m_strValue, this);
711 if (FAILED(hrc))
712 return hrc;
713 m_enmType = aType;
714 }
715 return m_pParent->i_doWriteConfig();
716}
717
718
719HRESULT DHCPGroupCondition::getValue(com::Utf8Str &aValue)
720{
721 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
722 return aValue.assignEx(m_strValue);
723}
724
725
726HRESULT DHCPGroupCondition::setValue(const com::Utf8Str &aValue)
727{
728 {
729 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
730 if (aValue == m_strValue)
731 return S_OK;
732 HRESULT hrc = i_validateTypeAndValue(m_enmType, aValue, this);
733 if (FAILED(hrc))
734 return hrc;
735 hrc = m_strValue.assignEx(aValue);
736 if (FAILED(hrc))
737 return hrc;
738 }
739 return m_pParent->i_doWriteConfig();
740}
741
742
743HRESULT DHCPGroupCondition::remove()
744{
745 return m_pParent->i_removeCondition(this);
746}
747
748
749
750/*********************************************************************************************************************************
751* DHCPGroupConfig Implementation *
752*********************************************************************************************************************************/
753#undef LOG_GROUP
754#define LOG_GROUP LOG_GROUP_MAIN_DHCPGROUPCONFIG
755
756
757HRESULT DHCPGroupConfig::initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const com::Utf8Str &a_rName)
758{
759 AutoInitSpan autoInitSpan(this);
760 AssertReturn(autoInitSpan.isOk(), E_FAIL);
761
762 Assert(m_Conditions.size() == 0);
763 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
764 if (SUCCEEDED(hrc))
765 hrc = m_strName.assignEx(a_rName);
766
767 if (SUCCEEDED(hrc))
768 autoInitSpan.setSucceeded();
769 else
770 autoInitSpan.setFailed(hrc);
771 return hrc;
772}
773
774
775HRESULT DHCPGroupConfig::initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPGroupConfig &a_rSrc)
776{
777 AutoInitSpan autoInitSpan(this);
778 AssertReturn(autoInitSpan.isOk(), E_FAIL);
779
780 Assert(m_Conditions.size() == 0);
781 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, a_rSrc);
782 if (SUCCEEDED(hrc))
783 hrc = m_strName.assignEx(a_rSrc.strName);
784
785 for (settings::DHCPGroupConditionVec::const_iterator it = a_rSrc.vecConditions.begin();
786 it != a_rSrc.vecConditions.end() && SUCCEEDED(hrc); ++it)
787 {
788 ComObjPtr<DHCPGroupCondition> ptrCondition;
789 hrc = ptrCondition.createObject();
790 if (SUCCEEDED(hrc))
791 {
792 hrc = ptrCondition->initWithSettings(this, *it);
793 if (SUCCEEDED(hrc))
794 {
795 try
796 {
797 m_Conditions.push_back(ptrCondition);
798 }
799 catch (std::bad_alloc &)
800 {
801 hrc = E_OUTOFMEMORY;
802 }
803 }
804 }
805 }
806
807 if (SUCCEEDED(hrc))
808 autoInitSpan.setSucceeded();
809 else
810 autoInitSpan.setFailed(hrc);
811 return hrc;
812}
813
814
815void DHCPGroupConfig::uninit()
816{
817 AutoUninitSpan autoUninitSpan(this);
818 if (!autoUninitSpan.uninitDone())
819 autoUninitSpan.setSucceeded();
820}
821
822
823HRESULT DHCPGroupConfig::i_saveSettings(settings::DHCPGroupConfig &a_rDst)
824{
825 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
826
827 HRESULT hrc = DHCPConfig::i_saveSettings(a_rDst);
828 if (SUCCEEDED(hrc))
829 hrc = a_rDst.strName.assignEx(m_strName);
830 if (SUCCEEDED(hrc))
831 {
832 size_t const cConditions = m_Conditions.size();
833 try
834 {
835 a_rDst.vecConditions.resize(cConditions);
836 }
837 catch (std::bad_alloc &)
838 {
839 hrc = E_OUTOFMEMORY;
840 }
841
842 for (size_t i = 0; i < cConditions && SUCCEEDED(hrc); i++)
843 hrc = m_Conditions[i]->i_saveSettings(a_rDst.vecConditions[i]);
844 }
845 return hrc;
846}
847
848
849HRESULT DHCPGroupConfig::i_removeCondition(DHCPGroupCondition *a_pCondition)
850{
851 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
852
853 for (ConditionsIterator it = m_Conditions.begin(); it != m_Conditions.end();)
854 {
855 DHCPGroupCondition *pCurCondition = *it;
856 if (pCurCondition == a_pCondition)
857 it = m_Conditions.erase(it);
858 else
859 ++it;
860 }
861
862 /* Never mind if already delete, right? */
863 return S_OK;
864}
865
866
867/**
868 * Overridden to add a 'name' attribute and emit condition child elements.
869 */
870void DHCPGroupConfig::i_writeDhcpdConfig(xml::ElementNode *a_pElmGroup)
871{
872 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
873
874 /* The name attribute: */
875 a_pElmGroup->setAttribute("name", m_strName);
876
877 /*
878 * Conditions:
879 */
880 for (ConditionsIterator it = m_Conditions.begin(); it != m_Conditions.end(); ++it)
881 {
882 xml::ElementNode *pElmCondition;
883 switch ((*it)->i_getType())
884 {
885 case DHCPGroupConditionType_MAC:
886 pElmCondition = a_pElmGroup->createChild("ConditionMAC");
887 break;
888 case DHCPGroupConditionType_MACWildcard:
889 pElmCondition = a_pElmGroup->createChild("ConditionMACWildcard");
890 break;
891 case DHCPGroupConditionType_vendorClassID:
892 pElmCondition = a_pElmGroup->createChild("ConditionVendorClassID");
893 break;
894 case DHCPGroupConditionType_vendorClassIDWildcard:
895 pElmCondition = a_pElmGroup->createChild("ConditionVendorClassIDWildcard");
896 break;
897 case DHCPGroupConditionType_userClassID:
898 pElmCondition = a_pElmGroup->createChild("ConditionUserClassID");
899 break;
900 case DHCPGroupConditionType_userClassIDWildcard:
901 pElmCondition = a_pElmGroup->createChild("ConditionUserClassIDWildcard");
902 break;
903 default:
904 AssertLogRelMsgFailed(("m_enmType=%d\n", (*it)->i_getType()));
905 continue;
906 }
907 pElmCondition->setAttribute("inclusive", (*it)->i_getInclusive());
908 pElmCondition->setAttribute("value", (*it)->i_getValue());
909 }
910
911 DHCPConfig::i_writeDhcpdConfig(a_pElmGroup);
912}
913
914
915HRESULT DHCPGroupConfig::getName(com::Utf8Str &aName)
916{
917 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
918 return aName.assignEx(m_strName);
919}
920
921
922HRESULT DHCPGroupConfig::setName(const com::Utf8Str &aName)
923{
924 {
925 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
926 if (aName == m_strName)
927 return S_OK;
928 HRESULT hrc = m_strName.assignEx(aName);
929 if (FAILED(hrc))
930 return hrc;
931 }
932 return i_doWriteConfig();
933}
934
935
936HRESULT DHCPGroupConfig::getConditions(std::vector<ComPtr<IDHCPGroupCondition> > &aConditions)
937{
938 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
939 size_t const cConditions = m_Conditions.size();
940 try
941 {
942 aConditions.resize(cConditions);
943 }
944 catch (std::bad_alloc &)
945 {
946 return E_OUTOFMEMORY;
947 }
948 HRESULT hrc = S_OK;
949 for (size_t i = 0; i < cConditions && SUCCEEDED(hrc); i++)
950 hrc = m_Conditions[i].queryInterfaceTo(aConditions[i].asOutParam());
951 return hrc;
952}
953
954
955HRESULT DHCPGroupConfig::addCondition(BOOL aInclusive, DHCPGroupConditionType_T aType, const com::Utf8Str &aValue,
956 ComPtr<IDHCPGroupCondition> &aCondition)
957{
958 /*
959 * Valdiate it.
960 */
961 HRESULT hrc = DHCPGroupCondition::i_validateTypeAndValue(aType, aValue, this);
962 if (SUCCEEDED(hrc))
963 {
964 /*
965 * Add it.
966 */
967 ComObjPtr<DHCPGroupCondition> ptrCondition;
968 hrc = ptrCondition.createObject();
969 if (SUCCEEDED(hrc))
970 hrc = ptrCondition->initWithDefaults(this, aInclusive != FALSE, aType, aValue);
971 if (SUCCEEDED(hrc))
972 {
973 hrc = ptrCondition.queryInterfaceTo(aCondition.asOutParam());
974 if (SUCCEEDED(hrc))
975 {
976 {
977 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
978 try
979 {
980 m_Conditions.push_back(ptrCondition);
981 }
982 catch (std::bad_alloc &)
983 {
984 aCondition.setNull();
985 return E_OUTOFMEMORY;
986 }
987 }
988
989 hrc = i_doWriteConfig();
990 if (FAILED(hrc))
991 aCondition.setNull();
992 }
993 }
994 }
995
996 return hrc;
997}
998
999
1000HRESULT DHCPGroupConfig::removeAllConditions()
1001{
1002 {
1003 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1004 if (m_Conditions.size() == 0)
1005 return S_OK;
1006
1007 /** @todo sever the weak parent link for each entry... */
1008 m_Conditions.erase(m_Conditions.begin(), m_Conditions.end());
1009 }
1010
1011 return i_doWriteConfig();
1012}
1013
1014
1015
1016/*********************************************************************************************************************************
1017* DHCPIndividualConfig Implementation *
1018*********************************************************************************************************************************/
1019#undef LOG_GROUP
1020#define LOG_GROUP LOG_GROUP_MAIN_DHCPINDIVIDUALCONFIG
1021
1022HRESULT DHCPIndividualConfig::initWithMachineIdAndSlot(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1023 com::Guid const &a_idMachine, ULONG a_uSlot, uint32_t a_uMACAddressVersion)
1024{
1025 AutoInitSpan autoInitSpan(this);
1026 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1027
1028 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
1029 if (SUCCEEDED(hrc))
1030 {
1031 unconst(m_enmScope) = DHCPConfigScope_MachineNIC;
1032 unconst(m_idMachine) = a_idMachine;
1033 unconst(m_uSlot) = a_uSlot;
1034 m_uMACAddressResolvedVersion = a_uMACAddressVersion;
1035
1036 autoInitSpan.setSucceeded();
1037 }
1038 return hrc;
1039}
1040
1041
1042HRESULT DHCPIndividualConfig::initWithMACAddress(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, PCRTMAC a_pMACAddress)
1043{
1044 AutoInitSpan autoInitSpan(this);
1045 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1046
1047 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
1048 if (SUCCEEDED(hrc))
1049 {
1050 unconst(m_enmScope) = DHCPConfigScope_MAC;
1051 unconst(m_MACAddress) = *a_pMACAddress;
1052
1053 autoInitSpan.setSucceeded();
1054 }
1055 return hrc;
1056}
1057
1058
1059HRESULT DHCPIndividualConfig::initWithSettingsAndMachineIdAndSlot(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1060 settings::DHCPIndividualConfig const &rConfig,
1061 com::Guid const &a_idMachine, ULONG a_uSlot,
1062 uint32_t a_uMACAddressVersion)
1063{
1064 AutoInitSpan autoInitSpan(this);
1065 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1066
1067 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
1068 if (SUCCEEDED(hrc))
1069 {
1070 unconst(m_enmScope) = DHCPConfigScope_MachineNIC;
1071 unconst(m_idMachine) = a_idMachine;
1072 unconst(m_uSlot) = a_uSlot;
1073 m_uMACAddressResolvedVersion = a_uMACAddressVersion;
1074 m_strFixedAddress = rConfig.strFixedAddress;
1075
1076 autoInitSpan.setSucceeded();
1077 }
1078 return hrc;
1079}
1080
1081
1082HRESULT DHCPIndividualConfig::initWithSettingsAndMACAddress(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1083 settings::DHCPIndividualConfig const &rConfig, PCRTMAC a_pMACAddress)
1084{
1085 AutoInitSpan autoInitSpan(this);
1086 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1087
1088 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
1089 if (SUCCEEDED(hrc))
1090 {
1091 unconst(m_enmScope) = DHCPConfigScope_MAC;
1092 unconst(m_MACAddress) = *a_pMACAddress;
1093 m_strFixedAddress = rConfig.strFixedAddress;
1094
1095 autoInitSpan.setSucceeded();
1096 }
1097 return hrc;
1098}
1099
1100
1101void DHCPIndividualConfig::uninit()
1102{
1103 AutoUninitSpan autoUninitSpan(this);
1104 if (!autoUninitSpan.uninitDone())
1105 autoUninitSpan.setSucceeded();
1106}
1107
1108
1109HRESULT DHCPIndividualConfig::i_saveSettings(settings::DHCPIndividualConfig &a_rDst)
1110{
1111 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1112
1113 a_rDst.uSlot = m_uSlot;
1114 int vrc = a_rDst.strMACAddress.printfNoThrow("%RTmac", &m_MACAddress);
1115 if (m_idMachine.isValid() && !m_idMachine.isZero() && RT_SUCCESS(vrc))
1116 vrc = a_rDst.strVMName.printfNoThrow("%RTuuid", m_idMachine.raw());
1117 if (RT_SUCCESS(vrc))
1118 vrc = a_rDst.strFixedAddress.assignNoThrow(m_strFixedAddress);
1119 if (RT_SUCCESS(vrc))
1120 return DHCPConfig::i_saveSettings(a_rDst);
1121 return E_OUTOFMEMORY;;
1122}
1123
1124
1125HRESULT DHCPIndividualConfig::getMACAddress(com::Utf8Str &aMACAddress)
1126{
1127 /* No locking needed here (the MAC address, machine UUID and NIC slot number cannot change). */
1128 RTMAC MACAddress;
1129 if (m_enmScope == DHCPConfigScope_MAC)
1130 MACAddress = m_MACAddress;
1131 else
1132 {
1133 HRESULT hrc = i_getMachineMAC(&MACAddress);
1134 if (FAILED(hrc))
1135 return hrc;
1136 }
1137
1138 /* Format the return string: */
1139 int vrc = aMACAddress.printfNoThrow("%RTmac", &MACAddress);
1140 return RT_SUCCESS(vrc) ? S_OK : E_OUTOFMEMORY;
1141}
1142
1143
1144HRESULT DHCPIndividualConfig::getMachineId(com::Guid &aId)
1145{
1146 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1147 aId = m_idMachine;
1148 return S_OK;
1149}
1150
1151
1152HRESULT DHCPIndividualConfig::getSlot(ULONG *aSlot)
1153{
1154 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1155 *aSlot = m_uSlot;
1156 return S_OK;
1157}
1158
1159HRESULT DHCPIndividualConfig::getFixedAddress(com::Utf8Str &aFixedAddress)
1160{
1161 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1162 return aFixedAddress.assignEx(m_strFixedAddress);
1163}
1164
1165
1166HRESULT DHCPIndividualConfig::setFixedAddress(const com::Utf8Str &aFixedAddress)
1167{
1168 if (aFixedAddress.isNotEmpty())
1169 {
1170 RTNETADDRIPV4 AddrIgnored;
1171 int vrc = RTNetStrToIPv4Addr(aFixedAddress.c_str(), &AddrIgnored);
1172 if (RT_FAILURE(vrc))
1173 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid IPv4 address '%s': %Rrc"), aFixedAddress.c_str(), vrc);
1174 }
1175
1176 {
1177 AutoWriteLock(this COMMA_LOCKVAL_SRC_POS);
1178 m_strFixedAddress = aFixedAddress;
1179 }
1180 return i_doWriteConfig();
1181}
1182
1183
1184/**
1185 * Gets the MAC address of m_idMachine + m_uSlot.
1186 *
1187 * @returns COM status code w/ setError.
1188 * @param pMACAddress Where to return the address.
1189 *
1190 * @note Must be called without holding any DHCP related locks as that would
1191 * be lock order violation. The m_idMachine and m_uSlot values are
1192 * practically const, so we don't need any locks here anyway.
1193 */
1194HRESULT DHCPIndividualConfig::i_getMachineMAC(PRTMAC pMACAddress)
1195{
1196 ComObjPtr<Machine> ptrMachine;
1197 HRESULT hrc = m_pVirtualBox->i_findMachine(m_idMachine, false /*fPermitInaccessible*/, true /*aSetError*/, &ptrMachine);
1198 if (SUCCEEDED(hrc))
1199 {
1200 ComPtr<INetworkAdapter> ptrNetworkAdapter;
1201 hrc = ptrMachine->GetNetworkAdapter(m_uSlot, ptrNetworkAdapter.asOutParam());
1202 if (SUCCEEDED(hrc))
1203 {
1204 com::Bstr bstrMACAddress;
1205 hrc = ptrNetworkAdapter->COMGETTER(MACAddress)(bstrMACAddress.asOutParam());
1206 if (SUCCEEDED(hrc))
1207 {
1208 Utf8Str strMACAddress;
1209 try
1210 {
1211 strMACAddress = bstrMACAddress;
1212 }
1213 catch (std::bad_alloc &)
1214 {
1215 return E_OUTOFMEMORY;
1216 }
1217
1218 int vrc = RTNetStrToMacAddr(strMACAddress.c_str(), pMACAddress);
1219 if (RT_SUCCESS(vrc))
1220 hrc = S_OK;
1221 else
1222 hrc = setErrorBoth(E_FAIL, vrc, tr("INetworkAdapter returned bogus MAC address '%ls': %Rrc"),
1223 bstrMACAddress.raw(), vrc);
1224 }
1225 }
1226 }
1227 return hrc;
1228}
1229
1230
1231HRESULT DHCPIndividualConfig::i_resolveMACAddress(uint32_t uVersion)
1232{
1233 HRESULT hrc;
1234 if (m_enmScope == DHCPConfigScope_MachineNIC)
1235 {
1236 RTMAC MACAddress;
1237 hrc = i_getMachineMAC(&MACAddress);
1238 if (SUCCEEDED(hrc))
1239 {
1240 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1241 if ((int32_t)(m_uMACAddressResolvedVersion - uVersion) >= 0)
1242 {
1243 m_uMACAddressResolvedVersion = uVersion;
1244 m_MACAddress = MACAddress;
1245 }
1246 }
1247 }
1248 else
1249 hrc = S_OK;
1250 return hrc;
1251}
1252
1253
1254/**
1255 * Overridden to write out additional config.
1256 */
1257void DHCPIndividualConfig::i_writeDhcpdConfig(xml::ElementNode *pElmConfig)
1258{
1259 char szTmp[RTUUID_STR_LENGTH + 32];
1260 RTStrPrintf(szTmp, sizeof(szTmp), "%RTmac", &m_MACAddress);
1261 pElmConfig->setAttribute("MACAddress", szTmp);
1262
1263 if (m_enmScope == DHCPConfigScope_MachineNIC)
1264 {
1265 RTStrPrintf(szTmp, sizeof(szTmp), "%RTuuid/%u", m_idMachine.raw(), m_uSlot);
1266 pElmConfig->setAttribute("name", szTmp);
1267 }
1268
1269 pElmConfig->setAttribute("fixedAddress", m_strFixedAddress);
1270
1271 DHCPConfig::i_writeDhcpdConfig(pElmConfig);
1272}
1273
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