]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[564-customer-request-relax-constraints-on-allowable-option-types-to-permit-option...
authorFrancis Dupont <fdupont@isc.org>
Wed, 10 Apr 2019 21:05:24 +0000 (23:05 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 18 Apr 2019 14:48:12 +0000 (16:48 +0200)
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp6/tests/config_parser_unittest.cc
src/lib/dhcp/tests/libdhcp++_unittest.cc
src/lib/dhcp/tests/option_unittest.cc
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

index d492e43fb061d411dd8f02b820d37d92d6ba6b7b..7c035595bb468ef476cf1075e4bb9236c5d755c8 100644 (file)
@@ -3351,7 +3351,7 @@ TEST_F(Dhcp4ParserTest, optionCodeNonUint8) {
 }
 
 // Verify that zero option code is rejected in the configuration.
-TEST_F(Dhcp4ParserTest, optionCodeZero) {
+TEST_F(Dhcp4ParserTest, DISABLED_optionCodeZero) {
     // Option code 0 is reserved and should not be accepted
     // by configuration parser.
     testInvalidOptionParam("0", "code");
index 64e1c95f268f7ae1dfb76682c275a21ba369f148..5458e4f41b0ca5c75ab00516fe24c727e1334141 100644 (file)
@@ -3555,7 +3555,7 @@ TEST_F(Dhcp6ParserTest, optionCodeHighNonUint16) {
 }
 
 // Verify that zero option code is rejected in the configuration.
-TEST_F(Dhcp6ParserTest, optionCodeZero) {
+TEST_F(Dhcp6ParserTest, DISABLED_optionCodeZero) {
     // Option code 0 is reserved and should not be accepted
     // by configuration parser.
     testInvalidOptionParam("0", "code");
index 43f64e7bbe7915dd7934a1f3051cd9648b655ba1..90471943e2d24b22c9680227ff7baa63342651bf 100644 (file)
@@ -1016,6 +1016,91 @@ TEST_F(LibDhcpTest, unpackSubOptions4) {
     EXPECT_EQ(0x0, option_bar->getValue());
 }
 
+// Verifies that options 0 (PAD) and 255 (END) are handled as PAD and END
+// in and only in the dhcp4 space.
+TEST_F(LibDhcpTest, unpackPadEnd) {
+    // Create option definition for the container.
+    OptionDefinitionPtr opt_def(new OptionDefinition("container", 200,
+                                                     "empty", "my-space"));
+    // Create option definition for option 0.
+    OptionDefinitionPtr opt_def0(new OptionDefinition("zero", 0, "uint8"));
+
+    // Create option definition for option 255.
+    OptionDefinitionPtr opt_def255(new OptionDefinition("max", 255, "uint8"));
+
+    // Create option definition for another option.
+    OptionDefinitionPtr opt_def2(new OptionDefinition("my-option", 1,
+                                                      "string"));
+
+    // Register created option definitions as runtime option definitions.
+    OptionDefSpaceContainer defs;
+    ASSERT_NO_THROW(defs.addItem(opt_def, DHCP4_OPTION_SPACE));
+    ASSERT_NO_THROW(defs.addItem(opt_def0, "my-space"));
+    ASSERT_NO_THROW(defs.addItem(opt_def255, "my-space"));
+    ASSERT_NO_THROW(defs.addItem(opt_def2, "my-space"));
+    LibDHCP::setRuntimeOptionDefs(defs);
+    LibDHCP::commitRuntimeOptionDefs();
+
+    // Create the buffer holding the structure of options.
+    const uint8_t raw_data[] = {
+        // Add a PAD
+        0x00,                         // option code = 0 (PAD)
+        // Container option starts here.
+        0xc8,                         // option code = 200 (container)
+        0x0b,                         // option length = 11
+        // Suboption 0.
+        0x00, 0x01, 0x00,             // code = 0, length = 1, content = 0
+        // Suboption 255.
+        0xff, 0x01, 0xff,             // code = 255, length = 1, content = 255
+        // Suboption 1.
+        0x01, 0x03, 0x66, 0x6f, 0x6f, // code = 1, length = 2, content = "foo"
+        // END
+        0xff
+    };
+    size_t raw_data_len = sizeof(raw_data) / sizeof(uint8_t);
+    OptionBuffer buf(raw_data, raw_data + raw_data_len);
+
+    // Parse options.
+    OptionCollection options;
+    list<uint16_t> deferred;
+    ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, DHCP4_OPTION_SPACE,
+                                            options, deferred));
+
+    // There should be one top level option.
+    ASSERT_EQ(1, options.size());
+
+    // Get it.
+    OptionPtr option = options.begin()->second;
+    ASSERT_TRUE(option);
+    EXPECT_EQ(200, option->getType());
+
+    // There should be 3 suboptions.
+    EXPECT_EQ(3, option->getOptions().size());
+
+    // Get suboption 0.
+    boost::shared_ptr<OptionInt<uint8_t> > sub0 =
+        boost::dynamic_pointer_cast<OptionInt<uint8_t> >
+            (option->getOption(0));
+    ASSERT_TRUE(sub0);
+    EXPECT_EQ(0, sub0->getType());
+    EXPECT_EQ(0, sub0->getValue());
+
+    // Get suboption 255.
+    boost::shared_ptr<OptionInt<uint8_t> > sub255 =
+        boost::dynamic_pointer_cast<OptionInt<uint8_t> >
+            (option->getOption(255));
+    ASSERT_TRUE(sub255);
+    EXPECT_EQ(255, sub255->getType());
+    EXPECT_EQ(255, sub255->getValue());
+
+    // Get suboption 1.
+    boost::shared_ptr<OptionString> sub =
+        boost::dynamic_pointer_cast<OptionString>(option->getOption(1));
+    ASSERT_TRUE(sub);
+    EXPECT_EQ(1, sub->getType());
+    EXPECT_EQ("foo", sub->getValue());
+}
+
 // Verifies that an Host Name (option 12), will be dropped when empty,
 // while subsequent options will still be unpacked.
 TEST_F(LibDhcpTest, emptyHostName) {
index a86a26d8821d645eb621aa105f62075fd2988ac2..62a69c5a88684cdcf9733fcc9de2486d49a33ada 100644 (file)
@@ -71,6 +71,10 @@ TEST_F(OptionTest, v4_basic) {
 
     // V4 options have type 0...255
     EXPECT_THROW(opt.reset(new Option(Option::V4, 256)), OutOfRange);
+
+    // 0 / PAD and 255 / END are no longer forbidden
+    EXPECT_NO_THROW(opt.reset(new Option(Option::V4, 0)));
+    EXPECT_NO_THROW(opt.reset(new Option(Option::V4, 255)));
 }
 
 const uint8_t dummyPayload[] =
index 1909d4157fa81c84ff81da94f422f020f06a6460..94ba6c0da32f2ae6f31b297d5c906bca6485647d 100644 (file)
@@ -833,6 +833,84 @@ TEST_F(ParseConfigTest, basicOptionDataTest) {
     cfg.runCfgOptionsTest(family_, config);
 }
 
+/// @brief Check parsing of options with code 0.
+TEST_F(ParseConfigTest, optionDataTest0) {
+
+    // Configuration string.
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 0,"
+        "      \"type\": \"ipv4-address\","
+        "      \"space\": \"isc\""
+        " } ], "
+        " \"option-data\": [ {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"isc\","
+        "    \"code\": 0,"
+        "    \"data\": \"192.0.2.0\","
+        "    \"csv-format\": true,"
+        "    \"always-send\": false"
+        " } ]"
+        "}";
+
+    // Verify that the configuration string parses.
+    int rcode = parseConfiguration(config);
+    ASSERT_EQ(0, rcode);
+
+    // Verify that the option can be retrieved.
+    OptionPtr opt_ptr = getOptionPtr("isc", 0);
+    ASSERT_TRUE(opt_ptr);
+
+    // Verify that the option data is correct.
+    std::string val = "type=00000, len=00004: 192.0.2.0 (ipv4-address)";
+
+    EXPECT_EQ(val, opt_ptr->toText());
+
+    // Check if it can be unparsed.
+    CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+    cfg.runCfgOptionsTest(family_, config);
+}
+
+/// @brief Check parsing of options with code 255.
+TEST_F(ParseConfigTest, optionDataTest255) {
+
+    // Configuration string.
+    std::string config =
+        "{ \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 255,"
+        "      \"type\": \"ipv4-address\","
+        "      \"space\": \"isc\""
+        " } ], "
+        " \"option-data\": [ {"
+        "    \"name\": \"foo\","
+        "    \"space\": \"isc\","
+        "    \"code\": 255,"
+        "    \"data\": \"192.0.2.0\","
+        "    \"csv-format\": true,"
+        "    \"always-send\": false"
+        " } ]"
+        "}";
+
+    // Verify that the configuration string parses.
+    int rcode = parseConfiguration(config);
+    ASSERT_EQ(0, rcode);
+
+    // Verify that the option can be retrieved.
+    OptionPtr opt_ptr = getOptionPtr("isc", 255);
+    ASSERT_TRUE(opt_ptr);
+
+    // Verify that the option data is correct.
+    std::string val = "type=00255, len=00004: 192.0.2.0 (ipv4-address)";
+
+    EXPECT_EQ(val, opt_ptr->toText());
+
+    // Check if it can be unparsed.
+    CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+    cfg.runCfgOptionsTest(family_, config);
+}
+
 /// @brief Check minimal parsing of options.
 ///
 /// Same than basic but without optional parameters set to their default.