From: Francis Dupont Date: Thu, 11 Apr 2019 10:04:16 +0000 (+0200) Subject: [564-customer-request-relax-constraints-on-allowable-option-types-to-permit-option... X-Git-Tag: Kea-1.6.0-beta~231^2~2 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=16faf810158d115da1abca46ec7316639347e931;p=thirdparty%2Fkea.git [564-customer-request-relax-constraints-on-allowable-option-types-to-permit-option-type-0-and-255] Added tests including the ZTP one --- diff --git a/src/bin/dhcp4/tests/vendor_opts_unittest.cc b/src/bin/dhcp4/tests/vendor_opts_unittest.cc index fed81ec34f..2f94205a71 100644 --- a/src/bin/dhcp4/tests/vendor_opts_unittest.cc +++ b/src/bin/dhcp4/tests/vendor_opts_unittest.cc @@ -1499,3 +1499,129 @@ TEST_F(Dhcpv4SrvTest, truncatedVIVSOOption) { Pkt4Ptr offer = srv.fake_sent_.front(); ASSERT_TRUE(offer); } + +/// Checks that it's possible to define and use a suboption 0. +TEST_F(VendorOptsTest, vendorOpsSubOption0) { + IfaceMgrTestConfig test_config(true); + IfaceMgr::instance().openSockets4(); + + NakedDhcpv4Srv srv(0); + + // Zero Touch provisioning + string config = + "{" + " \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + " }," + " \"option-def\": [" + " {" + " \"name\": \"vendor-encapsulated-options\"," + " \"code\": 43," + " \"type\": \"empty\"," + " \"encapsulate\": \"ZTP\"" + " }," + " {" + " \"name\": \"config-file-name\"," + " \"code\": 1," + " \"space\": \"ZTP\"," + " \"type\": \"string\"" + " }," + " {" + " \"name\": \"image-file-name\"," + " \"code\": 0," + " \"space\": \"ZTP\"," + " \"type\": \"string\"" + " }," + " {" + " \"name\": \"image-file-type\"," + " \"code\": 2," + " \"space\": \"ZTP\"," + " \"type\": \"string\"" + " }," + " {" + " \"name\": \"transfer-mode\"," + " \"code\": 3," + " \"space\": \"ZTP\"," + " \"type\": \"string\"" + " }," + " {" + " \"name\": \"all-image-file-name\"," + " \"code\": 4," + " \"space\": \"ZTP\"," + " \"type\": \"string\"" + " }," + " {" + " \"name\": \"http-port\"," + " \"code\": 5," + " \"space\": \"ZTP\"," + " \"type\": \"string\"" + " }" + " ]," + " \"option-data\": [" + " {" + " \"name\": \"vendor-encapsulated-options\"" + " }," + " {" + " \"name\": \"image-file-name\"," + " \"data\": \"/dist/images/jinstall-ex.tgz\"," + " \"space\": \"ZTP\"" + " }" + " ]," + "\"subnet4\": [ { " + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," + " \"subnet\": \"192.0.2.0/24\"" + " } ]" + "}"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP4(config, true)); + ConstElementPtr status; + + // Configure the server and make sure the config is accepted + EXPECT_NO_THROW(status = configureDhcp4Server(srv, json)); + ASSERT_TRUE(status); + comment_ = parseAnswer(rcode_, status); + ASSERT_EQ(0, rcode_); + + CfgMgr::instance().commit(); + + // Create a packet with enough to select the subnet and go through + // the DISCOVER processing + Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 1234)); + query->setRemoteAddr(IOAddress("192.0.2.1")); + OptionPtr clientid = generateClientId(); + query->addOption(clientid); + query->setIface("eth1"); + + // Create and add a PRL option to the query + OptionUint8ArrayPtr prl(new OptionUint8Array(Option::V4, + DHO_DHCP_PARAMETER_REQUEST_LIST)); + ASSERT_TRUE(prl); + prl->addValue(DHO_VENDOR_ENCAPSULATED_OPTIONS); + prl->addValue(DHO_VENDOR_CLASS_IDENTIFIER); + query->addOption(prl); + + srv.classifyPacket(query); + ASSERT_NO_THROW(srv.deferredUnpack(query)); + + // Pass it to the server and get an offer + Pkt4Ptr offer = srv.processDiscover(query); + + // Check if we get response at all + checkResponse(offer, DHCPOFFER, 1234); + + // Processing should add a vendor-encapsulated-options (code 43) + OptionPtr opt = offer->getOption(DHO_VENDOR_ENCAPSULATED_OPTIONS); + ASSERT_TRUE(opt); + const OptionCollection& opts = opt->getOptions(); + ASSERT_EQ(1, opts.size()); + OptionPtr sopt = opts.begin()->second; + ASSERT_TRUE(sopt); + EXPECT_EQ(0, sopt->getType()); + + // Check suboption 0 content. + OptionStringPtr sopt0 = + boost::dynamic_pointer_cast(sopt); + ASSERT_TRUE(sopt0); + EXPECT_EQ("/dist/images/jinstall-ex.tgz", sopt0->getValue()); +} diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc index 90471943e2..64ce61def9 100644 --- a/src/lib/dhcp/tests/libdhcp++_unittest.cc +++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc @@ -1055,7 +1055,9 @@ TEST_F(LibDhcpTest, unpackPadEnd) { // Suboption 1. 0x01, 0x03, 0x66, 0x6f, 0x6f, // code = 1, length = 2, content = "foo" // END - 0xff + 0xff, + // Extra bytes at tail. + 0x01, 0x02, 0x03, 0x04 }; size_t raw_data_len = sizeof(raw_data) / sizeof(uint8_t); OptionBuffer buf(raw_data, raw_data + raw_data_len); @@ -1063,8 +1065,12 @@ TEST_F(LibDhcpTest, unpackPadEnd) { // Parse options. OptionCollection options; list deferred; - ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, DHCP4_OPTION_SPACE, - options, deferred)); + size_t offset = 0; + ASSERT_NO_THROW(offset = LibDHCP::unpackOptions4(buf, DHCP4_OPTION_SPACE, + options, deferred)); + + // Returned offset should point to the END. + EXPECT_EQ(0xff, raw_data[offset]); // There should be one top level option. ASSERT_EQ(1, options.size()); diff --git a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc index 94ba6c0da3..57f2171113 100644 --- a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc +++ b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc @@ -723,7 +723,6 @@ TEST_F(ParseConfigTest, defaultSpaceOptionDefTest) { TEST_F(ParseConfigTest, badCodeOptionDefTest) { { - SCOPED_TRACE("negative code"); std::string config = "{ \"option-def\": [ {" @@ -769,6 +768,56 @@ TEST_F(ParseConfigTest, badCodeOptionDefTest) { int rcode = parseConfiguration(config, false); ASSERT_NE(0, rcode); } + + { + SCOPED_TRACE("conflict with PAD"); + family_ = AF_INET; // Switch to DHCPv4. + + std::string config = + "{ \"option-def\": [ {" + " \"name\": \"zero\"," + " \"code\": 0," + " \"type\": \"ip-address\"," + " \"space\": \"dhcp4\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, false); + ASSERT_NE(0, rcode); + } + + { + SCOPED_TRACE("conflict with END"); + family_ = AF_INET; // Switch to DHCPv4. + + std::string config = + "{ \"option-def\": [ {" + " \"name\": \"max\"," + " \"code\": 255," + " \"type\": \"ip-address\"," + " \"space\": \"dhcp4\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, false); + ASSERT_NE(0, rcode); + } + + { + SCOPED_TRACE("conflict with reserved"); + + std::string config = + "{ \"option-def\": [ {" + " \"name\": \"zero\"," + " \"code\": 0," + " \"type\": \"ipv6-address\"," + " \"space\": \"dhcp6\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, false); + ASSERT_NE(0, rcode); + } } /// @brief Check parsing of option definitions using invalid space fails. @@ -968,6 +1017,105 @@ TEST_F(ParseConfigTest, unknownOptionDataTest) { ASSERT_NE(0, rcode); } +/// @brief Check parsing of option data using invalid code fails. +TEST_F(ParseConfigTest, badCodeOptionDataTest) { + + { + SCOPED_TRACE("negative code"); + std::string config = + "{ \"option-data\": [ {" + " \"code\": -1," + " \"data\": \"01\"," + " \"space\": \"isc\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, true); + ASSERT_NE(0, rcode); + } + + { + SCOPED_TRACE("out of range code (v6)"); + std::string config = + "{ \"option-data\": [ {" + " \"code\": 100000," + " \"data\": \"01\"," + " \"space\": \"isc\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, true); + ASSERT_NE(0, rcode); + } + + { + SCOPED_TRACE("out of range code (v4)"); + family_ = AF_INET; // Switch to DHCPv4. + + std::string config = + "{ \"option-data\": [ {" + " \"code\": 1000," + " \"data\": \"01\"," + " \"space\": \"isc\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, false); + ASSERT_NE(0, rcode); + } + + { + SCOPED_TRACE("conflict with PAD"); + family_ = AF_INET; // Switch to DHCPv4. + + std::string config = + "{ \"option-data\": [ {" + " \"code\": 0," + " \"data\": \"01\"," + " \"csv-format\": false," + " \"space\": \"dhcp4\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, false); + ASSERT_NE(0, rcode); + } + + { + SCOPED_TRACE("conflict with END"); + family_ = AF_INET; // Switch to DHCPv4. + + std::string config = + "{ \"option-data\": [ {" + " \"code\": 255," + " \"data\": \"01\"," + " \"csv-format\": false," + " \"space\": \"dhcp4\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, false); + ASSERT_NE(0, rcode); + } + + { + SCOPED_TRACE("conflict with reserved"); + family_ = AF_INET6; // Switch to DHCPv6. + + std::string config = + "{ \"option-data\": [ {" + " \"code\": 0," + " \"data\": \"01\"," + " \"csv-format\": false," + " \"space\": \"dhcp6\"" + " } ]" + "}"; + + int rcode = parseConfiguration(config, false); + ASSERT_NE(0, rcode); + } +} + /// @brief Check parsing of options with invalid space fails. TEST_F(ParseConfigTest, badSpaceOptionDataTest) {