Parcourir la source

[3035] Added stub implementation for the function processing client FQDN.

Marcin Siodelski il y a 11 ans
Parent
commit
41c4d829e6

+ 30 - 0
src/bin/dhcp4/dhcp4_srv.cc

@@ -18,6 +18,8 @@
 #include <dhcp/hwaddr.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcp/option4_addrlst.h>
+#include <dhcp/option4_client_fqdn.h>
+#include <dhcp/option_custom.h>
 #include <dhcp/option_int.h>
 #include <dhcp/option_int_array.h>
 #include <dhcp/pkt4.h>
@@ -663,6 +665,34 @@ Dhcpv4Srv::appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
 }
 
 void
+Dhcpv4Srv::processClientName(const Pkt4Ptr& query, Pkt4Ptr& answer) {
+    // It is possible that client has sent both Client FQDN and Hostname
+    // option. In such case, server should prefer Client FQDN option and
+    // ignore the Hostname option.
+    Option4ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>
+        (query->getOption(DHO_FQDN));
+    if (fqdn) {
+        processClientFqdnOption(query, answer);
+
+    } else {
+        OptionCustomPtr hostname = boost::dynamic_pointer_cast<OptionCustom>
+            (query->getOption(DHO_HOST_NAME));
+        if (hostname) {
+            processHostnameOption(query, answer);
+        }
+
+    }
+}
+
+void
+Dhcpv4Srv::processClientFqdnOption(const Pkt4Ptr&, Pkt4Ptr&) {
+}
+
+void
+Dhcpv4Srv::processHostnameOption(const Pkt4Ptr&, Pkt4Ptr&) {
+}
+
+void
 Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
 
     // We need to select a subnet the client is connected in.

+ 50 - 0
src/bin/dhcp4/dhcp4_srv.h

@@ -250,6 +250,56 @@ protected:
     /// @param msg the message to add options to.
     void appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg);
 
+    /// @brief Processes Client FQDN and Hostname Options sent by a client.
+    ///
+    /// Client may send Client FQDN or Hostname option to communicate its name
+    /// to the server. Server may use this name to perform DNS update for the
+    /// lease being assigned to a client. If server takes responsibility for
+    /// updating DNS for a client it may communicate it by sending the Client
+    /// FQDN or Hostname %Option back to the client. Server select a different
+    /// name than requested by a client to update DNS. In such case, the server
+    /// stores this different name in its response.
+    ///
+    /// Client should not send both Client FQDN and Hostname options. However,
+    /// if client sends both options, server should prefer Client FQDN option
+    /// and ignore the Hostname option. If Client FQDN option is not present,
+    /// the Hostname option is processed.
+    ///
+    /// The Client FQDN %Option is processed by this function as described in
+    /// RFC4702.
+    ///
+    /// In response to a Hostname %Option sent by a client, the server may send
+    /// Hostname option with the same or different hostname. If different
+    /// hostname is sent, it is an indication to the client that server has
+    /// overridden the client's preferred name and will rather use this
+    /// different name to update DNS. However, since Hostname option doesn't
+    /// carry an information whether DNS update will be carried by the server
+    /// or not, the client is responsible for checking whether DNS update
+    /// has been performed.
+    ///
+    /// After successful processing options stored in the first parameter,
+    /// this function may add Client FQDN or Hostname option to the response
+    /// message. In some cases, server may cease to add any options to the
+    /// response, i.e. when server doesn't support DNS updates.
+    ///
+    /// @param query A DISCOVER or REQUEST message from a cient.
+    /// @param [out] answer A response message to be sent to a client.
+    void processClientName(const Pkt4Ptr& query, Pkt4Ptr& answer);
+
+private:
+    /// @brief Process Client FQDN %Option sent by a client.
+    ///
+    /// @param query A DISCOVER or REQUEST message from a cient.
+    /// @param [out] answer A response message to be sent to a client.
+    void processClientFqdnOption(const Pkt4Ptr& query, Pkt4Ptr& answer);
+
+    /// @brief Process Hostname %Option sent by a client.
+    ///
+    /// @param query A DISCOVER or REQUEST message from a cient.
+    /// @param [out] answer A response message to be sent to a client.
+    void processHostnameOption(const Pkt4Ptr& query, Pkt4Ptr& answer);
+
+protected:
     /// @brief Attempts to renew received addresses
     ///
     /// Attempts to renew existing lease. This typically includes finding a lease that

+ 1 - 0
src/bin/dhcp4/tests/Makefile.am

@@ -70,6 +70,7 @@ dhcp4_unittests_SOURCES += dhcp4_unittests.cc
 dhcp4_unittests_SOURCES += dhcp4_srv_unittest.cc
 dhcp4_unittests_SOURCES += ctrl_dhcp4_srv_unittest.cc
 dhcp4_unittests_SOURCES += config_parser_unittest.cc
+dhcp4_unittests_SOURCES += fqdn_unittest.cc
 dhcp4_unittests_SOURCES += marker_file.cc
 nodist_dhcp4_unittests_SOURCES = ../dhcp4_messages.h ../dhcp4_messages.cc
 nodist_dhcp4_unittests_SOURCES += marker_file.h test_libraries.h

+ 1 - 0
src/bin/dhcp4/tests/dhcp4_test_utils.h

@@ -132,6 +132,7 @@ public:
     using Dhcpv4Srv::processRelease;
     using Dhcpv4Srv::processDecline;
     using Dhcpv4Srv::processInform;
+    using Dhcpv4Srv::processClientName;
     using Dhcpv4Srv::getServerID;
     using Dhcpv4Srv::loadServerID;
     using Dhcpv4Srv::generateServerID;

+ 143 - 0
src/bin/dhcp4/tests/fqdn_unittest.cc

@@ -0,0 +1,143 @@
+// Copyright (C) 2013  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 <asiolink/io_address.h>
+#include <dhcp/option4_client_fqdn.h>
+#include <dhcp4/tests/dhcp4_test_utils.h>
+
+#include <gtest/gtest.h>
+#include <boost/scoped_ptr.hpp>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::test;
+
+namespace {
+class FqdnDhcpv4SrvTest : public Dhcpv4SrvTest {
+public:
+    FqdnDhcpv4SrvTest() : Dhcpv4SrvTest() {
+        srv_ = new NakedDhcpv4Srv(0);
+    }
+
+    virtual ~FqdnDhcpv4SrvTest() {
+        delete srv_;
+    }
+
+    // Create an instance of the DHCPv4 Client FQDN Option.
+    Option4ClientFqdnPtr
+    createClientFqdn(const uint8_t flags,
+                     const std::string& fqdn_name,
+                     const Option4ClientFqdn::DomainNameType fqdn_type) {
+        return (Option4ClientFqdnPtr(new Option4ClientFqdn(flags,
+                                                           Option4ClientFqdn::
+                                                           RCODE_CLIENT(),
+                                                           fqdn_name,
+                                                           fqdn_type)));
+    }
+
+    Option4ClientFqdnPtr getClientFqdnOption(const Pkt4Ptr& pkt) {
+        return (boost::dynamic_pointer_cast<
+                Option4ClientFqdn>(pkt->getOption(DHO_FQDN)));
+    }
+
+    // Create a message holding DHCPv4 Client FQDN Option.
+    Pkt4Ptr generatePktWithFqdn(const uint8_t msg_type,
+                                const uint8_t fqdn_flags,
+                                const std::string& fqdn_domain_name,
+                                const Option4ClientFqdn::DomainNameType
+                                fqdn_type,
+                                const bool include_prl) {
+        Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(msg_type, 1234));
+        pkt->setRemoteAddr(IOAddress("192.0.2.3"));
+        // For DISCOVER we don't include server id, because client broadcasts
+        // the message to all servers.
+        if (msg_type != DHCPDISCOVER) {
+            pkt->addOption(srv_->getServerID());
+        }
+        // Client id is required.
+        pkt->addOption(generateClientId());
+
+        // Create Client FQDN Option with the specified flags and
+        // domain-name.
+        pkt->addOption(createClientFqdn(fqdn_flags, fqdn_domain_name,
+                                        fqdn_type));
+
+        // Control whether or not to request that server returns the FQDN
+        // option. Server may be configured to always return it or return
+        // only in case client requested it.
+        if (include_prl) {
+            OptionUint8ArrayPtr option_prl =
+                OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
+                                    DHO_DHCP_PARAMETER_REQUEST_LIST));
+            option_prl->addValue(DHO_FQDN);
+        }
+        return (pkt);
+    }
+
+    // Test that server generates the appropriate FQDN option in response to
+    // client's FQDN option.
+    void testProcessFqdn(const Pkt4Ptr& query, const uint8_t exp_flags,
+                         const std::string& exp_domain_name) {
+        ASSERT_TRUE(getClientFqdnOption(query));
+
+        Pkt4Ptr answer;
+        if (query->getType() == DHCPDISCOVER) {
+            answer.reset(new Pkt4(DHCPOFFER, 1234));
+
+        } else {
+            answer.reset(new Pkt4(DHCPACK, 1234));
+
+        }
+        ASSERT_NO_THROW(srv_->processClientName(query, answer));
+
+        Option4ClientFqdnPtr fqdn = getClientFqdnOption(answer);
+        ASSERT_TRUE(fqdn);
+
+        const bool flag_n = (exp_flags & Option4ClientFqdn::FLAG_N) != 0;
+        const bool flag_s = (exp_flags & Option4ClientFqdn::FLAG_S) != 0;
+        const bool flag_o = (exp_flags & Option4ClientFqdn::FLAG_O) != 0;
+        const bool flag_e = (exp_flags & Option4ClientFqdn::FLAG_E) != 0;
+
+        EXPECT_EQ(flag_n, fqdn->getFlag(Option4ClientFqdn::FLAG_N));
+        EXPECT_EQ(flag_s, fqdn->getFlag(Option4ClientFqdn::FLAG_S));
+        EXPECT_EQ(flag_o, fqdn->getFlag(Option4ClientFqdn::FLAG_O));
+        EXPECT_EQ(flag_e, fqdn->getFlag(Option4ClientFqdn::FLAG_E));
+
+        EXPECT_EQ(exp_domain_name, fqdn->getDomainName());
+        EXPECT_EQ(Option4ClientFqdn::FULL, fqdn->getDomainNameType());
+
+    }
+
+private:
+    NakedDhcpv4Srv* srv_;
+
+};
+
+TEST_F(FqdnDhcpv4SrvTest, basic) {
+    Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
+                                        Option4ClientFqdn::FLAG_E |
+                                        Option4ClientFqdn::FLAG_S,
+                                        "myhost.example.com.",
+                                        Option4ClientFqdn::FULL,
+                                        true);
+
+    testProcessFqdn(query,
+                    Option4ClientFqdn::FLAG_E | Option4ClientFqdn::FLAG_S,
+                    "myhost.example.com.");
+
+}
+
+} // end of anonymous namespace