Changeset 79553 in vbox for trunk/src/VBox/NetworkServices/Dhcpd
- Timestamp:
- Jul 5, 2019 10:59:01 AM (6 years ago)
- Location:
- trunk/src/VBox/NetworkServices/Dhcpd
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/NetworkServices/Dhcpd/Config.cpp
r79524 r79553 16 16 */ 17 17 18 19 /********************************************************************************************************************************* 20 * Header Files * 21 *********************************************************************************************************************************/ 18 22 #include "DhcpdInternal.h" 19 #include "Config.h"20 23 21 24 #include <iprt/ctype.h> … … 27 30 #include <iprt/uuid.h> 28 31 29 #include <VBox/com/com.h> 30 31 #include <iostream> 32 32 #include <VBox/com/com.h> /* For log initialization. */ 33 34 #include "Config.h" 35 36 37 /** 38 * Configuration file exception. 39 */ 33 40 class ConfigFileError 34 : public RTCError41 : public RTCError 35 42 { 36 43 public: 37 ConfigFileError(const char *pszMessage) 38 : RTCError(pszMessage) {} 44 #if 0 /* This just confuses the compiler. */ 45 ConfigFileError(const char *a_pszMessage) 46 : RTCError(a_pszMessage) 47 {} 48 #endif 49 50 ConfigFileError(const char *a_pszMsgFmt, ...) 51 : RTCError((char *)NULL) 52 { 53 va_list va; 54 va_start(va, a_pszMsgFmt); 55 m_strMsg.printfV(a_pszMsgFmt, va); 56 va_end(va); 57 } 39 58 40 59 ConfigFileError(const RTCString &a_rstrMessage) 41 : RTCError(a_rstrMessage) {} 60 : RTCError(a_rstrMessage) 61 {} 42 62 }; 43 63 44 64 65 /** 66 * Private default constructor, external users use factor methods. 67 */ 45 68 Config::Config() 46 : m_strHome(), 47 m_strNetwork(), 48 m_strBaseName(), 49 m_strTrunk(), 50 m_enmTrunkType(kIntNetTrunkType_Invalid), 51 m_MacAddress(), 52 m_IPv4Address(), 53 m_IPv4Netmask(), 54 m_IPv4PoolFirst(), 55 m_IPv4PoolLast(), 56 m_GlobalOptions(), 57 m_VMMap() 58 { 59 return; 60 } 61 62 63 int Config::init() 64 { 65 int rc; 66 67 rc = homeInit(); 68 if (RT_FAILURE(rc)) 69 return rc; 70 71 return VINF_SUCCESS; 72 } 73 74 75 int Config::homeInit() 76 { 77 /* pathname of ~/.VirtualBox or equivalent */ 69 : m_strHome() 70 , m_strNetwork() 71 , m_strBaseName() 72 , m_strTrunk() 73 , m_enmTrunkType(kIntNetTrunkType_Invalid) 74 , m_MacAddress() 75 , m_IPv4Address() 76 , m_IPv4Netmask() 77 , m_IPv4PoolFirst() 78 , m_IPv4PoolLast() 79 , m_GlobalOptions() 80 , m_VMMap() 81 { 82 } 83 84 85 /** 86 * Initializes the object. 87 * 88 * @returns IPRT status code. 89 */ 90 int Config::i_init() 91 { 92 return i_homeInit(); 93 } 94 95 96 /** 97 * Initializes the m_strHome member with the path to ~/.VirtualBox or equivalent. 98 * 99 * @returns IPRT status code. 100 * @todo Too many init functions? 101 */ 102 int Config::i_homeInit() 103 { 78 104 char szHome[RTPATH_MAX]; 79 105 int rc = com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome), false); 80 if (RT_FAILURE(rc)) 81 { 82 LogDHCP(("unable to find VirtualBox home directory: %Rrs", rc)); 83 return rc; 84 } 85 86 m_strHome.assign(szHome); 87 return VINF_SUCCESS; 88 } 89 90 91 void Config::setNetwork(const RTCString &aStrNetwork) 106 if (RT_SUCCESS(rc)) 107 rc = m_strHome.assignNoThrow(szHome); 108 else 109 { 110 LogFunc(("unable to locate the VirtualBox home directory: %Rrc", rc)); /* no release log at this point. */ 111 RTMsgError("unable to locate the VirtualBox home directory: %Rrs", rc); 112 } 113 return rc; 114 } 115 116 117 /** 118 * Internal worker for the public factory methods that creates an instance and 119 * calls i_init() on it. 120 * 121 * @returns Config instance on success, NULL on failure. 122 */ 123 /*static*/ Config *Config::i_createInstanceAndCallInit() 124 { 125 Config *pConfig; 126 try 127 { 128 pConfig = new Config(); 129 } 130 catch (std::bad_alloc &) 131 { 132 return NULL; 133 } 134 135 int rc = pConfig->i_init(); 136 if (RT_SUCCESS(rc)) 137 return pConfig; 138 delete pConfig; 139 return NULL; 140 } 141 142 143 /** 144 * Internal network name (m_strNetwork) setter. 145 * 146 * Can only be called once. Will also invoke i_sanitizeBaseName to update 147 * m_strBaseName. 148 * 149 * @throws std::bad_alloc 150 */ 151 void Config::i_setNetwork(const RTCString &aStrNetwork) 92 152 { 93 153 AssertReturnVoid(m_strNetwork.isEmpty()); 94 154 95 155 m_strNetwork = aStrNetwork; 96 sanitizeBaseName(); 97 } 98 99 100 /* 156 i_sanitizeBaseName(); 157 } 158 159 160 /** 161 * Interal worker for i_setNetwork() that sets m_strBaseName to sanitized the 162 * version of m_strNetwork suitable for use as a path component. 163 */ 164 void Config::i_sanitizeBaseName() 165 { 166 if (m_strNetwork.isNotEmpty()) 167 { 168 m_strBaseName = m_strNetwork; 169 170 /** @todo make IPRT function for this. */ 171 char ch; 172 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 173 static const char s_szIllegals[] = "/\\\"*:<>?|\t\v\n\r\f\a\b"; /** @todo all control chars... */ 174 for (char *psz = m_strBaseName.mutableRaw(); (ch = *psz) != '\0'; ++psz) 175 if (strchr(s_szIllegals, ch)) 176 *psz = '_'; 177 #else 178 for (char *psz = m_strBaseName.mutableRaw(); (ch = *psz) != '\0'; ++psz) 179 if (RTPATH_IS_SEP(ch)) 180 *psz = '_'; 181 #endif 182 m_strBaseName.jolt(); /* Not really necessary, but it's protocol. */ 183 } 184 else 185 m_strBaseName.setNull(); 186 } 187 188 189 /** 190 * Worker for i_complete() that initializes the release log of the process. 191 * 101 192 * Requires network name to be known as the log file name depends on 102 193 * it. Alternatively, consider passing the log file name via the 103 194 * command line? 104 */ 105 int Config::logInit() 195 * 196 * @todo make the log file directly configurable? 197 */ 198 int Config::i_logInit() 106 199 { 107 200 if (m_strHome.isEmpty() || m_strBaseName.isEmpty()) … … 124 217 if (*p != '_' && !RT_C_IS_ALNUM(*p)) 125 218 *p = '_'; 126 127 219 128 220 int rc = com::VBoxLogRelCreate("DHCP Server", … … 146 238 147 239 148 int Config::complete() 149 { 150 int rc; 151 240 /** 241 * Post process and validate the configuration after it has been loaded. 242 */ 243 int Config::i_complete() 244 { 152 245 if (m_strNetwork.isEmpty()) 153 246 { … … 156 249 } 157 250 158 logInit();251 i_logInit(); 159 252 160 253 bool fMACGenerated = false; … … 164 257 { 165 258 RTUUID Uuid; 166 RTUuidCreate(&Uuid); 259 int rc = RTUuidCreate(&Uuid); 260 AssertReturn(rc, rc); 167 261 168 262 m_MacAddress.au8[0] = 0x08; … … 193 287 /* valid netmask */ 194 288 int cPrefixBits; 195 rc = RTNetMaskToPrefixIPv4(&m_IPv4Netmask, &cPrefixBits);289 int rc = RTNetMaskToPrefixIPv4(&m_IPv4Netmask, &cPrefixBits); 196 290 if (RT_FAILURE(rc) || cPrefixBits == 0) 197 291 { … … 226 320 /* our own address is not inside the pool */ 227 321 if ( RT_N2H_U32(m_IPv4PoolFirst.u) <= RT_N2H_U32(m_IPv4Address.u) 228 && RT_N2H_U32(m_IPv4Address.u) <= RT_N2H_U32(m_IPv4PoolLast.u))322 && RT_N2H_U32(m_IPv4Address.u) <= RT_N2H_U32(m_IPv4PoolLast.u)) 229 323 { 230 324 LogDHCP(("server address inside the pool range %RTnaipv4 - %RTnaipv4: %RTnaipv4\n", … … 242 336 243 337 244 Config *Config::hardcoded() 245 { 246 int rc; 247 248 std::unique_ptr<Config> config(new Config()); 249 rc = config->init(); 250 if (RT_FAILURE(rc)) 338 /*static*/ Config *Config::hardcoded() 339 { 340 std::unique_ptr<Config> config(i_createInstanceAndCallInit()); 341 AssertReturn(config.get() != NULL, NULL); 342 try 343 { 344 config->i_setNetwork("HostInterfaceNetworking-vboxnet0"); 345 config->m_strTrunk.assign("vboxnet0"); 346 } 347 catch (std::bad_alloc &) 348 { 251 349 return NULL; 252 253 config->setNetwork("HostInterfaceNetworking-vboxnet0"); 254 config->m_strTrunk.assign("vboxnet0"); 350 } 255 351 config->m_enmTrunkType = kIntNetTrunkType_NetFlt; 256 352 … … 263 359 264 360 265 config->m_IPv4Address.u = RT_H2N_U32_C(0xc0a838fe); /* 192.168.56.254 */266 config->m_IPv4Netmask.u = RT_H2N_U32_C(0xffffff00); /* 255.255.255.0 */361 config->m_IPv4Address.u = RT_H2N_U32_C(0xc0a838fe); /* 192.168.56.254 */ 362 config->m_IPv4Netmask.u = RT_H2N_U32_C(0xffffff00); /* 255.255.255.0 */ 267 363 268 364 /* flip to test naks */ 269 365 #if 1 270 config->m_IPv4PoolFirst.u = RT_H2N_U32_C(0xc0a8385a); /* 192.168.56.90 */271 config->m_IPv4PoolLast.u = RT_H2N_U32_C(0xc0a83863); /* 192.168.56.99 */366 config->m_IPv4PoolFirst.u = RT_H2N_U32_C(0xc0a8385a); /* 192.168.56.90 */ 367 config->m_IPv4PoolLast.u = RT_H2N_U32_C(0xc0a83863); /* 192.168.56.99 */ 272 368 #else 273 config->m_IPv4PoolFirst.u = RT_H2N_U32_C(0xc0a838c9); /* 192.168.56.201 */274 config->m_IPv4PoolLast.u = RT_H2N_U32_C(0xc0a838dc); /* 192.168.56.220 */369 config->m_IPv4PoolFirst.u = RT_H2N_U32_C(0xc0a838c9); /* 192.168.56.201 */ 370 config->m_IPv4PoolLast.u = RT_H2N_U32_C(0xc0a838dc); /* 192.168.56.220 */ 275 371 #endif 276 372 277 rc = config->complete();373 int rc = config->i_complete(); 278 374 AssertRCReturn(rc, NULL); 279 375 … … 282 378 283 379 284 /* compatibility with old VBoxNetDHCP */ 285 static const RTGETOPTDEF g_aCompatOptions[] = 286 { 287 { "--ip-address", 'i', RTGETOPT_REQ_IPV4ADDR },288 { "--lower-ip", 'l', RTGETOPT_REQ_IPV4ADDR },289 { "--mac-address", 'a', RTGETOPT_REQ_MACADDR },290 { "--need-main", 'M', RTGETOPT_REQ_BOOL},291 { "--netmask", 'm', RTGETOPT_REQ_IPV4ADDR },292 { "--network", 'n', RTGETOPT_REQ_STRING},293 { "--trunk-name", 't', RTGETOPT_REQ_STRING},294 { "--trunk-type", 'T', RTGETOPT_REQ_STRING},295 { "--upper-ip", 'u', RTGETOPT_REQ_IPV4ADDR},296 }; 297 298 299 Config *Config::compat(int argc, char **argv) 300 { 380 381 /*static*/ Config *Config::compat(int argc, char **argv) 382 { 383 /* compatibility with old VBoxNetDHCP */ 384 static const RTGETOPTDEF s_aCompatOptions[] = 385 { 386 { "--ip-address", 'i', RTGETOPT_REQ_IPV4ADDR }, 387 { "--lower-ip", 'l', RTGETOPT_REQ_IPV4ADDR }, 388 { "--mac-address", 'a', RTGETOPT_REQ_MACADDR }, 389 { "--need-main", 'M', RTGETOPT_REQ_BOOL }, 390 { "--netmask", 'm', RTGETOPT_REQ_IPV4ADDR }, 391 { "--network", 'n', RTGETOPT_REQ_STRING }, 392 { "--trunk-name", 't', RTGETOPT_REQ_STRING }, 393 { "--trunk-type", 'T', RTGETOPT_REQ_STRING }, 394 { "--upper-ip", 'u', RTGETOPT_REQ_IPV4ADDR }, 395 }; 396 301 397 RTGETOPTSTATE State; 302 int rc; 303 304 rc = RTGetOptInit(&State, argc, argv, 305 g_aCompatOptions, RT_ELEMENTS(g_aCompatOptions), 1, 306 RTGETOPTINIT_FLAGS_NO_STD_OPTS); 398 int rc = RTGetOptInit(&State, argc, argv, s_aCompatOptions, RT_ELEMENTS(s_aCompatOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); 307 399 AssertRCReturn(rc, NULL); 308 400 309 std::unique_ptr<Config> config(new Config()); 310 rc = config->init(); 311 if (RT_FAILURE(rc)) 312 return NULL; 401 std::unique_ptr<Config> config(i_createInstanceAndCallInit()); 402 AssertReturn(config.get() != NULL, NULL); 313 403 314 404 for (;;) 315 405 { 316 RTGETOPTUNION Val; 317 318 rc = RTGetOpt(&State, &Val); 406 RTGETOPTUNION ValueUnion; 407 rc = RTGetOpt(&State, &ValueUnion); 319 408 if (rc == 0) /* done */ 320 409 break; … … 330 419 return NULL; 331 420 } 332 config->m_MacAddress = Val .MacAddr;421 config->m_MacAddress = ValueUnion.MacAddr; 333 422 break; 334 423 … … 339 428 return NULL; 340 429 } 341 config->m_IPv4Address = Val .IPv4Addr;430 config->m_IPv4Address = ValueUnion.IPv4Addr; 342 431 break; 343 432 … … 348 437 return NULL; 349 438 } 350 config->m_IPv4PoolFirst = Val .IPv4Addr;439 config->m_IPv4PoolFirst = ValueUnion.IPv4Addr; 351 440 break; 352 441 … … 361 450 return NULL; 362 451 } 363 config->m_IPv4Netmask = Val .IPv4Addr;452 config->m_IPv4Netmask = ValueUnion.IPv4Addr; 364 453 break; 365 454 … … 370 459 return NULL; 371 460 } 372 config-> setNetwork(Val.psz);461 config->i_setNetwork(ValueUnion.psz); 373 462 break; 374 463 … … 379 468 return NULL; 380 469 } 381 config->m_strTrunk.assign(Val .psz);470 config->m_strTrunk.assign(ValueUnion.psz); 382 471 break; 383 472 … … 388 477 return NULL; 389 478 } 390 else if (strcmp(Val .psz, "none") == 0)479 else if (strcmp(ValueUnion.psz, "none") == 0) 391 480 config->m_enmTrunkType = kIntNetTrunkType_None; 392 else if (strcmp(Val .psz, "whatever") == 0)481 else if (strcmp(ValueUnion.psz, "whatever") == 0) 393 482 config->m_enmTrunkType = kIntNetTrunkType_WhateverNone; 394 else if (strcmp(Val .psz, "netflt") == 0)483 else if (strcmp(ValueUnion.psz, "netflt") == 0) 395 484 config->m_enmTrunkType = kIntNetTrunkType_NetFlt; 396 else if (strcmp(Val .psz, "netadp") == 0)485 else if (strcmp(ValueUnion.psz, "netadp") == 0) 397 486 config->m_enmTrunkType = kIntNetTrunkType_NetAdp; 398 487 else 399 488 { 400 RTMsgError("Unknown trunk type '%s'", Val .psz);489 RTMsgError("Unknown trunk type '%s'", ValueUnion.psz); 401 490 return NULL; 402 491 } … … 409 498 return NULL; 410 499 } 411 config->m_IPv4PoolLast = Val .IPv4Addr;500 config->m_IPv4PoolLast = ValueUnion.IPv4Addr; 412 501 break; 413 502 414 503 case VINF_GETOPT_NOT_OPTION: 415 RTMsgError("%s: Unexpected command line argument", Val .psz);504 RTMsgError("%s: Unexpected command line argument", ValueUnion.psz); 416 505 return NULL; 417 506 418 507 default: 419 RTGetOptPrintError(rc, &Val );508 RTGetOptPrintError(rc, &ValueUnion); 420 509 return NULL; 421 510 } 422 511 } 423 512 424 rc = config-> complete();513 rc = config->i_complete(); 425 514 if (RT_FAILURE(rc)) 426 515 return NULL; … … 430 519 431 520 521 Config *Config::create(int argc, char **argv) 522 { 432 523 #define DHCPD_GETOPT_COMMENT 256 /* No short option for --comment */ 433 static const RTGETOPTDEF g_aOptions[] = 434 { 435 { "--config", 'c', RTGETOPT_REQ_STRING }, 436 { "--comment", DHCPD_GETOPT_COMMENT, RTGETOPT_REQ_STRING } 437 }; 438 439 440 Config *Config::create(int argc, char **argv) 441 { 524 static const RTGETOPTDEF s_aOptions[] = 525 { 526 { "--config", 'c', RTGETOPT_REQ_STRING }, 527 { "--comment", DHCPD_GETOPT_COMMENT, RTGETOPT_REQ_STRING } 528 }; 529 442 530 RTGETOPTSTATE State; 443 int rc; 444 445 rc = RTGetOptInit(&State, argc, argv, 446 g_aOptions, RT_ELEMENTS(g_aOptions), 1, 447 RTGETOPTINIT_FLAGS_NO_STD_OPTS); 531 int rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); 448 532 AssertRCReturn(rc, NULL); 449 533 450 534 std::unique_ptr<Config> config; 535 451 536 for (;;) 452 537 { 453 RTGETOPTUNION Val; 454 455 rc = RTGetOpt(&State, &Val); 538 RTGETOPTUNION ValueUnion; 539 rc = RTGetOpt(&State, &ValueUnion); 456 540 if (rc == 0) /* done */ 457 541 break; … … 462 546 if (config.get() != NULL) 463 547 { 464 printf("Duplicate option: --config '%s'\n", Val.psz);548 RTMsgError("Duplicate option: --config '%s'\n", ValueUnion.psz); 465 549 return NULL; 466 550 } 467 551 468 printf("reading config from %s\n", Val.psz);469 config.reset(Config:: read(Val.psz));552 RTMsgInfo("reading config from '%s'...\n", ValueUnion.psz); 553 config.reset(Config::i_read(ValueUnion.psz)); 470 554 if (config.get() == NULL) 471 555 return NULL; 472 473 556 break; 474 557 … … 481 564 482 565 case VINF_GETOPT_NOT_OPTION: 483 RTMsgError("Unexpected command line argument: '%s'", Val .psz);566 RTMsgError("Unexpected command line argument: '%s'", ValueUnion.psz); 484 567 return NULL; 485 568 486 569 default: 487 RTGetOptPrintError(rc, &Val );570 RTGetOptPrintError(rc, &ValueUnion); 488 571 return NULL; 489 572 } 490 573 } 491 574 492 if (config.get() == NULL) 575 if (config.get() != NULL) 576 { 577 rc = config->i_complete(); 578 if (RT_SUCCESS(rc)) 579 return config.release(); 580 } 581 else 582 RTMsgError("No configuration file specified (--config file)!\n"); 583 return NULL; 584 } 585 586 587 /** 588 * 589 * @note The release log has is not operational when this method is called. 590 */ 591 Config *Config::i_read(const char *pszFileName) 592 { 593 if (pszFileName == NULL || pszFileName[0] == '\0') 594 { 595 RTMsgError("Empty configuration filename"); 493 596 return NULL; 494 495 rc = config->complete(); 496 if (RT_FAILURE(rc)) 497 return NULL; 498 499 return config.release(); 500 } 501 502 503 Config *Config::read(const char *pszFileName) 504 { 505 int rc; 506 507 if (pszFileName == NULL || pszFileName[0] == '\0') 508 return NULL; 597 } 509 598 510 599 xml::Document doc; … … 516 605 catch (const xml::EIPRTFailure &e) 517 606 { 518 LogDHCP(("%s\n", e.what())); 607 LogFunc(("%s\n", e.what())); 608 RTMsgError("%s\n", e.what()); 519 609 return NULL; 520 610 } 521 611 catch (const RTCError &e) 522 612 { 523 LogDHCP(("%s\n", e.what())); 613 LogFunc(("%s\n", e.what())); 614 RTMsgError("%s\n", e.what()); 524 615 return NULL; 525 616 } 526 617 catch (...) 527 618 { 528 Log DHCP(("Unknown exception while reading and parsing '%s'\n",529 pszFileName));619 LogFunc(("Unknown exception while reading and parsing '%s'\n", pszFileName)); 620 RTMsgError("Unknown exception while reading and parsing '%s'\n", pszFileName); 530 621 return NULL; 531 622 } 532 623 533 std::unique_ptr<Config> config(new Config()); 534 rc = config->init(); 535 if (RT_FAILURE(rc)) 624 std::unique_ptr<Config> config(i_createInstanceAndCallInit()); 625 AssertReturn(config.get() != NULL, NULL); 626 627 try 628 { 629 config->i_parseConfig(doc.getRootElement()); 630 } 631 catch (const RTCError &e) 632 { 633 LogFunc(("%s\n", e.what())); 634 RTMsgError("%s\n", e.what()); 536 635 return NULL; 537 538 try 539 { 540 config->parseConfig(doc.getRootElement()); 541 } 542 catch (const RTCError &e) 543 { 544 LogDHCP(("%s\n", e.what())); 636 } 637 catch (...) 638 { 639 LogFunc(("Unexpected exception\n")); 640 RTMsgError("Unexpected exception\n"); 545 641 return NULL; 546 642 } 547 catch (...)548 {549 LogDHCP(("Unexpected exception\n"));550 return NULL;551 }552 643 553 644 return config.release(); … … 555 646 556 647 557 void Config::parseConfig(const xml::ElementNode *root) 558 { 559 if (root == NULL) 648 /** 649 * Internal worker for i_read() that parses the root element and everything 650 * below it. 651 * 652 * @throws stuff. 653 */ 654 void Config::i_parseConfig(const xml::ElementNode *pElmRoot) 655 { 656 /* 657 * Check the root element and call i_parseServer to do real work. 658 */ 659 if (pElmRoot == NULL) 560 660 throw ConfigFileError("Empty config file"); 561 661 562 /* 563 * XXX: NAMESPACE API IS COMPLETELY BROKEN, SO IGNORE IT FOR NOW 564 */ 565 if (!root->nameEquals("DHCPServer")) 566 { 567 const char *name = root->getName(); 568 throw ConfigFileError(RTCStringFmt("Unexpected root element \"%s\"", 569 name ? name : "(null)")); 570 } 571 572 parseServer(root); 573 662 /** @todo XXX: NAMESPACE API IS COMPLETELY BROKEN, SO IGNORE IT FOR NOW */ 663 664 if (!pElmRoot->nameEquals("DHCPServer")) 665 throw ConfigFileError("Unexpected root element '%s'", pElmRoot->getName()); 666 667 i_parseServer(pElmRoot); 668 669 #if 0 /** @todo convert to LogRel2 stuff */ 574 670 // XXX: debug 575 671 for (optmap_t::const_iterator it = m_GlobalOptions.begin(); it != m_GlobalOptions.end(); ++it) { … … 590 686 std::cout << std::endl; 591 687 } 592 } 593 594 595 static void getIPv4AddrAttribute(const xml::ElementNode *pNode, const char *pcszAttrName, 596 RTNETADDRIPV4 *pAddr) 597 { 598 RTCString strAddr; 599 bool fHasAttr = pNode->getAttributeValue(pcszAttrName, &strAddr); 600 if (!fHasAttr) 601 throw ConfigFileError(RTCStringFmt("%s attribute missing", 602 pcszAttrName)); 603 604 int rc = RTNetStrToIPv4Addr(strAddr.c_str(), pAddr); 605 if (RT_FAILURE(rc)) 606 throw ConfigFileError(RTCStringFmt("%s attribute invalid", 607 pcszAttrName)); 608 } 609 610 611 void Config::parseServer(const xml::ElementNode *server) 688 #endif 689 } 690 691 692 /** 693 * Internal worker for parsing the elements under /DHCPServer/. 694 * 695 * @param pElmServer The DHCPServer element. 696 * @throws ConfigFileError 697 */ 698 void Config::i_parseServer(const xml::ElementNode *pElmServer) 612 699 { 613 700 /* 614 * DHCPServerattributes701 * <DHCPServer> attributes 615 702 */ 616 RTCString strNetworkName; 617 bool fHasNetworkName = server->getAttributeValue("networkName", &strNetworkName); 618 if (!fHasNetworkName) 703 const char *pszNetworkName; 704 if (pElmServer->getAttributeValue("networkName", &pszNetworkName)) 705 i_setNetwork(pszNetworkName); 706 else 619 707 throw ConfigFileError("DHCPServer/@networkName missing"); 620 621 setNetwork(strNetworkName); 622 623 RTCString strTrunkType; 624 if (!server->getAttributeValue("trunkType", &strTrunkType)) 708 /** @todo log file override. */ 709 /** @todo log level (dhcpd group flags). */ 710 /** @todo log flags. */ 711 /** @todo control logging to stderr/out. */ 712 /** @todo if we like we could open the release log now. */ 713 714 const char *pszTrunkType; 715 if (!pElmServer->getAttributeValue("trunkType", &pszTrunkType)) 625 716 throw ConfigFileError("DHCPServer/@trunkType missing"); 626 if (str TrunkType == "none")717 if (strcmp(pszTrunkType, "none") == 0) 627 718 m_enmTrunkType = kIntNetTrunkType_None; 628 else if (str TrunkType == "whatever")719 else if (strcmp(pszTrunkType, "whatever") == 0) 629 720 m_enmTrunkType = kIntNetTrunkType_WhateverNone; 630 else if (str TrunkType == "netflt")721 else if (strcmp(pszTrunkType, "netflt") == 0) 631 722 m_enmTrunkType = kIntNetTrunkType_NetFlt; 632 else if (str TrunkType == "netadp")723 else if (strcmp(pszTrunkType, "netadp") == 0) 633 724 m_enmTrunkType = kIntNetTrunkType_NetAdp; 634 725 else 635 throw ConfigFileError( RTCStringFmt("Invalid DHCPServer/@trunkType value: %s", strTrunkType.c_str()));726 throw ConfigFileError("Invalid DHCPServer/@trunkType value: %s", pszTrunkType); 636 727 637 728 if ( m_enmTrunkType == kIntNetTrunkType_NetFlt 638 729 || m_enmTrunkType == kIntNetTrunkType_NetAdp) 639 730 { 640 RTCString strTrunk; 641 if (!server->getAttributeValue("trunkName", &strTrunk)) 731 if (!pElmServer->getAttributeValue("trunkName", &m_strTrunk)) 642 732 throw ConfigFileError("DHCPServer/@trunkName missing"); 643 m_strTrunk = strTrunk;644 733 } 645 734 else 646 735 m_strTrunk = ""; 647 736 648 getIPv4AddrAttribute(server, "IPAddress", &m_IPv4Address);649 getIPv4AddrAttribute(server, "networkMask", &m_IPv4Netmask);650 getIPv4AddrAttribute(server, "lowerIP", &m_IPv4PoolFirst);651 getIPv4AddrAttribute(server, "upperIP", &m_IPv4PoolLast);737 i_getIPv4AddrAttribute(pElmServer, "IPAddress", &m_IPv4Address); 738 i_getIPv4AddrAttribute(pElmServer, "networkMask", &m_IPv4Netmask); 739 i_getIPv4AddrAttribute(pElmServer, "lowerIP", &m_IPv4PoolFirst); 740 i_getIPv4AddrAttribute(pElmServer, "upperIP", &m_IPv4PoolLast); 652 741 653 742 /* 654 * DHCPServerchildren743 * <DHCPServer> children 655 744 */ 656 xml::NodesLoop it(* server);657 const xml::ElementNode * node;658 while (( node= it.forAllNodes()) != NULL)745 xml::NodesLoop it(*pElmServer); 746 const xml::ElementNode *pElmChild; 747 while ((pElmChild = it.forAllNodes()) != NULL) 659 748 { 660 749 /* 661 750 * Global options 662 751 */ 663 if (node->nameEquals("Options")) 664 { 665 parseGlobalOptions(node); 666 } 667 752 if (pElmChild->nameEquals("Options")) 753 i_parseGlobalOptions(pElmChild); 668 754 /* 669 755 * Per-VM configuration 670 756 */ 671 else if (node->nameEquals("Config")) 672 { 673 parseVMConfig(node); 674 } 675 } 676 } 677 678 679 void Config::parseGlobalOptions(const xml::ElementNode *options) 757 else if (pElmChild->nameEquals("Config")) 758 i_parseVMConfig(pElmChild); 759 else 760 LogDHCP(("Ignoring unexpected DHCPServer child: %s\n", pElmChild->getName())); 761 } 762 } 763 764 765 /** 766 * Internal worker for parsing the elements under /DHCPServer/Options/. 767 * 768 * @param pElmServer The <Options> element. 769 * @throws ConfigFileError 770 */ 771 void Config::i_parseGlobalOptions(const xml::ElementNode *options) 680 772 { 681 773 xml::NodesLoop it(*options); 682 const xml::ElementNode *node; 683 while ((node = it.forAllNodes()) != NULL) 684 { 685 if (node->nameEquals("Option")) 686 { 687 parseOption(node, m_GlobalOptions); 688 } 774 const xml::ElementNode *pElmChild; 775 while ((pElmChild = it.forAllNodes()) != NULL) 776 { 777 if (pElmChild->nameEquals("Option")) 778 i_parseOption(pElmChild, m_GlobalOptions); 689 779 else 690 { 691 throw ConfigFileError(RTCStringFmt("Unexpected element \"%s\"", 692 node->getName())); 693 } 694 } 695 } 696 697 698 /** 780 throw ConfigFileError("Unexpected element <%s>", pElmChild->getName()); 781 } 782 } 783 784 785 /** 786 * Internal worker for parsing the elements under /DHCPServer/Config/. 787 * 699 788 * VM Config entries are generated automatically from VirtualBox.xml 700 789 * with the MAC fetched from the VM config. The client id is nowhere 701 790 * in the picture there, so VM config is indexed with plain RTMAC, not 702 791 * ClientId (also see getOptions below). 703 */ 704 void Config::parseVMConfig(const xml::ElementNode *config) 705 { 706 RTMAC mac; 707 int rc; 708 709 RTCString strMac; 710 bool fHasMac = config->getAttributeValue("MACAddress", &strMac); 711 if (!fHasMac) 712 throw ConfigFileError(RTCStringFmt("Config missing MACAddress attribute")); 713 714 rc = parseMACAddress(mac, strMac); 715 if (RT_FAILURE(rc)) 716 { 717 throw ConfigFileError(RTCStringFmt("Malformed MACAddress attribute \"%s\"", 718 strMac.c_str())); 719 } 720 721 vmmap_t::iterator vmit( m_VMMap.find(mac) ); 792 * 793 * @param pElmServer The <Config> element. 794 * @throws ConfigFileError 795 */ 796 void Config::i_parseVMConfig(const xml::ElementNode *pElmConfig) 797 { 798 /* 799 * Attributes: 800 */ 801 /* The MAC address: */ 802 RTMAC MacAddr; 803 i_getMacAddressAttribute(pElmConfig, "MACAddress", &MacAddr); 804 805 vmmap_t::iterator vmit( m_VMMap.find(MacAddr) ); 722 806 if (vmit != m_VMMap.end()) 723 { 724 throw ConfigFileError(RTCStringFmt("Duplicate Config for MACAddress \"%s\"", 725 strMac.c_str())); 726 } 727 728 optmap_t &vmopts = m_VMMap[mac]; 729 730 xml::NodesLoop it(*config); 731 const xml::ElementNode *node; 732 while ((node = it.forAllNodes()) != NULL) 733 if (node->nameEquals("Option")) 734 parseOption(node, vmopts); 807 throw ConfigFileError("Duplicate Config for MACAddress %RTmac", &MacAddr); 808 809 optmap_t &vmopts = m_VMMap[MacAddr]; 810 811 /* Name - optional: */ 812 const char *pszName = NULL; 813 if (pElmConfig->getAttributeValue("name", &pszName)) 814 { 815 /** @todo */ 816 } 817 818 /* Fixed IP address assignment - optional: */ 819 if (pElmConfig->findAttribute("FixedIPAddress") != NULL) 820 { 821 /** @todo */ 822 } 823 824 /* 825 * Process the children. 826 */ 827 xml::NodesLoop it(*pElmConfig); 828 const xml::ElementNode *pElmChild; 829 while ((pElmChild = it.forAllNodes()) != NULL) 830 if (pElmChild->nameEquals("Option")) 831 i_parseOption(pElmChild, vmopts); 735 832 else 736 throw ConfigFileError(RTCStringFmt("Unexpected element \"%s\"", 737 node->getName())); 738 } 739 740 741 int Config::parseMACAddress(RTMAC &aMac, const RTCString &aStr) 742 { 743 RTMAC mac; 744 int rc; 745 746 rc = RTNetStrToMacAddr(aStr.c_str(), &mac); 747 if (RT_FAILURE(rc)) 748 return rc; 749 if (rc == VWRN_TRAILING_CHARS) 750 return VERR_INVALID_PARAMETER; 751 752 aMac = mac; 753 return VINF_SUCCESS; 754 } 755 756 757 int Config::parseClientId(OptClientId &aId, const RTCString &aStr) 758 { 759 RT_NOREF(aId, aStr); 760 return VERR_GENERAL_FAILURE; 761 } 762 763 764 /** 765 * Parse <Option/> element and add the option to the specified optmap. 766 */ 767 void Config::parseOption(const xml::ElementNode *option, optmap_t &optmap) 768 { 769 int rc; 833 throw ConfigFileError("Unexpected element '%s' under '%s'", pElmChild->getName(), pElmConfig->getName()); 834 } 835 836 837 /** 838 * Internal worker for parsing <Option> elements found under 839 * /DHCPServer/Options/ and /DHCPServer/Config/ 840 * 841 * @param pElmServer The <Option> element. 842 * @param optmap The option map to add the option to. 843 * @throws ConfigFileError 844 */ 845 void Config::i_parseOption(const xml::ElementNode *pElmOption, optmap_t &optmap) 846 { 847 /* The 'name' attribute: */ 848 const char *pszName; 849 if (!pElmOption->getAttributeValue("name", &pszName)) 850 throw ConfigFileError("missing option name"); 770 851 771 852 uint8_t u8Opt; 772 RTCString strName; 773 bool fHasName = option->getAttributeValue("name", &strName); 774 if (fHasName) 775 { 776 const char *pcszName = strName.c_str(); 777 778 rc = RTStrToUInt8Full(pcszName, 10, &u8Opt); 853 int rc = RTStrToUInt8Full(pszName, 10, &u8Opt); 854 if (rc != VINF_SUCCESS) /* no warnings either */ 855 throw ConfigFileError("Bad option name '%s'", pszName); 856 857 /* The opional 'encoding' attribute: */ 858 uint32_t u32Enc = 0; /* XXX: DhcpOptEncoding_Legacy */ 859 const char *pszEncoding; 860 if (pElmOption->getAttributeValue("encoding", &pszEncoding)) 861 { 862 rc = RTStrToUInt32Full(pszEncoding, 10, &u32Enc); 779 863 if (rc != VINF_SUCCESS) /* no warnings either */ 780 throw ConfigFileError(RTCStringFmt("Bad option \"%s\"", pcszName)); 781 782 } 783 else 784 throw ConfigFileError("missing option name"); 785 786 787 uint32_t u32Enc = 0; /* XXX: DhcpOptEncoding_Legacy */ 788 RTCString strEncoding; 789 bool fHasEncoding = option->getAttributeValue("encoding", &strEncoding); 790 if (fHasEncoding) 791 { 792 const char *pcszEnc = strEncoding.c_str(); 793 794 rc = RTStrToUInt32Full(pcszEnc, 10, &u32Enc); 795 if (rc != VINF_SUCCESS) /* no warnings either */ 796 throw ConfigFileError(RTCStringFmt("Bad encoding \"%s\"", pcszEnc)); 864 throw ConfigFileError("Bad option encoding '%s'", pszEncoding); 797 865 798 866 switch (u32Enc) 799 867 { 800 case 0: /* XXX: DhcpOptEncoding_Legacy */801 case 1: /* XXX: DhcpOptEncoding_Hex */802 break;803 default:804 throw ConfigFileError(RTCStringFmt("Unknown encoding \"%s\"", pcszEnc));868 case 0: /* XXX: DhcpOptEncoding_Legacy */ 869 case 1: /* XXX: DhcpOptEncoding_Hex */ 870 break; 871 default: 872 throw ConfigFileError("Unknown encoding '%s'", pszEncoding); 805 873 } 806 874 } 807 875 808 809 /* value may be omitted for OptNoValue options like rapid commit */810 RTCString strValue;811 option->getAttributeValue("value", &strValue);812 813 /* XXX: TODO: encoding, handle hex */814 DhcpOption *opt = DhcpOption::parse(u8Opt, u32Enc, strValue.c_str());876 /* The 'value' attribute. May be omitted for OptNoValue options like rapid commit. */ 877 const char *pszValue; 878 if (!pElmOption->getAttributeValue("value", &pszValue)) 879 pszValue = ""; 880 881 /** @todo XXX: TODO: encoding, handle hex */ 882 DhcpOption *opt = DhcpOption::parse(u8Opt, u32Enc, pszValue); 815 883 if (opt == NULL) 816 throw ConfigFileError(RTCStringFmt("Bad option \"%s\"", strName.c_str())); 817 884 throw ConfigFileError("Bad option '%s' (encoding %u): '%s' ", pszName, u32Enc, pszValue ? pszValue : ""); 885 886 /* Add it to the map: */ 818 887 optmap << opt; 819 888 } … … 821 890 822 891 /** 823 * Set m_strBaseName to sanitized version of m_strNetwork that can be 824 * used in a path component. 825 */ 826 void Config::sanitizeBaseName() 827 { 828 if (m_strNetwork.isNotEmpty()) 829 { 830 m_strBaseName = m_strNetwork; 831 832 char ch; 833 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 834 static const char s_szIllegals[] = "/\\\"*:<>?|\t\v\n\r\f\a\b"; /** @todo all control chars... */ 835 for (char *psz = m_strBaseName.mutableRaw(); (ch = *psz) != '\0'; ++psz) 836 if (strchr(s_szIllegals, ch)) 837 *psz = '_'; 838 #else 839 for (char *psz = m_strBaseName.mutableRaw(); (ch = *psz) != '\0'; ++psz) 840 if (RTPATH_IS_SEP(ch)) 841 *psz = '_'; 842 #endif 843 m_strBaseName.jolt(); /* Not really necessary, but it's protocol. */ 892 * Helper for retrieving a IPv4 attribute. 893 * 894 * @param pElm The element to get the attribute from. 895 * @param pszAttrName The name of the attribute 896 * @param pAddr Where to return the address. 897 * @throws ConfigFileError 898 */ 899 /*static*/ void Config::i_getIPv4AddrAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTNETADDRIPV4 pAddr) 900 { 901 const char *pszAttrValue; 902 if (pElm->getAttributeValue(pszAttrName, &pszAttrValue)) 903 { 904 int rc = RTNetStrToIPv4Addr(pszAttrValue, pAddr); 905 if (RT_SUCCESS(rc)) 906 return; 907 throw ConfigFileError("%s attribute %s is not a valid IPv4 address: '%s' -> %Rrc", 908 pElm->getName(), pszAttrName, pszAttrValue, rc); 844 909 } 845 910 else 846 m_strBaseName.setNull(); 847 } 848 849 850 optmap_t Config::getOptions(const OptParameterRequest &reqOpts, 851 const ClientId &id, 852 const OptVendorClassId &vendor) const 853 { 854 optmap_t optmap; 855 911 throw ConfigFileError("Required %s attribute missing on element %s", pszAttrName, pElm->getName()); 912 } 913 914 915 /** 916 * Helper for retrieving a MAC address attribute. 917 * 918 * @param pElm The element to get the attribute from. 919 * @param pszAttrName The name of the attribute 920 * @param pMacAddr Where to return the MAC address. 921 * @throws ConfigFileError 922 */ 923 /*static*/ void Config::i_getMacAddressAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTMAC pMacAddr) 924 { 925 const char *pszAttrValue; 926 if (pElm->getAttributeValue(pszAttrName, &pszAttrValue)) 927 { 928 int rc = RTNetStrToMacAddr(pszAttrValue, pMacAddr); 929 if (RT_SUCCESS(rc) && rc != VWRN_TRAILING_CHARS) 930 return; 931 throw ConfigFileError("%s attribute %s is not a valid MAC address: '%s' -> %Rrc", 932 pElm->getName(), pszAttrName, pszAttrValue, rc); 933 } 934 else 935 throw ConfigFileError("Required %s attribute missing on element %s", pszAttrName, pElm->getName()); 936 } 937 938 939 /** 940 * Method used by DHCPD to assemble a list of options for the client. 941 * 942 * @returns a_rRetOpts for convenience 943 * @param a_rRetOpts Where to put the requested options. 944 * @param reqOpts The requested options. 945 * @param id The client ID. 946 * @param idVendorClass The vendor class ID. 947 * @param idUserClass The user class ID. 948 */ 949 optmap_t &Config::getOptions(optmap_t &a_rRetOpts, const OptParameterRequest &reqOpts, const ClientId &id, 950 const OptVendorClassId &idVendorClass /*= OptVendorClassId()*/, 951 const OptUserClassId &idUserClass /*= OptUserClassId()*/) const 952 { 856 953 const optmap_t *vmopts = NULL; 857 954 vmmap_t::const_iterator vmit( m_VMMap.find(id.mac()) ); … … 859 956 vmopts = &vmit->second; 860 957 861 RT_NOREF(vendor); /* not yet */ 862 863 864 optmap << new OptSubnetMask(m_IPv4Netmask); 958 RT_NOREF(idVendorClass, idUserClass); /* not yet */ 959 960 a_rRetOpts << new OptSubnetMask(m_IPv4Netmask); 865 961 866 962 const OptParameterRequest::value_t& reqValue = reqOpts.value(); … … 868 964 { 869 965 uint8_t optreq = *itOptReq; 870 std::cout << ">>> requested option " << (int)optreq << std::endl;966 LogRel2((">>> requested option %d (%#x)\n", optreq, optreq)); 871 967 872 968 if (optreq == OptSubnetMask::optcode) 873 969 { 874 std::cout << "... always supplied" << std::endl;970 LogRel2(("... always supplied\n")); 875 971 continue; 876 972 } … … 881 977 if (it != vmopts->end()) 882 978 { 883 optmap<< it->second;884 std::cout << "... found in VM options" << std::endl;979 a_rRetOpts << it->second; 980 LogRel2(("... found in VM options\n")); 885 981 continue; 886 982 } … … 890 986 if (it != m_GlobalOptions.end()) 891 987 { 892 optmap<< it->second;893 std::cout << "... found in global options" << std::endl;988 a_rRetOpts << it->second; 989 LogRel2(("... found in global options\n")); 894 990 continue; 895 991 } 896 992 897 // std::cout << "... not found" << std::endl; 898 } 899 900 901 /* XXX: testing ... */ 993 LogRel3(("... not found\n")); 994 } 995 996 997 #if 0 /* bird disabled this as it looks dubious and testing only. */ 998 /** @todo XXX: testing ... */ 902 999 if (vmopts != NULL) 903 1000 { 904 for (optmap_t::const_iterator it = vmopts->begin(); it != vmopts->end(); ++it) { 1001 for (optmap_t::const_iterator it = vmopts->begin(); it != vmopts->end(); ++it) 1002 { 905 1003 std::shared_ptr<DhcpOption> opt(it->second); 906 if ( optmap.count(opt->optcode()) == 0 && opt->optcode() > 127)1004 if (a_rRetOpts.count(opt->optcode()) == 0 && opt->optcode() > 127) 907 1005 { 908 optmap<< opt;909 std::cout << "... forcing VM option " << (int)opt->optcode() << std::endl;1006 a_rRetOpts << opt; 1007 LogRel2(("... forcing VM option %d (%#x)\n", opt->optcode(), opt->optcode())); 910 1008 } 911 1009 } 912 1010 } 913 1011 914 for (optmap_t::const_iterator it = m_GlobalOptions.begin(); it != m_GlobalOptions.end(); ++it) { 1012 for (optmap_t::const_iterator it = m_GlobalOptions.begin(); it != m_GlobalOptions.end(); ++it) 1013 { 915 1014 std::shared_ptr<DhcpOption> opt(it->second); 916 if ( optmap.count(opt->optcode()) == 0 && opt->optcode() > 127)1015 if (a_rRetOpts.count(opt->optcode()) == 0 && opt->optcode() > 127) 917 1016 { 918 optmap<< opt;919 std::cout << "... forcing global option " << (int)opt->optcode() << std::endl;1017 a_rRetOpts << opt; 1018 LogRel2(("... forcing global option %d (%#x)", opt->optcode(), opt->optcode())); 920 1019 } 921 1020 } 922 923 return optmap; 924 } 1021 #endif 1022 1023 return a_rRetOpts; 1024 } -
trunk/src/VBox/NetworkServices/Dhcpd/Config.h
r79524 r79553 30 30 #include <VBox/intnet.h> 31 31 32 33 32 #include "DhcpOptions.h" 34 33 #include "ClientId.h" 35 34 36 35 36 /** 37 * DHCP server configuration. 38 */ 37 39 class Config 38 40 { 39 /** XXX: TODO: also store fixed address assignments, etc? */41 /** @todo XXX: also store fixed address assignments, etc? */ 40 42 typedef std::map<RTMAC, optmap_t> vmmap_t; 41 43 42 RTCString m_strHome; /* path of ~/.VirtualBox or equivalent*/44 RTCString m_strHome; /**< path of ~/.VirtualBox or equivalent, */ 43 45 44 RTCString m_strNetwork;45 RTCString m_strBaseName; /* m_strNetwork sanitized to be usable in a path component*/46 RTCString m_strNetwork; /**< The name of the internal network the DHCP server is connected to. */ 47 RTCString m_strBaseName; /**< m_strNetwork sanitized to be usable in a path component. */ 46 48 47 RTCString m_strTrunk;48 INTNETTRUNKTYPE m_enmTrunkType; 49 RTCString m_strTrunk; /**< The trunk name of the internal network. */ 50 INTNETTRUNKTYPE m_enmTrunkType; /**< The trunk type of the internal network. */ 49 51 50 RTMAC m_MacAddress;52 RTMAC m_MacAddress; /**< The MAC address for the DHCP server. */ 51 53 52 RTNETADDRIPV4 m_IPv4Address;53 RTNETADDRIPV4 m_IPv4Netmask;54 RTNETADDRIPV4 m_IPv4Address; /**< The IPv4 address of the DHCP server. */ 55 RTNETADDRIPV4 m_IPv4Netmask; /**< The IPv4 netmask for the DHCP server. */ 54 56 55 RTNETADDRIPV4 m_IPv4PoolFirst;56 RTNETADDRIPV4 m_IPv4PoolLast;57 RTNETADDRIPV4 m_IPv4PoolFirst; /**< The first IPv4 address in the pool. */ 58 RTNETADDRIPV4 m_IPv4PoolLast; /**< The last IPV4 address in the pool (inclusive like all other 'last' variables). */ 57 59 58 optmap_t m_GlobalOptions; 59 vmmap_t m_VMMap; 60 61 optmap_t m_GlobalOptions; /**< Global DHCP option. */ 62 vmmap_t m_VMMap; /**< Per MAC address (VM) DHCP options. */ 63 /** @todo r=bird: optmap_t is too narrow for adding configuration options such 64 * as max-lease-time, min-lease-time, default-lease-time and such like 65 * that does not translate directly to any specific DHCP option. */ 66 /** @todo r=bird: Additionally, I'd like to have a more generic option groups 67 * that fits inbetween m_VMMap (mac based) and m_GlobalOptions. 68 * Pattern/wildcard matching on MAC address, possibly also client ID, 69 * vendor class and user class, including simple lists of these. */ 60 70 61 71 private: 62 72 Config(); 63 73 64 int init(); 65 int homeInit(); 66 int logInit(); 67 int complete(); 68 69 public: /* factory methods */ 70 static Config *hardcoded(); /* for testing */ 71 static Config *create(int argc, char **argv); /* --config */ 72 static Config *compat(int argc, char **argv); /* old VBoxNetDHCP flags */ 73 74 public: /* accessors */ 75 const RTCString &getHome() const { return m_strHome; } 76 77 const RTCString &getNetwork() const { return m_strNetwork; } 78 void setNetwork(const RTCString &aStrNetwork); 79 80 const RTCString &getBaseName() const { return m_strBaseName; } 81 const RTCString &getTrunk() const { return m_strTrunk; } 82 INTNETTRUNKTYPE getTrunkType() const { return m_enmTrunkType; } 83 84 const RTMAC &getMacAddress() const { return m_MacAddress; } 85 86 RTNETADDRIPV4 getIPv4Address() const { return m_IPv4Address; } 87 RTNETADDRIPV4 getIPv4Netmask() const { return m_IPv4Netmask; } 88 89 RTNETADDRIPV4 getIPv4PoolFirst() const { return m_IPv4PoolFirst; } 90 RTNETADDRIPV4 getIPv4PoolLast() const { return m_IPv4PoolLast; } 74 int i_init(); 75 int i_homeInit(); 76 static Config *i_createInstanceAndCallInit(); 77 int i_logInit(); 78 int i_complete(); 91 79 92 80 public: 93 optmap_t getOptions(const OptParameterRequest &reqOpts, const ClientId &id, 94 const OptVendorClassId &vendor = OptVendorClassId()) const; 81 /** @name Factory methods 82 * @{ */ 83 static Config *hardcoded(); /**< For testing. */ 84 static Config *create(int argc, char **argv); /**< --config */ 85 static Config *compat(int argc, char **argv); /**< Old VBoxNetDHCP command line parsing. */ 86 /** @} */ 87 88 /** @name Accessors 89 * @{ */ 90 const RTCString &getHome() const { return m_strHome; } 91 92 const RTCString &getNetwork() const { return m_strNetwork; } 93 94 const RTCString &getBaseName() const { return m_strBaseName; } 95 const RTCString &getTrunk() const { return m_strTrunk; } 96 INTNETTRUNKTYPE getTrunkType() const { return m_enmTrunkType; } 97 98 const RTMAC &getMacAddress() const { return m_MacAddress; } 99 100 RTNETADDRIPV4 getIPv4Address() const { return m_IPv4Address; } 101 RTNETADDRIPV4 getIPv4Netmask() const { return m_IPv4Netmask; } 102 103 RTNETADDRIPV4 getIPv4PoolFirst() const { return m_IPv4PoolFirst; } 104 RTNETADDRIPV4 getIPv4PoolLast() const { return m_IPv4PoolLast; } 105 /** @} */ 106 107 optmap_t &getOptions(optmap_t &a_rRetOpts, const OptParameterRequest &reqOpts, const ClientId &id, 108 const OptVendorClassId &idVendorClass = OptVendorClassId(), 109 const OptUserClassId &idUserClass = OptUserClassId()) const; 95 110 96 111 private: 97 static Config *read(const char *pszFileName); 98 void parseConfig(const xml::ElementNode *root); 99 void parseServer(const xml::ElementNode *server); 100 void parseGlobalOptions(const xml::ElementNode *options); 101 void parseVMConfig(const xml::ElementNode *config); 102 void parseOption(const xml::ElementNode *option, optmap_t &optmap); 112 /** @name Configuration file reading and parsing 113 * @{ */ 114 static Config *i_read(const char *pszFileName); 115 void i_parseConfig(const xml::ElementNode *root); 116 void i_parseServer(const xml::ElementNode *server); 117 void i_parseGlobalOptions(const xml::ElementNode *options); 118 void i_parseVMConfig(const xml::ElementNode *config); 119 void i_parseOption(const xml::ElementNode *option, optmap_t &optmap); 103 120 104 int parseMACAddress(RTMAC &aMac, const RTCString &aStr); 105 int parseClientId(OptClientId &aId, const RTCString &aStr); 121 static void i_getIPv4AddrAttribute(const xml::ElementNode *pElm, const char *pcszAttrName, PRTNETADDRIPV4 pAddr); 122 static void i_getMacAddressAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTMAC pMacAddr); 123 /** @} */ 106 124 107 void sanitizeBaseName(); 125 void i_setNetwork(const RTCString &aStrNetwork); 126 void i_sanitizeBaseName(); 108 127 }; 109 128 -
trunk/src/VBox/NetworkServices/Dhcpd/DHCPD.cpp
r79524 r79553 36 36 return VERR_INVALID_STATE; 37 37 38 /** @todo r=bird: This must be configurable so main can read the database and 39 * fish assignments out of it. (That's the most efficient and accurate way of 40 * figuring out the IP address of a VM.) */ 41 38 42 /* leases file name */ 39 43 m_strLeasesFileName = pConfig->getHome(); … … 171 175 172 176 OptParameterRequest optlist(req); 173 reply->addOptions(m_pConfig->getOptions(optlist, req.clientId())); 177 optmap_t replyOptions; 178 reply->addOptions(m_pConfig->getOptions(replyOptions, optlist, req.clientId())); 174 179 175 180 // reply->maybeUnicast(req); /* XXX: we reject ciaddr != 0 above */ … … 209 214 210 215 OptParameterRequest optlist(req); 211 ack->addOptions(m_pConfig->getOptions(optlist, req.clientId())); 216 optmap_t replyOptions; 217 ack->addOptions(m_pConfig->getOptions(replyOptions, optlist, req.clientId())); 212 218 213 219 ack->addOption(OptMessage("Ok, ok, here it is")); … … 236 242 return NULL; 237 243 238 optmap_t info(m_pConfig->getOptions(params, req.clientId())); 244 optmap_t info; 245 m_pConfig->getOptions(info, params, req.clientId()); 239 246 if (info.empty()) 240 247 return NULL; -
trunk/src/VBox/NetworkServices/Dhcpd/DhcpOptions.h
r79524 r79553 608 608 609 609 610 /* 611 * Define the DHCP options we want to use.610 /** @name The DHCP options types. 611 * @{ 612 612 */ 613 613 typedef OptValue<1, RTNETADDRIPV4> OptSubnetMask; … … 636 636 typedef OptString<66> OptTFTPServer; /* when overloaded */ 637 637 typedef OptString<67> OptBootFileName; /* when overloaded */ 638 typedef OptList<77, uint8_t> OptUserClassId; 638 639 typedef OptNoValue<80> OptRapidCommit; /* RFC4039 */ 640 /** @} */ 639 641 640 642 #endif /* !VBOX_INCLUDED_SRC_Dhcpd_DhcpOptions_h */
Note:
See TracChangeset
for help on using the changeset viewer.