Changeset 79800 in vbox for trunk/src/VBox
- Timestamp:
- Jul 16, 2019 12:06:00 AM (5 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/DHCPConfigImpl.h
r79771 r79800 235 235 VirtualBoxBase *pErrorDst); 236 236 237 /** @name Internal accessors 238 * @{ */ 239 bool i_getInclusive() const RT_NOEXCEPT { return m_fInclusive; } 240 DHCPGroupConditionType_T i_getType() const RT_NOEXCEPT { return m_enmType; } 241 com::Utf8Str const &i_getValue() const RT_NOEXCEPT { return m_strValue; } 242 /** @} */ 243 237 244 protected: 238 245 /** @name Wrapped IDHCPGroupCondition properties … … 288 295 HRESULT i_saveSettings(settings::DHCPGroupConfig &a_rDst); 289 296 HRESULT i_removeCondition(DHCPGroupCondition *a_pCondition); 297 void i_writeDhcpdConfig(xml::ElementNode *a_pElmGroup) RT_OVERRIDE; 290 298 291 299 protected: -
trunk/src/VBox/Main/src-server/DHCPConfigImpl.cpp
r79778 r79800 865 865 866 866 867 /** 868 * Overridden to add a 'name' attribute and emit condition child elements. 869 */ 870 void 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 867 915 HRESULT DHCPGroupConfig::getName(com::Utf8Str &aName) 868 916 { -
trunk/src/VBox/NetworkServices/Dhcpd/Config.cpp
r79778 r79800 39 39 * Global Variables * 40 40 *********************************************************************************************************************************/ 41 /*static*/ bool Config::g_fInitializedLog = false; 41 /*static*/ bool Config::g_fInitializedLog = false; 42 /*static*/ uint32_t GroupConfig::s_uGroupNo = 0; 42 43 43 44 … … 55 56 #endif 56 57 58 explicit ConfigFileError(xml::Node const *pNode, const char *a_pszMsgFmt, ...) 59 : RTCError((char *)NULL) 60 { 61 62 i_buildPath(pNode); 63 m_strMsg.append(": "); 64 65 va_list va; 66 va_start(va, a_pszMsgFmt); 67 m_strMsg.appendPrintf(a_pszMsgFmt, va); 68 va_end(va); 69 } 70 71 57 72 ConfigFileError(const char *a_pszMsgFmt, ...) 58 73 : RTCError((char *)NULL) … … 67 82 : RTCError(a_rstrMessage) 68 83 {} 84 85 private: 86 void i_buildPath(xml::Node const *pNode) 87 { 88 if (pNode) 89 { 90 i_buildPath(pNode->getParent()); 91 m_strMsg.append('/'); 92 m_strMsg.append(pNode->getName()); 93 if (pNode->isElement()) 94 { 95 xml::ElementNode const *pElm = (xml::ElementNode const *)pNode; 96 for (xml::Node const *pNodeChild = pElm->getFirstChild(); pNodeChild != NULL; 97 pNodeChild = pNodeChild->getNextSibiling()) 98 if (pNodeChild->isAttribute()) 99 { 100 m_strMsg.append("[@"); 101 m_strMsg.append(pNodeChild->getName()); 102 m_strMsg.append('='); 103 m_strMsg.append(pNodeChild->getValue()); 104 m_strMsg.append(']'); 105 } 106 } 107 } 108 } 109 69 110 }; 70 111 … … 83 124 , m_IPv4PoolFirst() 84 125 , m_IPv4PoolLast() 85 , m_GlobalOptions() 86 , m_VMMap() 126 , m_GlobalConfig() 127 , m_GroupConfigs() 128 , m_HostConfigs() 87 129 { 88 130 } … … 327 369 { "--log-flags", 'f', RTGETOPT_REQ_STRING }, 328 370 { "--log-group-settings", 'g', RTGETOPT_REQ_STRING }, 371 { "--relaxed", 'r', RTGETOPT_REQ_NOTHING }, 372 { "--strict", 's', RTGETOPT_REQ_NOTHING }, 329 373 }; 330 374 … … 339 383 const char *pszConfig = NULL; 340 384 const char *pszComment = NULL; 385 bool fStrict = true; 341 386 342 387 for (;;) … … 367 412 case 'g': 368 413 pszLogGroupSettings = ValueUnion.psz; 414 break; 415 416 case 'r': 417 fStrict = false; 418 break; 419 420 case 's': 421 fStrict = true; 369 422 break; 370 423 … … 376 429 break; 377 430 378 case VINF_GETOPT_NOT_OPTION:379 RTMsgError("Unexpected command line argument: '%s'", ValueUnion.psz);380 return NULL;381 382 431 default: 383 432 RTGetOptPrintError(rc, &ValueUnion); … … 418 467 RTMsgInfo("reading config from '%s'...\n", pszConfig); 419 468 std::unique_ptr<Config> ptrConfig; 420 ptrConfig.reset(Config::i_read(pszConfig ));469 ptrConfig.reset(Config::i_read(pszConfig, fStrict)); 421 470 if (ptrConfig.get() != NULL) 422 471 { … … 433 482 * @note The release log has is not operational when this method is called. 434 483 */ 435 Config *Config::i_read(const char *pszFileName ) RT_NOEXCEPT484 Config *Config::i_read(const char *pszFileName, bool fStrict) RT_NOEXCEPT 436 485 { 437 486 if (pszFileName == NULL || pszFileName[0] == '\0') … … 468 517 try 469 518 { 470 config->i_parseConfig(doc.getRootElement() );519 config->i_parseConfig(doc.getRootElement(), fStrict); 471 520 } 472 521 catch (const RTCError &e) … … 491 540 492 541 /** 542 * Helper for retrieving a IPv4 attribute. 543 * 544 * @param pElm The element to get the attribute from. 545 * @param pszAttrName The name of the attribute 546 * @param pAddr Where to return the address. 547 * @throws ConfigFileError 548 */ 549 static void getIPv4AddrAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTNETADDRIPV4 pAddr) 550 { 551 const char *pszAttrValue; 552 if (pElm->getAttributeValue(pszAttrName, &pszAttrValue)) 553 { 554 int rc = RTNetStrToIPv4Addr(pszAttrValue, pAddr); 555 if (RT_SUCCESS(rc)) 556 return; 557 throw ConfigFileError(pElm, "Attribute %s is not a valid IPv4 address: '%s' -> %Rrc", pszAttrName, pszAttrValue, rc); 558 } 559 throw ConfigFileError(pElm, "Required %s attribute missing", pszAttrName); 560 } 561 562 563 /** 564 * Helper for retrieving a MAC address attribute. 565 * 566 * @param pElm The element to get the attribute from. 567 * @param pszAttrName The name of the attribute 568 * @param pMacAddr Where to return the MAC address. 569 * @throws ConfigFileError 570 */ 571 static void getMacAddressAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTMAC pMacAddr) 572 { 573 const char *pszAttrValue; 574 if (pElm->getAttributeValue(pszAttrName, &pszAttrValue)) 575 { 576 int rc = RTNetStrToMacAddr(pszAttrValue, pMacAddr); 577 if (RT_SUCCESS(rc) && rc != VWRN_TRAILING_CHARS) 578 return; 579 throw ConfigFileError(pElm, "attribute %s is not a valid MAC address: '%s' -> %Rrc", pszAttrName, pszAttrValue, rc); 580 } 581 throw ConfigFileError(pElm, "Required %s attribute missing", pszAttrName); 582 } 583 584 585 /** 493 586 * Internal worker for i_read() that parses the root element and everything 494 587 * below it. 495 588 * 496 * @param pElmRoot The root element. 589 * @param pElmRoot The root element. 590 * @param fStrict Set if we're in strict mode, clear if we just 591 * want to get on with it if we can. 497 592 * @throws std::bad_alloc, ConfigFileError 498 593 */ 499 void Config::i_parseConfig(const xml::ElementNode *pElmRoot )594 void Config::i_parseConfig(const xml::ElementNode *pElmRoot, bool fStrict) 500 595 { 501 596 /* … … 510 605 throw ConfigFileError("Unexpected root element '%s'", pElmRoot->getName()); 511 606 512 i_parseServer(pElmRoot );607 i_parseServer(pElmRoot, fStrict); 513 608 514 609 #if 0 /** @todo convert to LogRel2 stuff */ … … 539 634 * 540 635 * @param pElmServer The DHCPServer element. 636 * @param fStrict Set if we're in strict mode, clear if we just 637 * want to get on with it if we can. 541 638 * @throws std::bad_alloc, ConfigFileError 542 639 */ 543 void Config::i_parseServer(const xml::ElementNode *pElmServer )640 void Config::i_parseServer(const xml::ElementNode *pElmServer, bool fStrict) 544 641 { 545 642 /* … … 588 685 } 589 686 590 i_getIPv4AddrAttribute(pElmServer, "IPAddress", &m_IPv4Address);591 i_getIPv4AddrAttribute(pElmServer, "networkMask", &m_IPv4Netmask);592 i_getIPv4AddrAttribute(pElmServer, "lowerIP", &m_IPv4PoolFirst);593 i_getIPv4AddrAttribute(pElmServer, "upperIP", &m_IPv4PoolLast);687 ::getIPv4AddrAttribute(pElmServer, "IPAddress", &m_IPv4Address); 688 ::getIPv4AddrAttribute(pElmServer, "networkMask", &m_IPv4Netmask); 689 ::getIPv4AddrAttribute(pElmServer, "lowerIP", &m_IPv4PoolFirst); 690 ::getIPv4AddrAttribute(pElmServer, "upperIP", &m_IPv4PoolLast); 594 691 595 692 /* … … 600 697 while ((pElmChild = it.forAllNodes()) != NULL) 601 698 { 699 /* Global options: */ 700 if (pElmChild->nameEquals("Options")) 701 m_GlobalConfig.initFromXml(pElmChild, fStrict); 702 /* Group w/ options: */ 703 else if (pElmChild->nameEquals("Group")) 704 { 705 std::unique_ptr<GroupConfig> ptrGroup(new GroupConfig()); 706 ptrGroup->initFromXml(pElmChild, fStrict); 707 if (m_GroupConfigs.find(ptrGroup->getGroupName()) == m_GroupConfigs.end()) 708 { 709 m_GroupConfigs[ptrGroup->getGroupName()] = ptrGroup.get(); 710 ptrGroup.release(); 711 } 712 else if (!fStrict) 713 LogRelFunc(("Ignoring duplicate group name: %s", ptrGroup->getGroupName().c_str())); 714 else 715 throw ConfigFileError("Duplicate group name: %s", ptrGroup->getGroupName().c_str()); 716 } 602 717 /* 603 * Global options 604 */ 605 if (pElmChild->nameEquals("Options")) 606 i_parseGlobalOptions(pElmChild); 607 /* 608 * Per-VM configuration 718 * MAC address and per VM NIC configurations: 609 719 */ 610 720 else if (pElmChild->nameEquals("Config")) 611 i_parseVMConfig(pElmChild); 721 { 722 std::unique_ptr<HostConfig> ptrHost(new HostConfig()); 723 ptrHost->initFromXml(pElmChild, fStrict); 724 if (m_HostConfigs.find(ptrHost->getMACAddress()) == m_HostConfigs.end()) 725 { 726 m_HostConfigs[ptrHost->getMACAddress()] = ptrHost.get(); 727 ptrHost.release(); 728 } 729 else if (!fStrict) 730 LogRelFunc(("Ignorining duplicate MAC address (Config): %RTmac", &ptrHost->getMACAddress())); 731 else 732 throw ConfigFileError("Duplicate MAC address (Config): %RTmac", &ptrHost->getMACAddress()); 733 } 734 else if (!fStrict) 735 LogRel(("Ignoring unexpected DHCPServer child: %s\n", pElmChild->getName())); 612 736 else 613 LogRel(("Ignoring unexpected DHCPServer child: %s\n", pElmChild->getName())); 614 } 615 } 616 617 618 /** 619 * Internal worker for parsing the elements under /DHCPServer/Options/. 620 * 621 * @param pElmServer The <Options> element. 737 throw ConfigFileError("Unexpected DHCPServer child <%s>'", pElmChild->getName()); 738 } 739 } 740 741 742 /** 743 * Internal worker for parsing \<Option\> elements found under 744 * /DHCPServer/Options/, /DHCPServer/Group/ and /DHCPServer/Config/. 745 * 746 * @param pElmOption An \<Option\> element. 622 747 * @throws std::bad_alloc, ConfigFileError 623 748 */ 624 void Config::i_parseGlobalOptions(const xml::ElementNode *options) 625 { 626 xml::NodesLoop it(*options); 627 const xml::ElementNode *pElmChild; 628 while ((pElmChild = it.forAllNodes()) != NULL) 629 { 630 if (pElmChild->nameEquals("Option")) 631 i_parseOption(pElmChild, m_GlobalOptions); 632 else 633 throw ConfigFileError("Unexpected element <%s>", pElmChild->getName()); 634 } 635 } 636 637 638 /** 639 * Internal worker for parsing the elements under /DHCPServer/Config/. 640 * 641 * VM Config entries are generated automatically from VirtualBox.xml 642 * with the MAC fetched from the VM config. The client id is nowhere 643 * in the picture there, so VM config is indexed with plain RTMAC, not 644 * ClientId (also see getOptions below). 645 * 646 * @param pElmServer The <Config> element. 647 * @throws std::bad_alloc, ConfigFileError 648 */ 649 void Config::i_parseVMConfig(const xml::ElementNode *pElmConfig) 650 { 651 /* 652 * Attributes: 653 */ 654 /* The MAC address: */ 655 RTMAC MacAddr; 656 i_getMacAddressAttribute(pElmConfig, "MACAddress", &MacAddr); 657 658 vmmap_t::iterator vmit( m_VMMap.find(MacAddr) ); 659 if (vmit != m_VMMap.end()) 660 throw ConfigFileError("Duplicate Config for MACAddress %RTmac", &MacAddr); 661 662 optmap_t &vmopts = m_VMMap[MacAddr]; 663 664 /* Name - optional: */ 665 const char *pszName = NULL; 666 if (pElmConfig->getAttributeValue("name", &pszName)) 667 { 668 /** @todo */ 669 } 670 671 /* Fixed IP address assignment - optional: */ 672 if (pElmConfig->findAttribute("FixedIPAddress") != NULL) 673 { 674 /** @todo */ 675 } 676 677 /* 678 * Process the children. 679 */ 680 xml::NodesLoop it(*pElmConfig); 681 const xml::ElementNode *pElmChild; 682 while ((pElmChild = it.forAllNodes()) != NULL) 683 if (pElmChild->nameEquals("Option")) 684 i_parseOption(pElmChild, vmopts); 685 else 686 throw ConfigFileError("Unexpected element '%s' under '%s'", pElmChild->getName(), pElmConfig->getName()); 687 } 688 689 690 /** 691 * Internal worker for parsing <Option> elements found under 692 * /DHCPServer/Options/ and /DHCPServer/Config/ 693 * 694 * @param pElmServer The <Option> element. 695 * @param optmap The option map to add the option to. 696 * @throws std::bad_alloc, ConfigFileError 697 */ 698 void Config::i_parseOption(const xml::ElementNode *pElmOption, optmap_t &optmap) 749 void ConfigLevelBase::i_parseOption(const xml::ElementNode *pElmOption) 699 750 { 700 751 /* The 'name' attribute: */ 701 752 const char *pszName; 702 753 if (!pElmOption->getAttributeValue("name", &pszName)) 703 throw ConfigFileError( "missing option name");754 throw ConfigFileError(pElmOption, "missing option name"); 704 755 705 756 uint8_t u8Opt; 706 757 int rc = RTStrToUInt8Full(pszName, 10, &u8Opt); 707 758 if (rc != VINF_SUCCESS) /* no warnings either */ 708 throw ConfigFileError( "Bad option name '%s': %Rrc", pszName, rc);759 throw ConfigFileError(pElmOption, "Bad option name '%s': %Rrc", pszName, rc); 709 760 710 761 /* The opional 'encoding' attribute: */ … … 715 766 rc = RTStrToUInt32Full(pszEncoding, 10, &u32Enc); 716 767 if (rc != VINF_SUCCESS) /* no warnings either */ 717 throw ConfigFileError( "Bad option encoding '%s': %Rrc", pszEncoding, rc);768 throw ConfigFileError(pElmOption, "Bad option encoding '%s': %Rrc", pszEncoding, rc); 718 769 719 770 switch (u32Enc) … … 723 774 break; 724 775 default: 725 throw ConfigFileError( "Unknown encoding '%s'", pszEncoding);776 throw ConfigFileError(pElmOption, "Unknown encoding '%s'", pszEncoding); 726 777 } 727 778 } … … 735 786 DhcpOption *opt = DhcpOption::parse(u8Opt, u32Enc, pszValue); 736 787 if (opt == NULL) 737 throw ConfigFileError( "Bad option '%s' (encoding %u): '%s' ", pszName, u32Enc, pszValue ? pszValue : "");788 throw ConfigFileError(pElmOption, "Bad option '%s' (encoding %u): '%s' ", pszName, u32Enc, pszValue ? pszValue : ""); 738 789 739 790 /* Add it to the map: */ 740 optmap << opt; 741 } 742 743 744 /** 745 * Helper for retrieving a IPv4 attribute. 746 * 747 * @param pElm The element to get the attribute from. 748 * @param pszAttrName The name of the attribute 749 * @param pAddr Where to return the address. 750 * @throws ConfigFileError 751 */ 752 /*static*/ void Config::i_getIPv4AddrAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTNETADDRIPV4 pAddr) 753 { 754 const char *pszAttrValue; 755 if (pElm->getAttributeValue(pszAttrName, &pszAttrValue)) 756 { 757 int rc = RTNetStrToIPv4Addr(pszAttrValue, pAddr); 758 if (RT_SUCCESS(rc)) 759 return; 760 throw ConfigFileError("%s attribute %s is not a valid IPv4 address: '%s' -> %Rrc", 761 pElm->getName(), pszAttrName, pszAttrValue, rc); 791 m_Options << opt; 792 } 793 794 795 /** 796 * Final children parser, handling only \<Option\> and barfing at anything else. 797 * 798 * @param pElmChild The child element to handle. 799 * @param fStrict Set if we're in strict mode, clear if we just 800 * want to get on with it if we can. 801 * @throws std::bad_alloc, ConfigFileError 802 */ 803 void ConfigLevelBase::i_parseChild(const xml::ElementNode *pElmChild, bool fStrict) 804 { 805 if (pElmChild->nameEquals("Option")) 806 { 807 try 808 { 809 i_parseOption(pElmChild); 810 } 811 catch (ConfigFileError &rXcpt) 812 { 813 if (fStrict) 814 throw rXcpt; 815 LogRelFunc(("Ignoring option: %s\n", rXcpt.what())); 816 } 817 } 818 else if (!fStrict) 819 { 820 ConfigFileError Dummy(pElmChild->getParent(), "Unexpected child '%s'", pElmChild->getName()); 821 LogRelFunc(("%s\n", Dummy.what())); 762 822 } 763 823 else 764 throw ConfigFileError("Required %s attribute missing on element %s", pszAttrName, pElm->getName()); 765 } 766 767 768 /** 769 * Helper for retrieving a MAC address attribute. 770 * 771 * @param pElm The element to get the attribute from. 772 * @param pszAttrName The name of the attribute 773 * @param pMacAddr Where to return the MAC address. 774 * @throws ConfigFileError 775 */ 776 /*static*/ void Config::i_getMacAddressAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTMAC pMacAddr) 777 { 778 const char *pszAttrValue; 779 if (pElm->getAttributeValue(pszAttrName, &pszAttrValue)) 780 { 781 int rc = RTNetStrToMacAddr(pszAttrValue, pMacAddr); 782 if (RT_SUCCESS(rc) && rc != VWRN_TRAILING_CHARS) 783 return; 784 throw ConfigFileError("%s attribute %s is not a valid MAC address: '%s' -> %Rrc", 785 pElm->getName(), pszAttrName, pszAttrValue, rc); 786 } 824 throw ConfigFileError(pElmChild->getParent(), "Unexpected child '%s'", pElmChild->getName()); 825 } 826 827 828 /** 829 * Base class initialization taking a /DHCPServer/Options, /DHCPServer/Group or 830 * /DHCPServer/Config element as input and handling common attributes as well as 831 * any \<Option\> children. 832 * 833 * @param pElmConfig The configuration element to parse. 834 * @param fStrict Set if we're in strict mode, clear if we just 835 * want to get on with it if we can. 836 * @throws std::bad_alloc, ConfigFileError 837 */ 838 void ConfigLevelBase::initFromXml(const xml::ElementNode *pElmConfig, bool fStrict) 839 { 840 /* 841 * Common attributes: 842 */ 843 if (!pElmConfig->getAttributeValue("secMinLeaseTime", &m_secMinLeaseTime)) 844 m_secMinLeaseTime = 0; 845 if (!pElmConfig->getAttributeValue("secDefaultLeaseTime", &m_secDefaultLeaseTime)) 846 m_secDefaultLeaseTime = 0; 847 if (!pElmConfig->getAttributeValue("secMaxLeaseTime", &m_secMaxLeaseTime)) 848 m_secMaxLeaseTime = 0; 849 850 /* 851 * Parse children. 852 */ 853 xml::NodesLoop it(*pElmConfig); 854 const xml::ElementNode *pElmChild; 855 while ((pElmChild = it.forAllNodes()) != NULL) 856 i_parseChild(pElmChild, fStrict); 857 } 858 859 860 /** 861 * Internal worker for parsing the elements under /DHCPServer/Options/. 862 * 863 * @param pElmOptions The <Options> element. 864 * @param fStrict Set if we're in strict mode, clear if we just 865 * want to get on with it if we can. 866 * @throws std::bad_alloc, ConfigFileError 867 */ 868 void GlobalConfig::initFromXml(const xml::ElementNode *pElmOptions, bool fStrict) 869 { 870 ConfigLevelBase::initFromXml(pElmOptions, fStrict); 871 } 872 873 874 /** 875 * Overrides base class to handle the condition elements under \<Group\>. 876 * 877 * @param pElmChild The child element. 878 * @param fStrict Set if we're in strict mode, clear if we just 879 * want to get on with it if we can. 880 * @throws std::bad_alloc, ConfigFileError 881 */ 882 void GroupConfig::i_parseChild(const xml::ElementNode *pElmChild, bool fStrict) 883 { 884 if (pElmChild->nameEquals("ConditionMAC")) 885 { } 886 else if (pElmChild->nameEquals("ConditionMACWildcard")) 887 { } 888 else if (pElmChild->nameEquals("ConditionVendorClassID")) 889 { } 890 else if (pElmChild->nameEquals("ConditionVendorClassIDWildcard")) 891 { } 892 else if (pElmChild->nameEquals("ConditionUserClassID")) 893 { } 894 else if (pElmChild->nameEquals("ConditionUserClassIDWildcard")) 895 { } 787 896 else 788 throw ConfigFileError("Required %s attribute missing on element %s", pszAttrName, pElm->getName()); 897 { 898 ConfigLevelBase::i_parseChild(pElmChild, fStrict); 899 return; 900 } 901 } 902 903 904 /** 905 * Internal worker for parsing the elements under /DHCPServer/Group/. 906 * 907 * @param pElmGroup The \<Group\> element. 908 * @param fStrict Set if we're in strict mode, clear if we just 909 * want to get on with it if we can. 910 * @throws std::bad_alloc, ConfigFileError 911 */ 912 void GroupConfig::initFromXml(const xml::ElementNode *pElmGroup, bool fStrict) 913 { 914 /* 915 * Attributes: 916 */ 917 if (!pElmGroup->getAttributeValue("name", m_strName) || m_strName.isEmpty()) 918 { 919 if (fStrict) 920 throw ConfigFileError(pElmGroup, "Group as no name or the name is empty"); 921 m_strName.printf("Group#%u", s_uGroupNo++); 922 } 923 924 /* 925 * Do common initialization (including children). 926 */ 927 ConfigLevelBase::initFromXml(pElmGroup, fStrict); 928 } 929 930 931 /** 932 * Internal worker for parsing the elements under /DHCPServer/Config/. 933 * 934 * VM Config entries are generated automatically from VirtualBox.xml 935 * with the MAC fetched from the VM config. The client id is nowhere 936 * in the picture there, so VM config is indexed with plain RTMAC, not 937 * ClientId (also see getOptions below). 938 * 939 * @param pElmConfig The \<Config\> element. 940 * @param fStrict Set if we're in strict mode, clear if we just 941 * want to get on with it if we can. 942 * @throws std::bad_alloc, ConfigFileError 943 */ 944 void HostConfig::initFromXml(const xml::ElementNode *pElmConfig, bool fStrict) 945 { 946 /* 947 * Attributes: 948 */ 949 /* The MAC address: */ 950 ::getMacAddressAttribute(pElmConfig, "MACAddress", &m_MACAddress); 951 952 /* Name - optional: */ 953 if (!pElmConfig->getAttributeValue("name", m_strName)) 954 m_strName.printf("MAC:%RTmac", m_MACAddress); 955 956 /* Fixed IP address assignment - optional: */ 957 const char *pszFixedAddress = pElmConfig->findAttributeValue("FixedIPAddress"); 958 if (!pszFixedAddress || *RTStrStripL(pszFixedAddress) == '\0') 959 m_fHaveFixedAddress = false; 960 else 961 { 962 m_fHaveFixedAddress = false; 963 ::getIPv4AddrAttribute(pElmConfig, "FixedIPAddress", &m_FixedAddress); 964 } 965 966 /* 967 * Do common initialization. 968 */ 969 ConfigLevelBase::initFromXml(pElmConfig, fStrict); 970 } 971 972 973 /** 974 * Assembles a priorities vector of configurations for the client. 975 * 976 * @returns a_rRetConfigs for convenience. 977 * @param a_rRetConfigs Where to return the configurations. 978 * @param a_ridClient The client ID. 979 * @param a_ridVendorClass The vendor class ID if present. 980 * @param a_ridUserClass The user class ID if present 981 */ 982 Config::ConfigVec &Config::getConfigsForClient(Config::ConfigVec &a_rRetConfigs, const ClientId &a_ridClient, 983 const OptVendorClassId &a_ridVendorClass, 984 const OptUserClassId &a_ridUserClass) const 985 { 986 /* Host specific config first: */ 987 HostConfigMap::const_iterator itHost = m_HostConfigs.find(a_ridClient.mac()); 988 if (itHost != m_HostConfigs.end()) 989 a_rRetConfigs.push_back(itHost->second); 990 991 /* Groups: */ 992 RT_NOREF(a_ridVendorClass, a_ridUserClass); /* not yet */ 993 994 /* Global: */ 995 a_rRetConfigs.push_back(&m_GlobalConfig); 996 997 return a_rRetConfigs; 789 998 } 790 999 … … 795 1004 * @returns a_rRetOpts for convenience 796 1005 * @param a_rRetOpts Where to put the requested options. 797 * @param reqOpts The requested options. 798 * @param id The client ID. 799 * @param idVendorClass The vendor class ID. 800 * @param idUserClass The user class ID. 1006 * @param a_rReqOpts The requested options. 1007 * @param a_rConfigs Relevant configurations returned by 1008 * Config::getConfigsForClient(). 801 1009 * 802 1010 * @throws std::bad_alloc 803 1011 */ 804 optmap_t &Config::getOptions(optmap_t &a_rRetOpts, const OptParameterRequest &reqOpts, const ClientId &id, 805 const OptVendorClassId &idVendorClass /*= OptVendorClassId()*/, 806 const OptUserClassId &idUserClass /*= OptUserClassId()*/) const 807 { 808 const optmap_t *vmopts = NULL; 809 vmmap_t::const_iterator vmit( m_VMMap.find(id.mac()) ); 810 if (vmit != m_VMMap.end()) 811 vmopts = &vmit->second; 812 813 RT_NOREF(idVendorClass, idUserClass); /* not yet */ 814 1012 optmap_t &Config::getOptionsForClient(optmap_t &a_rRetOpts, const OptParameterRequest &a_rReqOpts, ConfigVec &a_rConfigs) const 1013 { 1014 /* 1015 * Always supply the subnet: 1016 */ 815 1017 a_rRetOpts << new OptSubnetMask(m_IPv4Netmask); 816 1018 817 const OptParameterRequest::value_t& reqValue = reqOpts.value(); 1019 /* 1020 * Try provide the requested options: 1021 */ 1022 const OptParameterRequest::value_t &reqValue = a_rReqOpts.value(); 818 1023 for (octets_t::const_iterator itOptReq = reqValue.begin(); itOptReq != reqValue.end(); ++itOptReq) 819 1024 { 820 uint8_t optreq = *itOptReq;821 LogRel2((">>> requested option %d (%#x)\n", optreq, optreq));822 823 if ( optreq == OptSubnetMask::optcode)1025 uint8_t bOptReq = *itOptReq; 1026 LogRel2((">>> requested option %d (%#x)\n", bOptReq, bOptReq)); 1027 1028 if (bOptReq != OptSubnetMask::optcode) 824 1029 { 1030 bool fFound = false; 1031 for (size_t i = 0; i < a_rConfigs.size(); i++) 1032 { 1033 optmap_t::const_iterator itFound; 1034 if (a_rConfigs[i]->findOption(bOptReq, itFound)) /* crap interface */ 1035 { 1036 LogRel2(("... found in %s (type %s)\n", a_rConfigs[i]->getName(), a_rConfigs[i]->getType())); 1037 a_rRetOpts << itFound->second; 1038 fFound = true; 1039 break; 1040 } 1041 } 1042 if (!fFound) 1043 LogRel3(("... not found\n")); 1044 } 1045 else 825 1046 LogRel2(("... always supplied\n")); 826 continue;827 }828 829 if (vmopts != NULL)830 {831 optmap_t::const_iterator it( vmopts->find(optreq) );832 if (it != vmopts->end())833 {834 a_rRetOpts << it->second;835 LogRel2(("... found in VM options\n"));836 continue;837 }838 }839 840 optmap_t::const_iterator it( m_GlobalOptions.find(optreq) );841 if (it != m_GlobalOptions.end())842 {843 a_rRetOpts << it->second;844 LogRel2(("... found in global options\n"));845 continue;846 }847 848 LogRel3(("... not found\n"));849 1047 } 850 1048 -
trunk/src/VBox/NetworkServices/Dhcpd/Config.h
r79761 r79800 35 35 36 36 /** 37 * Base configuration 38 * 39 * @author bird (2019-07-15) 40 */ 41 class ConfigLevelBase 42 { 43 private: 44 /** DHCP options. */ 45 optmap_t m_Options; 46 /** Minimum lease time, zero means try next level up. */ 47 uint32_t m_secMinLeaseTime; 48 /** Default lease time, zero means try next level up. */ 49 uint32_t m_secDefaultLeaseTime; 50 /** Maximum lease time, zero means try next level up. */ 51 uint32_t m_secMaxLeaseTime; 52 53 public: 54 ConfigLevelBase() 55 : m_Options() 56 , m_secMinLeaseTime(0) 57 , m_secDefaultLeaseTime(0) 58 , m_secMaxLeaseTime(0) 59 { } 60 61 virtual ~ConfigLevelBase() 62 { } 63 64 virtual void initFromXml(xml::ElementNode const *pElm, bool fStrict); 65 virtual const char *getType() const RT_NOEXCEPT = 0; 66 virtual const char *getName() const RT_NOEXCEPT = 0; 67 68 /** 69 * Tries to find DHCP option @a bOpt, returning an success indicator and 70 * iterator to the result. 71 */ 72 bool findOption(uint8_t bOpt, optmap_t::const_iterator &a_rItRet) const RT_NOEXCEPT 73 { 74 a_rItRet = m_Options.find(bOpt); 75 return a_rItRet != m_Options.end(); 76 } 77 78 protected: 79 void i_parseOption(const xml::ElementNode *pElmOption); 80 virtual void i_parseChild(const xml::ElementNode *pElmChild, bool fStrict); 81 }; 82 83 84 /** 85 * Global config 86 */ 87 class GlobalConfig : public ConfigLevelBase 88 { 89 public: 90 GlobalConfig() 91 : ConfigLevelBase() 92 { } 93 void initFromXml(xml::ElementNode const *pElm, bool fStrict) RT_OVERRIDE; 94 const char *getType() const RT_NOEXCEPT RT_OVERRIDE { return "global"; } 95 const char *getName() const RT_NOEXCEPT RT_OVERRIDE { return "GlobalConfig"; } 96 }; 97 98 99 #if 0 /* later */ 100 /** 101 * Group membership condition. 102 */ 103 class GroupConditionBase 104 { 105 protected: 106 /** The value. */ 107 RTCString m_strValue; 108 109 public: 110 111 }; 112 #endif 113 114 115 /** 116 * Group config 117 */ 118 class GroupConfig : public ConfigLevelBase 119 { 120 public: 121 /** The group name. */ 122 RTCString m_strName; 123 124 public: 125 GroupConfig() 126 : ConfigLevelBase() 127 { 128 } 129 130 void initFromXml(xml::ElementNode const *pElm, bool fStrict) RT_OVERRIDE; 131 const char *getType() const RT_NOEXCEPT RT_OVERRIDE { return "group"; } 132 const char *getName() const RT_NOEXCEPT RT_OVERRIDE { return m_strName.c_str(); } 133 134 /** @name Accessors 135 * @{ */ 136 RTCString const &getGroupName() const RT_NOEXCEPT { return m_strName; } 137 /** @} */ 138 139 protected: 140 void i_parseChild(const xml::ElementNode *pElmChild, bool fStrict) RT_OVERRIDE; 141 /** Used to name unnamed groups. */ 142 static uint32_t s_uGroupNo; 143 }; 144 145 146 /** 147 * Host (MAC address) specific configuration. 148 */ 149 class HostConfig : public ConfigLevelBase 150 { 151 protected: 152 /** The MAC address. */ 153 RTMAC m_MACAddress; 154 /** Name annotating the entry. */ 155 RTCString m_strName; 156 /** Fixed address assignment when m_fHaveFixedAddress is true. */ 157 RTNETADDRIPV4 m_FixedAddress; 158 /** Set if we have a fixed address asignment. */ 159 bool m_fHaveFixedAddress; 160 161 public: 162 HostConfig() 163 : ConfigLevelBase() 164 , m_fHaveFixedAddress(false) 165 { 166 RT_ZERO(m_MACAddress); 167 RT_ZERO(m_FixedAddress); 168 } 169 170 void initFromXml(xml::ElementNode const *pElm, bool fStrict) RT_OVERRIDE; 171 const char *getType() const RT_NOEXCEPT RT_OVERRIDE { return "host"; } 172 const char *getName() const RT_NOEXCEPT RT_OVERRIDE { return m_strName.c_str(); } 173 174 /** @name Accessors 175 * @{ */ 176 RTMAC const &getMACAddress() const RT_NOEXCEPT { return m_MACAddress; } 177 /** @} */ 178 }; 179 180 181 /** 37 182 * DHCP server configuration. 38 183 */ 39 184 class Config 40 185 { 41 /** @todo XXX: also store fixed address assignments, etc? */ 42 typedef std::map<RTMAC, optmap_t> vmmap_t; 186 /** Group configuration map. */ 187 typedef std::map<RTCString, GroupConfig * > GroupConfigMap; 188 /** Host configuration map. */ 189 typedef std::map<RTMAC, HostConfig * > HostConfigMap; 190 43 191 44 192 RTCString m_strHome; /**< path of ~/.VirtualBox or equivalent, */ … … 59 207 60 208 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. */ 209 /** The global configuration. */ 210 GlobalConfig m_GlobalConfig; 211 /** The group configurations, indexed by group name. */ 212 GroupConfigMap m_GroupConfigs; 213 /** The host configurations, indexed by MAC address. */ 214 HostConfigMap m_HostConfigs; 70 215 71 216 /** Set if we've initialized the log already (via command line). */ … … 109 254 /** @} */ 110 255 111 optmap_t &getOptions(optmap_t &a_rRetOpts, const OptParameterRequest &reqOpts, const ClientId &id, 112 const OptVendorClassId &idVendorClass = OptVendorClassId(), 113 const OptUserClassId &idUserClass = OptUserClassId()) const; 256 /** Configuration vector. */ 257 typedef std::vector<ConfigLevelBase const *> ConfigVec; 258 ConfigVec &getConfigsForClient(ConfigVec &a_rRetConfigs, const ClientId &a_ridClient, 259 const OptVendorClassId &a_ridVendorClass, 260 const OptUserClassId &a_ridUserClass) const; 261 optmap_t &getOptionsForClient(optmap_t &a_rRetOpts, const OptParameterRequest &a_rReqOpts, 262 ConfigVec &a_rConfigs) const; 114 263 115 264 private: 116 265 /** @name Configuration file reading and parsing 117 266 * @{ */ 118 static Config *i_read(const char *pszFileName) RT_NOEXCEPT; 119 void i_parseConfig(const xml::ElementNode *root); 120 void i_parseServer(const xml::ElementNode *server); 121 void i_parseGlobalOptions(const xml::ElementNode *options); 122 void i_parseVMConfig(const xml::ElementNode *config); 123 void i_parseOption(const xml::ElementNode *option, optmap_t &optmap); 124 125 static void i_getIPv4AddrAttribute(const xml::ElementNode *pElm, const char *pcszAttrName, PRTNETADDRIPV4 pAddr); 126 static void i_getMacAddressAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTMAC pMacAddr); 267 static Config *i_read(const char *pszFilename, bool fStrict) RT_NOEXCEPT; 268 void i_parseConfig(const xml::ElementNode *pElmRoot, bool fStrict); 269 void i_parseServer(const xml::ElementNode *pElmServer, bool fStrict); 127 270 /** @} */ 128 271 }; -
trunk/src/VBox/NetworkServices/Dhcpd/DHCPD.cpp
r79622 r79800 242 242 return NULL; 243 243 244 Config::ConfigVec vecConfigs; 245 m_pConfig->getConfigsForClient(vecConfigs, req.clientId(), OptVendorClassId(req), OptUserClassId(req)); 246 244 247 Binding *b = m_db.allocateBinding(req); 245 248 if (b == NULL) … … 270 273 reply->addOption(OptLeaseTime(b->leaseTime())); 271 274 272 273 275 OptParameterRequest optlist(req); 274 276 optmap_t replyOptions; 275 reply->addOptions(m_pConfig->getOptions (replyOptions, optlist, req.clientId()));277 reply->addOptions(m_pConfig->getOptionsForClient(replyOptions, optlist, vecConfigs)); 276 278 277 279 // reply->maybeUnicast(req); /** @todo XXX: we reject ciaddr != 0 above */ … … 307 309 } 308 310 311 Config::ConfigVec vecConfigs; 312 m_pConfig->getConfigsForClient(vecConfigs, req.clientId(), OptVendorClassId(req), OptUserClassId(req)); 309 313 310 314 Binding *b = m_db.allocateBinding(req); … … 314 318 } 315 319 316 317 320 std::unique_ptr<DhcpServerMessage> ack(i_createMessage(RTNET_DHCP_MT_ACK, req)); 318 321 … … 325 328 OptParameterRequest optlist(req); 326 329 optmap_t replyOptions; 327 ack->addOptions(m_pConfig->getOptions (replyOptions, optlist, req.clientId()));330 ack->addOptions(m_pConfig->getOptionsForClient(replyOptions, optlist, vecConfigs)); 328 331 329 332 /** @todo r=bird: Sec 9.9 in rfc-2132 indicates the server only sends this in NACKs. Test code? */ … … 351 354 return NULL; 352 355 353 const OptParameterRequest params(req); 354 if (!params.present()) 355 return NULL; 356 356 OptParameterRequest optlist(req); 357 if (!optlist.present()) 358 return NULL; 359 360 Config::ConfigVec vecConfigs; 357 361 optmap_t info; 358 m_pConfig->getOptions(info, params, req.clientId()); 362 m_pConfig->getOptionsForClient(info, optlist, m_pConfig->getConfigsForClient(vecConfigs, req.clientId(), 363 OptVendorClassId(req), OptUserClassId(req))); 359 364 if (info.empty()) 360 365 return NULL;
Note:
See TracChangeset
for help on using the changeset viewer.