]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[3705] Address review comments.
authorMarcin Siodelski <marcin@isc.org>
Tue, 17 Mar 2015 09:14:46 +0000 (10:14 +0100)
committerMarcin Siodelski <marcin@isc.org>
Tue, 17 Mar 2015 09:14:46 +0000 (10:14 +0100)
18 files changed:
doc/guide/dhcp6-srv.xml
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/json_config_parser.cc
src/bin/dhcp6/tests/config_parser_unittest.cc
src/bin/dhcp6/tests/dhcp6_client.h
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/lib/dhcp/std_option_defs.h
src/lib/dhcp/tests/pkt_captures6.cc
src/lib/dhcpsrv/Makefile.am
src/lib/dhcpsrv/cfg_option.cc
src/lib/dhcpsrv/cfg_option.h
src/lib/dhcpsrv/cfg_rsoo.cc [new file with mode: 0644]
src/lib/dhcpsrv/cfg_rsoo.h [new file with mode: 0644]
src/lib/dhcpsrv/srv_config.cc
src/lib/dhcpsrv/srv_config.h
src/lib/dhcpsrv/tests/Makefile.am
src/lib/dhcpsrv/tests/cfg_option_unittest.cc
src/lib/dhcpsrv/tests/cfg_rsoo_unittest.cc [new file with mode: 0644]

index 4381680468e5ca06ecfe090e4991c66f1d0783b5..a6b7e8a2b224b4c046f0fe750dfe8e10979302c2 100644 (file)
@@ -885,6 +885,9 @@ temporarily override a list of interface names and listen on all interfaces.
 <row><entry>clt-time</entry><entry>46</entry><entry>uint32</entry><entry>false</entry></row>
 <row><entry>lq-relay-data</entry><entry>47</entry><entry>record</entry><entry>false</entry></row>
 <row><entry>lq-client-link</entry><entry>48</entry><entry>ipv6-address</entry><entry>true</entry></row>
+<row><entry>erp-local-domain-name</entry><entry>65</entry><entry>fqdn</entry><entry>false</entry></row>
+<row><entry>rsoo</entry><entry>66</entry><entry>empty</entry><entry>false</entry></row>
+<row><entry>client-linklayer-addr</entry><entry>79</entry><entry>binary</entry><entry>false</entry></row>
         </tbody>
         </tgroup>
       </table>
@@ -1371,7 +1374,7 @@ should include options from the isc option space:
     <section id="dhcp6-rsoo">
       <title>Relay-Supplied Options</title>
       <para><ulink url="http://tools.ietf.org/html/rfc6422">RFC 6422</ulink>
-      defines a mechanism called Relay supplied options. In certain cases relay
+      defines a mechanism called Relay-Supplied DHCP Options. In certain cases relay
       agents are the only entities that may have specific information. They can
       insert options when relaying messages from the client to the server. The
       server will then do certain checks and copy those options to the response
@@ -1381,11 +1384,11 @@ should include options from the isc option space:
       included. First, the server must not provide the option by itself. In
       other words, if both relay and server provide an option, the server always
       takes precedence. Second, the option must be RSOO-enabled. IANA mantains a
-      list of RSOO-enabled options here: <ulink url="http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#options-relay-supplied">List of RSOO-enabled options</ulink>.
-      However, there may cases when system administrators want to echo other
+      list of RSOO-enabled options <ulink url="http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#options-relay-supplied">here</ulink>.
+      However, there may be cases when system administrators want to echo other
       options. Kea can be instructed to treat other options as RSOO-enabled.
       For example, to mark options 110, 120 and 130 as RSOO-enabled, the following
-      syntax may be used:
+      syntax should be used:
 <screen>
 "Dhcp6": {
     <userinput>"relay-supplied-options": [ "110", "120", "130" ],</userinput>
index 851863a9948873dd5d48c617ae6cad516db4ee2b..bcae8d0f33d8c7e2ff279abadb33caf77a453d2f 100644 (file)
@@ -2739,39 +2739,28 @@ void Dhcpv6Srv::processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp) {
         return;
     }
 
-    // Get the global options info. We'll use it to check whether an
-    // option is RSOO-enabled or not.
-    ConstCfgOptionPtr global_opts = CfgMgr::instance().getCurrentCfg()->
-        getCfgOption();
+    // Get RSOO configuration.
+    ConstCfgRSOOPtr cfg_rsoo  = CfgMgr::instance().getCurrentCfg()->getCfgRSOO();
 
     // Let's get over all relays (encapsulation levels). We need to do
     // it in the same order as the client packet traversed the relays.
     for (int i = query->relay_info_.size(); i > 0 ; --i) {
         OptionPtr rsoo_container = query->getRelayOption(D6O_RSOO, i - 1);
-        if (!rsoo_container) {
-            // No relay-supplied options by this relay? Ok, carry on.
-            continue;
-        }
-
-        // There are RSOO options. Let's get through them one by one
-        // and if it's RSOO-enabled and there's no such option provided yet,
-        // copy it to the server's response
-        const OptionCollection& rsoo = rsoo_container->getOptions();
-        for (OptionCollection::const_iterator opt = rsoo.begin(); opt != rsoo.end();
-             ++opt) {
-            if (!global_opts->isRSOOEnabled(opt->second->getType())) {
-                // We didn't copy this option, because it's not RSOO-enabled.
-                continue;
-            }
-
-            if (rsp->getOption(opt->second->getType())) {
-                // There is such an option in the server's response already,
-                // we'll skip relay's option
-                continue;
+        if (rsoo_container) {
+            // There are RSOO options. Let's get through them one by one
+            // and if it's RSOO-enabled and there's no such option provided yet,
+            // copy it to the server's response
+            const OptionCollection& rsoo = rsoo_container->getOptions();
+            for (OptionCollection::const_iterator opt = rsoo.begin();
+                 opt != rsoo.end(); ++opt) {
+
+                // Echo option if it is RSOO enabled option and there is no such
+                // option added yet.
+                if (cfg_rsoo->enabled(opt->second->getType()) &&
+                    !rsp->getOption(opt->second->getType())) {
+                    rsp->addOption(opt->second);
+                }
             }
-
-            // All checks went ok, let's add this option.
-            rsp->addOption(opt->second);
         }
     }
 }
index 53ea89b86d0dbee41d0662cb754aa2a897a7fb8c..f53afa1217f4653dbf9c824e861c0029df6e1a95 100644 (file)
@@ -41,6 +41,7 @@
 #include <boost/shared_ptr.hpp>
 
 #include <iostream>
+#include <limits>
 #include <map>
 #include <vector>
 
@@ -575,10 +576,14 @@ public:
     ParserCollection subnets_;
 };
 
-/// @brief parser for list of RSOO options
+/// @brief Parser for list of RSOO options
 ///
-/// This parser handles Dhcp6/relay-supplied-options entry.
-/// It contains a list of option codes.
+/// This parser handles Dhcp6/relay-supplied-options entry. It contains a
+/// list of RSOO-enabled options which should be sent back to the client.
+///
+/// The option on this list can be specified using an option code or option
+/// name. Therefore, the values on the list should always be enclosed in
+/// "quotes".
 class RSOOListConfigParser : public DhcpConfigParser {
 public:
 
@@ -603,34 +608,47 @@ public:
     ///
     /// @param value pointer to the content of parsed values
     virtual void build(isc::data::ConstElementPtr value) {
+        try {
+            BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
+                std::string option_str = source_elem->stringValue();
+                // This option can be either code (integer) or name. Let's try code first
+                int64_t code = 0;
+                try {
+                    code = boost::lexical_cast<int64_t>(option_str);
+                    // Protect against the negative value and too high value.
+                    if (code < 0) {
+                        isc_throw(BadValue, "invalid option code value specified '"
+                                  << option_str << "', the option code must be a"
+                                  " non-negative value");
+
+                    } else if (code > std::numeric_limits<uint16_t>::max()) {
+                        isc_throw(BadValue, "invalid option code value specified '"
+                                  << option_str << "', the option code must not be"
+                                  " greater than '" << std::numeric_limits<uint16_t>::max()
+                                  << "'");
+                    }
+
+                } catch (const boost::bad_lexical_cast &) {
+                    // Oh well, it's not a number
+                }
 
-        // By default, there's only one RSOO option defined: 65
-        // http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml
-        CfgMgr::instance().getStagingCfg()->getCfgOption()->clearRSOO();
-        CfgMgr::instance().getStagingCfg()->getCfgOption()->addRSOO(D6O_ERP_LOCAL_DOMAIN_NAME);
-
-        BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
-
-            std::string option_str = source_elem->stringValue();
-            // This option can be either code (integer) or name. Let's try code first
-            uint16_t code = 0;
-            try {
-                code = boost::lexical_cast<uint16_t>(option_str);
-            } catch (const boost::bad_lexical_cast &) {
-                // Oh well, it's not a number
-            }
-
-            if (!code) {
-                OptionDefinitionPtr def = LibDHCP::getOptionDef(Option::V6, option_str);
-                if (def) {
-                    code = def->getCode();
-                } else {
-                    isc_throw(BadValue, "Unable to convert '" << option_str
-                              << "' to option code while parsing allowed"
-                              << "relay-supplied-options");
+                if (!code) {
+                    OptionDefinitionPtr def = LibDHCP::getOptionDef(Option::V6, option_str);
+                    if (def) {
+                        code = def->getCode();
+                    } else {
+                        isc_throw(BadValue, "unable to find option code for the "
+                                  " specified option name '" << option_str << "'"
+                                  " while parsing the list of enabled"
+                                  " relay-supplied-options");
+                    }
                 }
+                CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enable(code);
             }
-            CfgMgr::instance().getStagingCfg()->getCfgOption()->addRSOO(code);
+        } catch (const std::exception& ex) {
+            // Rethrow exception with the appended position of the parsed
+            // element.
+            isc_throw(DhcpConfigError, ex.what() << " (" << value->getPosition() << ")");
         }
     }
 
index 7c1690acdc2aa1edd9abfb7f4c93d1a50cc8b856..239bb84906e90421987515b56a51fc2e31e8ca03 100644 (file)
@@ -3798,18 +3798,18 @@ TEST_F(Dhcp6ParserTest, rsooNumbers) {
     checkResult(status, 0);
 
     // The following codes should be enabled now
-    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(10));
-    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(20));
-    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(30));
+    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(10));
+    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(20));
+    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(30));
 
     // This option is on the IANA list, so it should be allowed all the time
     // (http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml)
-    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()
-                ->isRSOOEnabled(D6O_ERP_LOCAL_DOMAIN_NAME));
+    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
+                ->enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
 
     // Those options are not enabled
-    EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(25));
-    EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()->isRSOOEnabled(1));
+    EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(25));
+    EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()->enabled(1));
 }
 
 /// The goal of this test is to verify that configuration can include
@@ -3831,39 +3831,68 @@ TEST_F(Dhcp6ParserTest, rsooNames) {
     checkResult(status, 0);
 
     for (uint16_t code = 0; code < D6O_NAME_SERVERS; ++code) {
-        EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()
-                     ->isRSOOEnabled(code)) << " for option code " << code;
+        EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
+                     ->enabled(code)) << " for option code " << code;
     }
 
     // The following codes should be enabled now
-    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()
-                ->isRSOOEnabled(D6O_NAME_SERVERS));
+    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
+                ->enabled(D6O_NAME_SERVERS));
 
     for (uint16_t code = D6O_NAME_SERVERS + 1; code < D6O_REMOTE_ID; ++code) {
-        EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()
-                     ->isRSOOEnabled(code)) << " for option code " << code;
+        EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
+                     ->enabled(code)) << " for option code " << code;
     }
 
     // Check remote-id. It should be enabled.
-    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()
-                ->isRSOOEnabled(D6O_REMOTE_ID));
+    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
+                ->enabled(D6O_REMOTE_ID));
     for (uint16_t code = D6O_REMOTE_ID + 1; code < D6O_ERP_LOCAL_DOMAIN_NAME; ++code) {
-        EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()
-                     ->isRSOOEnabled(code)) << " for option code " << code;
+        EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
+                     ->enabled(code)) << " for option code " << code;
     }
 
     // This option is on the IANA list, so it should be allowed all the time
     // (http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml)
-    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgOption()
-                ->isRSOOEnabled(D6O_ERP_LOCAL_DOMAIN_NAME));
+    EXPECT_TRUE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
+                ->enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
 
     for (uint16_t code = D6O_ERP_LOCAL_DOMAIN_NAME + 1; code < 300; ++code) {
-        EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgOption()
-                     ->isRSOOEnabled(code)) << " for option code " << code;
+        EXPECT_FALSE(CfgMgr::instance().getStagingCfg()->getCfgRSOO()
+                     ->enabled(code)) << " for option code " << code;
     }
+}
 
+TEST_F(Dhcp6ParserTest, rsooNegativeNumber) {
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
+        Element::fromJSON("{ " + genIfaceConfig() + ","
+                          "\"relay-supplied-options\": [ \"80\", \"-2\" ],"
+                          "\"preferred-lifetime\": 3000,"
+                          "\"rebind-timer\": 2000, "
+                          "\"renew-timer\": 1000, "
+                          "\"subnet6\": [  ], "
+                          "\"valid-lifetime\": 4000 }")));
 
+    // returned value should be 0 (success)
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
 }
 
+TEST_F(Dhcp6ParserTest, rsooBogusName) {
+    ConstElementPtr status;
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
+        Element::fromJSON("{ " + genIfaceConfig() + ","
+                          "\"relay-supplied-options\": [ \"bogus\", \"dns-servers\" ],"
+                          "\"preferred-lifetime\": 3000,"
+                          "\"rebind-timer\": 2000, "
+                          "\"renew-timer\": 1000, "
+                          "\"subnet6\": [  ], "
+                          "\"valid-lifetime\": 4000 }")));
+
+    // returned value should be 0 (success)
+    checkResult(status, 1);
+    EXPECT_TRUE(errorContainsPosition(status, "<string>"));
+}
 
 };
index 8b04890a7a638a62c1431086234c8a648be5b2b2..cae538b6f1975bb3fef1ee639c0356c04143dfbe 100644 (file)
@@ -110,6 +110,21 @@ public:
             status_code_ = 0;
             received_status_code_ = false;
         }
+
+        /// @brief Finds an option with the specific code in the received
+        /// configuration.
+        ///
+        /// @param code Option code.
+        ///
+        /// @return Pointer to the option if the option exists, or NULL if
+        /// the option doesn't exist.
+        OptionPtr findOption(const uint16_t code) const {
+            std::multimap<unsigned int, OptionPtr>::const_iterator it = options_.find(code);
+            if (it != options_.end()) {
+                return (it->second);
+            }
+            return (OptionPtr());
+        }
     };
 
     /// @brief Holds the DHCPv6 messages taking part in transaction between
index 5769a66e7a4e2f42fbf1b01d2be64a54f54c0046..d7b29569ffea9952e5a8f2bb5e2c1e82d5f8ccba 100644 (file)
@@ -2277,6 +2277,80 @@ TEST_F(Dhcpv6SrvTest, rsoo2relays) {
     EXPECT_EQ(expected, opt120->getData());
 }
 
+// This test verifies that the server will send the option for which it
+// has a candidate, rather than the option sent by the relay in the RSOO.
+TEST_F(Dhcpv6SrvTest, rsooOverride) {
+    Dhcp6Client client;
+    // The client will be requesting specific options.
+    client.useORO(true);
+
+    // The following configuration enables RSOO options: 110 and 120.
+    // It also configures the server with option 120 which should
+    // "override" the option 120 sent in the RSOO by the relay.
+    string config =
+        "{"
+        "    \"relay-supplied-options\": [ \"110\", \"120\" ],"
+        "    \"option-def\": [ {"
+        "      \"name\": \"foo\","
+        "      \"code\": 120,"
+        "      \"type\": \"binary\","
+        "      \"array\": False,"
+        "      \"record-types\": \"\","
+        "      \"space\": \"dhcp6\","
+        "      \"encapsulate\": \"\""
+        "    } ],"
+        "    \"option-data\": [ {"
+        "      \"code\": 120,"
+        "      \"data\": \"05\""
+        "    } ],"
+        "    \"preferred-lifetime\": 3000,"
+        "    \"rebind-timer\": 2000, "
+        "    \"renew-timer\": 1000, "
+        "    \"subnet6\": [ { "
+        "        \"pools\": [ { \"pool\": \"2001:db8::/64\" } ],"
+        "        \"subnet\": \"2001:db8::/48\" "
+        "     } ],"
+        "    \"valid-lifetime\": 4000"
+        "}";
+
+    EXPECT_NO_THROW(configure(config, *client.getServer()));
+
+    // Fabricate the relay.
+    Pkt6::RelayInfo relay;
+    relay.msg_type_ = DHCPV6_RELAY_FORW;
+    relay.hop_count_ = 1;
+    relay.linkaddr_ = IOAddress("2001:db8::1");
+    relay.peeraddr_ = IOAddress("fe80::1");
+    vector<uint16_t> rsoo;
+    // The relay will send 2 options: 110, 120
+    rsoo.push_back(110);
+    rsoo.push_back(120);
+    // Use 0x1 as payload
+    OptionPtr opt = createRSOO(rsoo, 1);
+    relay.options_.insert(make_pair(opt->getType(), opt));
+    client.relay_info_.push_back(relay);
+
+    // Client should request option 120 in the ORO so as the server
+    // sends the configured option 120 to the client.
+    client.requestOption(120);
+    client.doSARR();
+
+    // The option 110 should be the one injected by the relay.
+    opt = client.config_.findOption(110);
+    ASSERT_TRUE(opt);
+    // We check that this is the option injected by the relay by
+    // checking option length. It should has 10 bytes long payload.
+    ASSERT_EQ(10, opt->getData().size());
+
+    // The second option should be the one configured on the server,
+    // rather than the one injected by the relay.
+    opt = client.config_.findOption(120);
+    ASSERT_TRUE(opt);
+    // It should have the size of 1.
+    ASSERT_EQ(1, opt->getData().size());
+}
+
+
 /// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
 /// to call processX() methods.
 
index 4d1f710ec1b6d2a0fdf11fe9de5b458d8d429920..4cdaf1d7b248380fae42541da5df0c443d76d9ab 100644 (file)
@@ -327,7 +327,7 @@ const OptionDefParams OPTION_DEF_PARAMS6[] = {
       RECORD_DEF(LQ_RELAY_DATA_RECORDS), "" },
     { "lq-client-link", D6O_LQ_CLIENT_LINK, OPT_IPV6_ADDRESS_TYPE, true,
       NO_RECORD_DEF, "" },
-    { "rsoo", D6O_RSOO, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "dhcp4" },
+    { "rsoo", D6O_RSOO, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "rsoo-opts" },
     { "client-linklayer-addr", D6O_CLIENT_LINKLAYER_ADDR, OPT_BINARY_TYPE, false,
         NO_RECORD_DEF, "" }
 
index 38e52602f0b6240baccb63d05ef57a58a328d95d..f788c9034ac3491074ed3e722bf3f276553e3669 100644 (file)
@@ -351,6 +351,7 @@ Pkt6Ptr isc::test::PktCaptures::captureCableLabsShortVendorClass() {
 ///          - rsoo (66)
 ///              - option 255 (len 4)
 ///              - option 256 (len 9)
+///          - remote-id option (37)
 ///          - RELAY-FORW
 ///             - SOLICIT
 ///                  - client-id option
index d82601d6b9f5811fe6ab719bed99efd8be7ae151..c60310994265788fc2923ef1bbaa6273ae0b1ff3 100644 (file)
@@ -70,6 +70,7 @@ libkea_dhcpsrv_la_SOURCES += cfg_hosts.cc cfg_hosts.h
 libkea_dhcpsrv_la_SOURCES += cfg_iface.cc cfg_iface.h
 libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h
 libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h
+libkea_dhcpsrv_la_SOURCES += cfg_rsoo.cc cfg_rsoo.h
 libkea_dhcpsrv_la_SOURCES += cfg_subnets4.cc cfg_subnets4.h
 libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h
 libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h
index 46f0338243826e5758f8735651742870a40d753a..6258db0e508ac4901f5191e321fb41ea8b7cee7b 100644 (file)
@@ -29,10 +29,6 @@ OptionDescriptor::equals(const OptionDescriptor& other) const {
 }
 
 CfgOption::CfgOption() {
-
-    // By default, the only allowed Relay-Supplied Options option is
-    // ERP local domain name. Other options may be added in configuration.
-    rsoo_options_.insert(D6O_ERP_LOCAL_DOMAIN_NAME);
 }
 
 bool
@@ -198,20 +194,5 @@ CfgOption::optionSpaceToVendorId(const std::string& option_space) {
     return (static_cast<uint32_t>(check));
 }
 
-void CfgOption::clearRSOO() {
-    rsoo_options_.clear();
-}
-
-bool CfgOption::isRSOOEnabled(uint16_t code) const {
-    return (rsoo_options_.find(code) != rsoo_options_.end());
-}
-
-void CfgOption::addRSOO(uint16_t code) {
-    if (rsoo_options_.find(code) == rsoo_options_.end()) {
-        // If there's no such code added yet, let's add it
-        rsoo_options_.insert(code);
-    }
-}
-
 } // end of namespace isc::dhcp
 } // end of namespace isc
index da4c0d5c57357bc9aa8d620ae7f95dd9b8af4b0f..4dad5b4ca31e2479aa9e121667299baabc17f547 100644 (file)
@@ -195,11 +195,6 @@ typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
 /// options is useful when the client requests stateless configuration from
 /// the DHCP server and no subnet is selected for this client. This client
 /// will only receive global options.
-///
-/// isRSSOEnabled(), addRSOO(), clearRSOO() are methods related to
-/// Relay-Supplied Options option. This information does not provide any values
-/// about the options themselves, but rather contain a list of options that
-/// are allowed in RSOO ("RSOO-enabled").
 class CfgOption {
 public:
 
@@ -357,23 +352,6 @@ public:
     /// @return vendor id.
     static uint32_t optionSpaceToVendorId(const std::string& option_space);
 
-    /// @brief Removes designation of all options as RSOO-enabled.
-    ///
-    /// This method removes all designations of all options as being RSOO-enabled.
-    /// Note that the list is maintained by IANA and option 65 is officially
-    /// RSOO-enabled. This list may be extended in the future. Also, the user may
-    /// add extra options here.
-    void clearRSOO();
-
-    /// @brief Returns whether specific option code is RSOO-enabled.
-    /// @param code option code to check
-    /// @return true, if it is allowed in Relay-Supplied Options option
-    bool isRSOOEnabled(uint16_t code) const;
-
-    /// @brief Marks specified option code as RSOO-enabled.
-    /// @param code option to be enabled in RSOO
-    void addRSOO(uint16_t code);
-
 private:
 
     /// @brief Appends encapsulated options to the options in an option space.
@@ -419,15 +397,6 @@ private:
                                  uint32_t> VendorOptionSpaceCollection;
     /// @brief Container holding options grouped by vendor id.
     VendorOptionSpaceCollection vendor_options_;
-
-    /// @brief Contains a list of options that are allowed in RSOO option
-    ///
-    /// RSOO stands for Relay-Supplied Options option. This is an option that
-    /// is inserted by the relay agent with the intention that the server will
-    /// echo those options back to the client. Only those options marked as
-    /// RSOO-enabled may appear in the RSOO. Currently only option 65 is marked
-    /// as such, but more options may be added in the future. See RFC6422 for details.
-    std::set<uint16_t> rsoo_options_;
 };
 
 /// @name Pointers to the @c CfgOption objects.
diff --git a/src/lib/dhcpsrv/cfg_rsoo.cc b/src/lib/dhcpsrv/cfg_rsoo.cc
new file mode 100644 (file)
index 0000000..dc2dae2
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcp/dhcp6.h>
+#include <dhcpsrv/cfg_rsoo.h>
+
+namespace isc {
+namespace dhcp {
+
+CfgRSOO::CfgRSOO()
+    : rsoo_options_() {
+    rsoo_options_.insert(D6O_ERP_LOCAL_DOMAIN_NAME);
+}
+
+void
+CfgRSOO::clear() {
+    rsoo_options_.clear();
+}
+
+bool
+CfgRSOO::enabled(const uint16_t code) const {
+    return (rsoo_options_.find(code) != rsoo_options_.end());
+}
+
+void
+CfgRSOO::enable(const uint16_t code) {
+    if (rsoo_options_.find(code) == rsoo_options_.end()) {
+        // If there's no such code added yet, let's add it
+        rsoo_options_.insert(code);
+    }
+}
+
+
+}
+}
diff --git a/src/lib/dhcpsrv/cfg_rsoo.h b/src/lib/dhcpsrv/cfg_rsoo.h
new file mode 100644 (file)
index 0000000..8af75c0
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef CFG_RSOO_H
+#define CFG_RSOO_H
+
+#include <boost/shared_ptr.hpp>
+#include <set>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Represents configuration of the RSOO options for the DHCP server.
+///
+/// This class holds the set of RSOO-enabled options (see RFC6422). The list
+/// of RSOO-enabled options is maintained by IANA and currently the option
+/// 65 is officially RSSO-enabled. The list may be extended in the future
+/// and this class allows for specifying any future RSOO-enabled options.
+/// The administrator may also use existing options as RSOO-enabled.
+class CfgRSOO {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// It adds the default (officially) RSOO-enabled options:
+    /// - OPTION_ERP_LOCAL_DOMAIN_NAME
+    CfgRSOO();
+
+    /// @brief Removes designation of all options as RSOO_enabled.
+    ///
+    /// This method removes all designations of all options as being RSOO-enabled.
+    void clear();
+
+    /// @brief Returns whether specific option code is RSOO-enabled.
+    ///
+    /// @param code Option code to check
+    /// @return true, if it is allowed in Relay-Supplied Options option
+    bool enabled(const uint16_t code) const;
+
+    /// @brief Marks specified option code as RSOO-enabled.
+    ///
+    /// @param code option to be enabled in RSOO
+    void enable(const uint16_t code);
+
+private:
+
+    /// @brief Contains a set of options that are allowed in RSOO option
+    ///
+    /// RSOO stands for Relay-Supplied Options option. This is an option that
+    /// is inserted by the relay agent with the intention that the server will
+    /// echo those options back to the client. Only those options marked as
+    /// RSOO-enabled may appear in the RSOO. Currently only option 65 is marked
+    /// as such, but more options may be added in the future. See RFC6422 for details.
+    std::set<uint16_t> rsoo_options_;
+
+};
+
+/// @name Pointers to the @c CfgRSOO objects.
+//@{
+/// @brief Pointer to the Non-const object.
+typedef boost::shared_ptr<CfgRSOO> CfgRSOOPtr;
+
+/// @brief Pointer to the const object.
+typedef boost::shared_ptr<const CfgRSOO> ConstCfgRSOOPtr;
+
+//@}
+
+}
+}
+
+#endif // CFG_RSOO_H
index 34725a3642bfee63579d618ab4bb53f7ed63b20c..d2b9a78870671d900747af8c9de5fbe805011cf5 100644 (file)
@@ -29,14 +29,14 @@ SrvConfig::SrvConfig()
     : sequence_(0), cfg_iface_(new CfgIface()),
       cfg_option_def_(new CfgOptionDef()), cfg_option_(new CfgOption()),
       cfg_subnets4_(new CfgSubnets4()), cfg_subnets6_(new CfgSubnets6()),
-      cfg_hosts_(new CfgHosts()) {
+      cfg_hosts_(new CfgHosts()), cfg_rsoo_(new CfgRSOO()) {
 }
 
 SrvConfig::SrvConfig(const uint32_t sequence)
     : sequence_(sequence), cfg_iface_(new CfgIface()),
       cfg_option_def_(new CfgOptionDef()), cfg_option_(new CfgOption()),
       cfg_subnets4_(new CfgSubnets4()), cfg_subnets6_(new CfgSubnets6()),
-      cfg_hosts_(new CfgHosts()) {
+      cfg_hosts_(new CfgHosts()), cfg_rsoo_(new CfgRSOO()) {
 }
 
 std::string
index 140651f2303fae0a630bce5d87a90fda940f502a..ab895b080d7f82b558fa7871541291f677d9bcc2 100644 (file)
@@ -19,6 +19,7 @@
 #include <dhcpsrv/cfg_iface.h>
 #include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/cfg_option_def.h>
+#include <dhcpsrv/cfg_rsoo.h>
 #include <dhcpsrv/cfg_subnets4.h>
 #include <dhcpsrv/cfg_subnets6.h>
 #include <dhcpsrv/cfg_mac_source.h>
@@ -239,6 +240,24 @@ public:
         return (cfg_hosts_);
     }
 
+    /// @brief Returns pointer to the non-const object representing
+    /// set of RSOO-enabled options.
+    ///
+    /// @return Pointer to the non-const object holding RSOO-enabled
+    /// options.
+    CfgRSOOPtr getCfgRSOO() {
+        return (cfg_rsoo_);
+    }
+
+    /// @brief Returns pointer to the const object representing set
+    /// of RSOO-enabled options.
+    ///
+    /// @return Pointer to the const object holding RSOO-enabled
+    /// options.
+    ConstCfgRSOOPtr getCfgRSOO() const {
+        return (cfg_rsoo_);
+    }
+
     //@}
 
     /// @brief Returns non-const reference to an array that stores
@@ -371,6 +390,12 @@ private:
 
     /// @brief A list of configured MAC sources.
     CfgMACSource cfg_mac_source_;
+
+    /// @brief Pointer to the configuration for RSOO-enabled options.
+    ///
+    /// This object holds a set of RSOO-enabled options. See the
+    /// RFC 6422 for the definition of RSOO-enabled option.
+    CfgRSOOPtr cfg_rsoo_;
 };
 
 /// @name Pointers to the @c SrvConfig object.
index cb14f5d470afaf5dc6f9154b6fe7410e8c61824f..36334dd1bdd24880379342fdc4a7760ac36e8726 100644 (file)
@@ -64,6 +64,7 @@ libdhcpsrv_unittests_SOURCES += cfg_iface_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_mac_source_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_option_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc
+libdhcpsrv_unittests_SOURCES += cfg_rsoo_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_subnets4_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_subnets6_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
index 5f1d8ab252b56ba23940307ea09521a764820831..495556ba32df272bec74efc5195bed5d46782694 100644 (file)
@@ -477,33 +477,5 @@ TEST(CfgOptionTest, addVendorOptions) {
     EXPECT_TRUE(options->empty());
 }
 
-// This test verifies that Relay-Supplied Options option (RSOO) is handled
-// properly.
-TEST(CfgOptionTest, rsoo) {
-    CfgOption cfg;
-
-    // All options from 0..64 are not RSOO-enabled
-    for (uint16_t code = 0; code < D6O_ERP_LOCAL_DOMAIN_NAME; ++code) {
-        EXPECT_FALSE(cfg.isRSOOEnabled(code));
-    }
-
-    // Option 65 is the only one so far that is enabled
-    EXPECT_TRUE(cfg.isRSOOEnabled(D6O_ERP_LOCAL_DOMAIN_NAME));
-
-    // Let's check other options. They should not be enabled.
-    for (uint16_t code = D6O_ERP_LOCAL_DOMAIN_NAME + 1; code < 300; ++code) {
-        EXPECT_FALSE(cfg.isRSOOEnabled(code)) << " for option code " << code;
-    }
-
-    // Let's clear it.
-    cfg.clearRSOO();
-
-    // Now not even option 65 is enabled.
-    EXPECT_FALSE(cfg.isRSOOEnabled(D6O_ERP_LOCAL_DOMAIN_NAME));
-
-    // Should be possible to specify that an option is RSOO-enabled
-    EXPECT_NO_THROW(cfg.addRSOO(200));
-    EXPECT_TRUE(cfg.isRSOOEnabled(200));
-}
 
 } // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/cfg_rsoo_unittest.cc b/src/lib/dhcpsrv/tests/cfg_rsoo_unittest.cc
new file mode 100644 (file)
index 0000000..3069c75
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <dhcp/dhcp6.h>
+#include <dhcpsrv/cfg_rsoo.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+// This test verifies that the RSOO configuration holds the default
+// RSOO-enabled options.
+TEST(CfgRSOOTest, defaults) {
+    CfgRSOO rsoo;
+    EXPECT_TRUE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
+    for (uint16_t code = 0; code < 200; ++code) {
+        if (code != D6O_ERP_LOCAL_DOMAIN_NAME) {
+            EXPECT_FALSE(rsoo.enabled(code))
+                << "expected that the option with code "
+                << code << " is by default RSOO-disabled, but"
+                " it is enabled";
+        }
+    }
+
+    // Now, let's see if we can remove the default options.
+    ASSER_NO_THROW(rsoo.clear());
+    EXPECT_FALSE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
+
+    // Make sure it can be added again.
+    ASSERT_NO_THROW(rsoo.enable(D6O_ERP_LOCAL_DOMAIN_NAME));
+    EXPECT_TRUE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
+}
+
+// This test verifies that it is possible to enable more RSOO options
+// and later remove all of them.
+TEST(CfgRSOOTest, enableAndClear) {
+    CfgRSOO rsoo;
+    EXPECT_TRUE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
+
+    // Enable option 88.
+    ASSERT_FALSE(rsoo.enabled(88));
+    ASSERT_NO_THROW(rsoo.enable(88));
+    EXPECT_TRUE(rsoo.enabled(88));
+
+    // Enable option 89.
+    ASSERT_FALSE(rsoo.enabled(89));
+    ASSERT_NO_THROW(rsoo.enable(89));
+    EXPECT_TRUE(rsoo.enabled(89));
+
+    // Remove them and make sure they have been removed.
+    ASSERT_NO_THROW(rsoo.clear());
+    for (uint16_t code = 0; code < 200; ++code) {
+        EXPECT_FALSE(rsoo.enabled(code))
+            << "expected that the option with code "
+            << code << " is RSOO-disabled after clearing"
+            " the RSOO configuration, but it is not";
+    }
+}
+
+// This test verfies that the same option may be specified
+// multiple times and that the code doesn't fail.
+TEST(CfgRSOOTest, enableTwice) {
+    CfgRSOO rsoo;
+    // By default there should be the default option enabled.
+    // Let's try to enable it again. It should pass.
+    ASSERT_NO_THROW(rsoo.enable(D6O_ERP_LOCAL_DOMAIN_NAME));
+    EXPECT_TRUE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
+
+    // Enable option 88.
+    ASSERT_FALSE(rsoo.enabled(88));
+    ASSERT_NO_THROW(rsoo.enable(88));
+    EXPECT_TRUE(rsoo.enabled);
+
+    // And enable it again.
+    ASSERT_NO_THROW(rsoo.enabled(88));
+    EXPECT_TRUE(rsoo.enabled(88));
+
+    // Remove all.
+    ASSERT_NO_THROW(rsoo.clear());
+    ASSERT_FALSE(rsoo.enabled(D6O_ERP_LOCAL_DOMAIN_NAME));
+    ASSERT_FALSE(rsoo.enabled(88));
+}
+
+} // end of anonymous namespace