end, expected_type, encapsulates);
}
- /// @brief Create a sample DHCPv4 option 43 with suboptions.
- static OptionBuffer createVendorOption() {
- const uint8_t opt_data[] = {
- 0x2B, 0x0D, // Vendor-Specific Information (CableLabs)
- // Suboptions start here...
- 0x02, 0x05, // Device Type Option (length = 5)
- 'D', 'u', 'm', 'm', 'y',
- 0x04, 0x04, // Serial Number Option (length = 4)
- 0x42, 0x52, 0x32, 0x32 // Serial number
- };
- return (OptionBuffer(opt_data, opt_data + sizeof(opt_data)));
- }
-
/// @brief Create a sample DHCPv4 option 82 with suboptions.
static OptionBuffer createAgentInformationOption() {
const uint8_t opt_data[] = {
ASSERT_EQ(1, addresses.size());
EXPECT_EQ("10.0.0.10", addresses[0].toText());
-#if 0
- // Vendor Specific Information option
- x = options.find(43);
- ASSERT_FALSE(x == options.end());
- OptionPtr vsi = x->second;
- ASSERT_TRUE(vsi);
- EXPECT_EQ(DHO_VENDOR_ENCAPSULATED_OPTIONS, vsi->getType());
- suboptions = vsi->getOptions();
-
- // There should be one suboption of VSI.
- ASSERT_EQ(1, suboptions.size());
- OptionPtr eso = suboptions.begin()->second;
- ASSERT_TRUE(eso);
- EXPECT_EQ(0xdc, eso->getType());
- EXPECT_EQ(2, eso->len());
-#endif
-
// Checking DHCP Relay Agent Information Option.
x = options.find(DHO_DHCP_AGENT_OPTIONS);
ASSERT_FALSE(x == options.end());
LibDhcpTest::testStdOptionDefs4(DHO_NTP_SERVERS, begin, end,
typeid(Option4AddrLst));
-#if 0
- // The following option requires well formed buffer to be created from.
- // Not just a dummy one. This buffer includes some suboptions.
- OptionBuffer vendor_opts_buf = createVendorOption();
- LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_ENCAPSULATED_OPTIONS,
- vendor_opts_buf.begin(),
- vendor_opts_buf.end(),
- typeid(OptionCustom),
- "vendor-encapsulated-options-space");
-#endif
-
LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end,
typeid(Option4AddrLst));
testRuntimeOptionDefs(5, 100, false);
}
+// This test verifies the processing of option 43
+TEST_F(LibDhcpTest, option43) {
+ // Check deferOption()
+ EXPECT_TRUE(LibDHCP::deferOption(DHCP4_OPTION_SPACE, 43));
+ EXPECT_FALSE(LibDHCP::deferOption(DHCP4_OPTION_SPACE, 44));
+ EXPECT_FALSE(LibDHCP::deferOption(DHCP6_OPTION_SPACE, 43));
+
+ // Check last resort
+ OptionDefinitionPtr def;
+ def = LibDHCP::getLastResortOptionDef(DHCP6_OPTION_SPACE, 43);
+ EXPECT_FALSE(def);
+ def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 44);
+ EXPECT_FALSE(def);
+ def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 43);
+ ASSERT_TRUE(def);
+ EXPECT_FALSE(def->getArrayType());
+ EXPECT_EQ(43, def->getCode());
+ EXPECT_EQ("vendor-encapsulated-options-space", def->getEncapsulatedSpace());
+ EXPECT_EQ("vendor-encapsulated-options", def->getName());
+ EXPECT_EQ(0, def->getRecordFields().size());
+ EXPECT_EQ(OptionDataType::OPT_EMPTY_TYPE, def->getType());
+
+ OptionDefinitionPtr def_by_name =
+ LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE,
+ "vendor-encapsulated-options");
+ EXPECT_TRUE(def_by_name);
+ EXPECT_EQ(def, def_by_name);
+}
+
} // end of anonymous space
#include <dhcpsrv/parsers/dhcp_parsers.h>
#include <dhcpsrv/parsers/client_class_def_parser.h>
#include <dhcpsrv/parsers/option_data_parser.h>
+#include <dhcpsrv/parsers/simple_parser4.h>
+#include <dhcpsrv/parsers/simple_parser6.h>
#include <eval/eval_context.h>
#include <asiolink/io_address.h>
#include <asiolink/io_error.h>
CfgOptionDefPtr defs(new CfgOptionDef());
ConstElementPtr option_defs = class_def_cfg->get("option-def");
if (option_defs) {
+ // Apply defaults
+ SimpleParser::setListDefaults(option_defs,
+ family == AF_INET ?
+ SimpleParser4::OPTION4_DEF_DEFAULTS :
+ SimpleParser6::OPTION6_DEF_DEFAULTS);
+
OptionDefParser parser;
BOOST_FOREACH(ConstElementPtr option_def, option_defs->listValue()) {
OptionDefinitionTuple def;
DhcpConfigError);
}
+// Verifies that a class with invalid option-def, fails to parse.
+TEST_F(ClientClassDefParserTest, invalidOptionDef) {
+ std::string cfg_text =
+ "{ \n"
+ " \"name\": \"one\", \n"
+ " \"option-def\": [ \n"
+ " { \"bogus\": \"bad\" } \n"
+ " ] \n"
+ "} \n";
+
+ ClientClassDefPtr cclass;
+ ASSERT_THROW(cclass = parseClientClassDef(cfg_text, AF_INET),
+ DhcpConfigError);
+}
+
// Verifies that a class with invalid option-data, fails to parse.
TEST_F(ClientClassDefParserTest, invalidOptionData) {
std::string cfg_text =
EXPECT_EQ(IOAddress("0.0.0.0"), cclass->getNextServer());
EXPECT_EQ(0, cclass->getSname().size());
EXPECT_EQ(0, cclass->getFilename().size());
+
+ // Nor option definitions
+ CfgOptionDefPtr cfg = cclass->getCfgOptionDef();
+ ASSERT_TRUE(cfg->getAll(DHCP4_OPTION_SPACE)->empty());
+}
+
+// Test verifies option-def for a bad option fails to parse.
+TEST_F(ClientClassDefParserTest, badOptionDef) {
+ std::string cfg_text =
+ "{ \n"
+ " \"name\": \"MICROSOFT\", \n"
+ " \"option-def\": [ \n"
+ " { \n"
+ " \"name\": \"foo\", \n"
+ " \"code\": 222, \n"
+ " \"type\": \"uint32\" \n"
+ " } \n"
+ " ] \n"
+ "} \n";
+
+ ClientClassDefPtr cclass;
+ ASSERT_THROW(cclass = parseClientClassDef(cfg_text, AF_INET),
+ DhcpConfigError);
+}
+
+// Test verifies option-def works for private options (224-254).
+TEST_F(ClientClassDefParserTest, privateOptionDef) {
+ std::string cfg_text =
+ "{ \n"
+ " \"name\": \"MICROSOFT\", \n"
+ " \"option-def\": [ \n"
+ " { \n"
+ " \"name\": \"foo\", \n"
+ " \"code\": 232, \n"
+ " \"type\": \"uint32\" \n"
+ " } \n"
+ " ] \n"
+ "} \n";
+
+ ClientClassDefPtr cclass;
+ ASSERT_NO_THROW(cclass = parseClientClassDef(cfg_text, AF_INET));
+
+ // We should find our class.
+ ASSERT_TRUE(cclass);
+
+ // And the option definition.
+ CfgOptionDefPtr cfg = cclass->getCfgOptionDef();
+ ASSERT_TRUE(cfg);
+ EXPECT_TRUE(cfg->get(DHCP4_OPTION_SPACE, 232));
+ EXPECT_FALSE(cfg->get(DHCP6_OPTION_SPACE, 232));
+ EXPECT_FALSE(cfg->get(DHCP4_OPTION_SPACE, 233));
}
+// Test verifies option-def works for option 43.
+TEST_F(ClientClassDefParserTest, option43Def) {
+ std::string cfg_text =
+ "{ \n"
+ " \"name\": \"MICROSOFT\", \n"
+ " \"test\": \"option[60].text == 'MICROSOFT'\", \n"
+ " \"option-def\": [ \n"
+ " { \n"
+ " \"name\": \"vendor-encapsulated-options\", \n"
+ " \"code\": 43, \n"
+ " \"space\": \"dhcp4\", \n"
+ " \"type\": \"empty\", \n"
+ " \"encapsulate\": \"vsi\" \n"
+ " } \n"
+ " ], \n"
+ " \"option-data\": [ \n"
+ " { \n"
+ " \"name\": \"vendor-encapsulated-options\" \n"
+ " }, \n"
+ " { \n"
+ " \"code\": 1, \n"
+ " \"space\": \"vsi\", \n"
+ " \"csv-format\": false, \n"
+ " \"data\": \"C0000200\" \n"
+ " } \n"
+ " ] \n"
+ "} \n";
+
+ ClientClassDefPtr cclass;
+ ASSERT_NO_THROW(cclass = parseClientClassDef(cfg_text, AF_INET));
+
+ // We should find our class.
+ ASSERT_TRUE(cclass);
+
+ // And the option definition.
+ CfgOptionDefPtr cfg_def = cclass->getCfgOptionDef();
+ ASSERT_TRUE(cfg_def);
+ EXPECT_TRUE(cfg_def->get(DHCP4_OPTION_SPACE, 43));
+
+ // Verify the option data.
+ OptionDescriptor od = cclass->getCfgOption()->get(DHCP4_OPTION_SPACE, 43);
+ ASSERT_TRUE(od.option_);
+ EXPECT_EQ(43, od.option_->getType());
+ const OptionCollection& oc = od.option_->getOptions();
+ ASSERT_EQ(1, oc.size());
+ OptionPtr opt = od.option_->getOption(1);
+ ASSERT_TRUE(opt);
+ EXPECT_EQ(1, opt->getType());
+ ASSERT_EQ(4, opt->getData().size());
+ const uint8_t expected[4] = { 0xc0, 0x00, 0x02, 0x00 };
+ EXPECT_EQ(0, std::memcmp(expected, &opt->getData()[0], 4));
+}
+
+
// Test verifies that it is possible to define next-server field and it
// is actually set in the class properly.
TEST_F(ClientClassDefParserTest, nextServer) {
#include <config.h>
#include <dhcpsrv/client_class_def.h>
#include <dhcpsrv/cfgmgr.h>
+#include <dhcp/libdhcp++.h>
#include <dhcp/option_space.h>
#include <testutils/test_to_element.h>
#include <exceptions/exceptions.h>
ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr)));
EXPECT_EQ(name, cclass->getName());
ASSERT_FALSE(cclass->getMatchExpr());
+ EXPECT_FALSE(cclass->getCfgOptionDef());
// Verify we get an empty collection of cfg_option
cfg_option = cclass->getCfgOption();
EXPECT_FALSE(*cclass == *cclass2);
EXPECT_TRUE(*cclass != *cclass2);
+ // Make a class that with same name, expression and options, but
+ // different option definitions, verify that the equality tools reflect
+ // that the equality tools reflect that the classes are not equal.
+ ASSERT_NO_THROW(cclass2.reset(new ClientClassDef(*cclass)));
+ EXPECT_TRUE(cclass->equals(*cclass2));
+ OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE, 43);
+ EXPECT_FALSE(def);
+ def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 43);
+ EXPECT_TRUE(def);
+ CfgOptionDefPtr cfg(new CfgOptionDef());
+ ASSERT_NO_THROW(cfg->add(def, DHCP4_OPTION_SPACE));
+ cclass2->setCfgOptionDef(cfg);
+ EXPECT_FALSE(cclass->equals(*cclass2));
+ EXPECT_FALSE(*cclass == *cclass2);
+ EXPECT_TRUE(*cclass != *cclass2);
+
// Make a class with same name and expression, but no options
// verify that the equality tools reflect that the classes are not equal.
test_options.reset(new CfgOption());
ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr)));
// Let's checks that it doesn't return any nonsense
+ EXPECT_FALSE(cclass->getCfgOptionDef());
string empty;
ASSERT_EQ(IOAddress("0.0.0.0"), cclass->getNextServer());
EXPECT_EQ(empty, cclass->getSname());