Browse Source

[3636] DHCPv4 server does not append the dot at the end of the hostname.

This patch has been proposed by Alexis Fidalgo. It was earlier reported
that Kea always appends a dot at the end of the hostname which may cause
some clients to fail on processing this option.
Marcin Siodelski 10 years ago
parent
commit
1feae7244e

+ 8 - 5
src/bin/dhcp4/dhcp4_srv.cc

@@ -817,7 +817,7 @@ Dhcpv4Srv::processHostnameOption(const OptionStringPtr& opt_hostname,
         // If there are two labels, it means that the client has specified
         // the unqualified name. We have to concatenate the unqalified name
         // with the domain name.
-        opt_hostname_resp->setValue(d2_mgr.qualifyName(hostname));
+        opt_hostname_resp->setValue(d2_mgr.qualifyName(hostname,false));
     }
 
     answer->addOption(opt_hostname_resp);
@@ -1071,10 +1071,13 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
         // hostname is empty, it means that server is responsible for
         // generating the entire hostname for the client. The example of the
         // client's name, generated from the IP address is: host-192-0-2-3.
-        if ((fqdn || opt_hostname) && lease->hostname_.empty()) {
-            lease->hostname_ = CfgMgr::instance()
-                               .getD2ClientMgr().generateFqdn(lease->addr_);
-
+	if ((fqdn || opt_hostname) && lease->hostname_.empty()) {
+		if(fqdn) {
+			lease->hostname_ = CfgMgr::instance().getD2ClientMgr().generateFqdn(lease->addr_,true);
+		}
+		if(opt_hostname) {
+			lease->hostname_ = CfgMgr::instance().getD2ClientMgr().generateFqdn(lease->addr_,false);
+		}
             // The operations below are rather safe, but we want to catch
             // any potential exceptions (e.g. invalid lease database backend
             // implementation) and log an error.

+ 1 - 1
src/bin/dhcp4/tests/fqdn_unittest.cc

@@ -139,7 +139,7 @@ public:
     ///
     /// @return An std::string contained the generated FQDN.
     std::string generatedNameFromAddress(const IOAddress& addr) {
-        return(CfgMgr::instance().getD2ClientMgr().generateFqdn(addr));
+        return(CfgMgr::instance().getD2ClientMgr().generateFqdn(addr,true));
     }
 
     // Get the Client FQDN Option from the given message.

+ 1 - 1
src/bin/dhcp6/dhcp6_srv.cc

@@ -2609,7 +2609,7 @@ Dhcpv6Srv::generateFqdn(const Pkt6Ptr& answer) {
     // Get the IPv6 address acquired by the client.
     IOAddress addr = iaaddr->getAddress();
     std::string generated_name =
-        CfgMgr::instance().getD2ClientMgr().generateFqdn(addr);
+        CfgMgr::instance().getD2ClientMgr().generateFqdn(addr,true);
     try {
         // The lease has been acquired but the FQDN for this lease hasn't
         // been updated in the lease database. We now have new FQDN

+ 18 - 6
src/lib/dhcpsrv/d2_client_mgr.cc

@@ -171,31 +171,43 @@ D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n,
 }
 
 std::string
-D2ClientMgr::generateFqdn(const asiolink::IOAddress& address) const {
+D2ClientMgr::generateFqdn(const asiolink::IOAddress& address, bool appendDot) const {
     std::string hostname = address.toText();
     std::replace(hostname.begin(), hostname.end(),
                  (address.isV4() ? '.' : ':'), '-');
 
     std::ostringstream gen_name;
     gen_name << d2_client_config_->getGeneratedPrefix() << "-" << hostname;
-    return (qualifyName(gen_name.str()));
+    return (qualifyName(gen_name.str(),appendDot));
 }
 
+
 std::string
-D2ClientMgr::qualifyName(const std::string& partial_name) const {
+D2ClientMgr::qualifyName(const std::string& partial_name, bool appendDot) const {
     std::ostringstream gen_name;
+
     gen_name << partial_name << "." << d2_client_config_->getQualifyingSuffix();
 
-    // Tack on a trailing dot in case suffix doesn't have one.
     std::string str = gen_name.str();
     size_t len = str.length();
-    if ((len > 0) && (str[len - 1] != '.')) {
-        gen_name << ".";
+    //unless it's forced, will append trailing dot
+    if(appendDot) {
+	    // Tack on a trailing dot in case suffix doesn't have one.
+	    if ((len > 0) && (str[len - 1] != '.')) {
+		    gen_name << ".";
+	    }
+    } else {
+	    //if a call with appendDot is false, remove the dot if exists
+	    if ((len > 0) && (str[len - 1] == '.')) {
+		    gen_name.str(str.substr(0,len-1));
+	    }
     }
 
     return (gen_name.str());
 }
 
+
+
 void
 D2ClientMgr::startSender(D2ClientErrorHandler error_handler) {
     if (amSending()) {

+ 5 - 3
src/lib/dhcpsrv/d2_client_mgr.h

@@ -172,9 +172,10 @@ public:
     /// ('.' for IPv4 or ':' for IPv6) replaced with a hyphen, '-'.
     ///
     /// @param address IP address from which to derive the name (IPv4 or IPv6)
+    /// @param appendDot wether if a trailing dot should be appended or not
     ///
     /// @return std::string containing the generated name.
-    std::string generateFqdn(const asiolink::IOAddress& address) const;
+    std::string generateFqdn(const asiolink::IOAddress& address, bool appendDot) const;
 
     /// @brief Adds a qualifying suffix to a given domain name
     ///
@@ -186,9 +187,10 @@ public:
     /// one.
     ///
     /// @param partial_name domain name to qualify
+    /// @param appendDot wether if a trailing dot should be appended or not
     ///
     /// @return std::string containing the qualified name.
-    std::string qualifyName(const std::string& partial_name) const;
+    std::string qualifyName(const std::string& partial_name, bool appendDot) const;
 
     /// @brief Set server FQDN flags based on configuration and a given FQDN
     ///
@@ -465,7 +467,7 @@ D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) {
     } else {
         // If the supplied name is partial, qualify it by adding the suffix.
         if (fqdn.getDomainNameType() == T::PARTIAL) {
-            fqdn_resp.setDomainName(qualifyName(fqdn.getDomainName()), T::FULL);
+            fqdn_resp.setDomainName(qualifyName(fqdn.getDomainName(),true), T::FULL);
         }
     }
 }

+ 37 - 6
src/lib/dhcpsrv/tests/d2_client_unittest.cc

@@ -601,6 +601,8 @@ TEST(D2ClientMgr, qualifyName) {
 
     // Create enabled configuration.
     D2ClientConfigPtr cfg;
+
+    //append suffix and dot
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
                                   isc::asiolink::IOAddress("127.0.0.1"), 478,
@@ -612,9 +614,38 @@ TEST(D2ClientMgr, qualifyName) {
 
     // Verify that the qualifying suffix gets appended with trailing dot added.
     std::string partial_name = "somehost";
-    std::string qualified_name = mgr.qualifyName(partial_name);
+    std::string qualified_name = mgr.qualifyName(partial_name,true);
     EXPECT_EQ("somehost.suffix.com.", qualified_name);
 
+
+	//append suffix but dot
+    ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
+                                  dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+                                  false, false, true, false,
+                                  "prefix", "suffix.com")));
+    ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+    partial_name = "somehost";
+    qualified_name = mgr.qualifyName(partial_name,false); //false means no dot
+    EXPECT_EQ("somehost.suffix.com", qualified_name);
+
+
+	//append no suffix and not dot
+    ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
+                                  dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+                                  false, false, true, false,
+                                  "prefix", ""))); //empty suffix
+    ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
+    partial_name = "somehost";
+    qualified_name = mgr.qualifyName(partial_name,false); //false means no dot
+    EXPECT_EQ("somehost", qualified_name);
+
+    // Verify that the qualifying suffix gets appended with trailing dot added.
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
                                   isc::asiolink::IOAddress("127.0.0.1"), 478,
@@ -625,7 +656,7 @@ TEST(D2ClientMgr, qualifyName) {
     ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
 
     // Verify that the qualifying suffix gets appended without dot added.
-    qualified_name = mgr.qualifyName(partial_name);
+    qualified_name = mgr.qualifyName(partial_name,true);
     EXPECT_EQ("somehost.hasdot.com.", qualified_name);
 }
 
@@ -647,19 +678,19 @@ TEST(D2ClientMgr, generateFqdn) {
 
     // Verify that it works with an IPv4 address.
     asiolink::IOAddress v4address("192.0.2.75");
-    EXPECT_EQ("prefix-192-0-2-75.suffix.com.", mgr.generateFqdn(v4address));
+    EXPECT_EQ("prefix-192-0-2-75.suffix.com.", mgr.generateFqdn(v4address,true));
 
     // Verify that it works with an IPv6 address.
     asiolink::IOAddress v6address("2001:db8::2");
-    EXPECT_EQ("prefix-2001-db8--2.suffix.com.", mgr.generateFqdn(v6address));
+    EXPECT_EQ("prefix-2001-db8--2.suffix.com.", mgr.generateFqdn(v6address,true));
 
     // Create a disabled config.
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig()));
     ASSERT_NO_THROW(mgr.setD2ClientConfig(cfg));
 
     // Verify names generate properly with a disabled configuration.
-    EXPECT_EQ("myhost-192-0-2-75.example.com.", mgr.generateFqdn(v4address));
-    EXPECT_EQ("myhost-2001-db8--2.example.com.", mgr.generateFqdn(v6address));
+    EXPECT_EQ("myhost-192-0-2-75.example.com.", mgr.generateFqdn(v4address,true));
+    EXPECT_EQ("myhost-2001-db8--2.example.com.", mgr.generateFqdn(v6address,true));
 }
 
 /// @brief Tests adjustDomainName template method with Option4ClientFqdn