]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4142] Initial fix minus UTs
authorThomas Markwalder <tmark@isc.org>
Thu, 2 Oct 2025 18:10:19 +0000 (14:10 -0400)
committerAndrei Pavel <andrei@isc.org>
Mon, 27 Oct 2025 15:19:08 +0000 (17:19 +0200)
/src/bin/dhcp4/dhcp4_messages.*
    DHCP4_CLIENT_HOSTNAME_SCRUBBED_EMPTY
    DHCP4_CLIENT_FQDN_SCRUBBED_EMPTY - new messages

/src/bin/dhcp4/dhcp4_srv.cc
    Dhcpv4Srv::processClientFqdnOption() - catch FQDNScrubbedEmtpy, log and drop FQDN option

    Dhcpv4Srv::processHostnameOption() - log and drop hostname option if scrubbed empty

/src/bin/dhcp6/dhcp6_messages.*
    DHCP6_CLIENT_FQDN_SCRUBBED_EMPTY - new message

/src/bin/dhcp6/dhcp6_srv.cc
    Dhcpv6Srv::processClientFqdn() - catch FQDNScrubbedEmtpy, log and drop FQDN option

/src/lib/dhcpsrv/d2_client_mgr.h
    FQDNScrubbedEmpty - new exception type
    D2ClientMgr:: adjustDomainName() - throw FQDNScrubbedEmpty when FQDN is scrubbed empty

src/bin/dhcp4/dhcp4_messages.h
src/bin/dhcp4/dhcp4_messages.mes
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp6/dhcp6_messages.h
src/bin/dhcp6/dhcp6_messages.mes
src/bin/dhcp6/dhcp6_srv.cc
src/lib/dhcpsrv/d2_client_mgr.h

index 97a9ac3a3bf7c14d4980db91dc210dd55c30ee12..18472293e36245efbb2dedfe6fa26d4c92394b8c 100644 (file)
@@ -27,9 +27,11 @@ extern const isc::log::MessageID DHCP4_CLASS_UNCONFIGURED;
 extern const isc::log::MessageID DHCP4_CLIENTID_IGNORED_FOR_LEASES;
 extern const isc::log::MessageID DHCP4_CLIENT_FQDN_DATA;
 extern const isc::log::MessageID DHCP4_CLIENT_FQDN_PROCESS;
+extern const isc::log::MessageID DHCP4_CLIENT_FQDN_SCRUBBED_EMPTY;
 extern const isc::log::MessageID DHCP4_CLIENT_HOSTNAME_DATA;
 extern const isc::log::MessageID DHCP4_CLIENT_HOSTNAME_MALFORMED;
 extern const isc::log::MessageID DHCP4_CLIENT_HOSTNAME_PROCESS;
+extern const isc::log::MessageID DHCP4_CLIENT_HOSTNAME_SCRUBBED_EMPTY;
 extern const isc::log::MessageID DHCP4_CLIENT_NAME_PROC_FAIL;
 extern const isc::log::MessageID DHCP4_CONFIG_COMPLETE;
 extern const isc::log::MessageID DHCP4_CONFIG_LOAD_FAIL;
index d6279d4be89606f089bd417816d78c46effa78c2..fd9e4d17f9bd2da81bac9c6cb2ac5ca160bbae38 100644 (file)
@@ -164,6 +164,20 @@ This debug message is issued when the server starts processing the Hostname
 option sent in the client's query. The argument includes the client and
 transaction identification information.
 
+% DHCP4_CLIENT_HOSTNAME_SCRUBBED_EMPTY %1: sanitiziing client's Hostname option '%2' yielded an empty string
+Logged at debug log level 50.
+This debug message is issued when the result of sanitizing the
+hostname option(12) sent by the client is an empty string. When this occurs
+the server will ignore the hostname option. The arguments include the
+client and the hostname option it sent.
+
+% DHCP4_CLIENT_FQDN_SCRUBBED_EMPTY %1: sanitiziing client's FQDN option '%2' yielded an empty string
+Logged at debug log level 50.
+This debug message is issued when the result of sanitizing the
+FQDN option(81) sent by the client is an empty string. When this occurs
+the server will ignore the FQDN option. The arguments include the
+client and the FQDN option it sent.
+
 % DHCP4_CLIENT_NAME_PROC_FAIL %1: failed to process the fqdn or hostname sent by a client: %2
 Logged at debug log level 55.
 This debug message is issued when the DHCP server was unable to process the
index ca8ce1164a61aa7dce77bb653a1286c3ea5ef75e..137316a6d9d0fc28eabb3a47987cb25356c6a401 100644 (file)
@@ -2717,8 +2717,15 @@ Dhcpv4Srv::processClientFqdnOption(Dhcpv4Exchange& ex) {
     } else {
         // Adjust the domain name based on domain name value and type sent by the
         // client and current configuration.
-        d2_mgr.adjustDomainName<Option4ClientFqdn>(*fqdn, *fqdn_resp,
-                                                   *(ex.getContext()->getDdnsParams()));
+        try {
+            d2_mgr.adjustDomainName<Option4ClientFqdn>(*fqdn, *fqdn_resp,
+                                                       *(ex.getContext()->getDdnsParams()));
+        } catch (const FQDNScrubbedEmpty& scrubbed) {
+            LOG_DEBUG(ddns4_logger, DBG_DHCP4_DETAIL, DHCP4_CLIENT_FQDN_SCRUBBED_EMPTY)
+                    .arg(ex.getQuery()->getLabel())
+                    .arg(scrubbed.what());
+            return;
+        }
     }
 
     // Add FQDN option to the response message. Note that, there may be some
@@ -2860,7 +2867,15 @@ Dhcpv4Srv::processHostnameOption(Dhcpv4Exchange& ex) {
             ex.getContext()->getDdnsParams()->getHostnameSanitizer();
 
         if (sanitizer) {
-            hostname = sanitizer->scrub(hostname);
+            auto tmp = sanitizer->scrub(hostname);
+            if (tmp.empty()) {
+                LOG_DEBUG(ddns4_logger, DBG_DHCP4_DETAIL, DHCP4_CLIENT_HOSTNAME_SCRUBBED_EMPTY)
+                    .arg(ex.getQuery()->getLabel())
+                    .arg(hostname);
+                return;
+            }
+
+            hostname = tmp;
         }
 
         // Convert hostname to lower case.
index cae45ff60604556c92aa5bcd48ca39791b1d8a43..e251d4d917a81492f8e087724dcfb703ea704fe6 100644 (file)
@@ -28,6 +28,7 @@ extern const isc::log::MessageID DHCP6_CLASSES_ASSIGNED;
 extern const isc::log::MessageID DHCP6_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION;
 extern const isc::log::MessageID DHCP6_CLASS_ASSIGNED;
 extern const isc::log::MessageID DHCP6_CLASS_UNCONFIGURED;
+extern const isc::log::MessageID DHCP6_CLIENT_FQDN_SCRUBBED_EMPTY;
 extern const isc::log::MessageID DHCP6_CONFIG_COMPLETE;
 extern const isc::log::MessageID DHCP6_CONFIG_LOAD_FAIL;
 extern const isc::log::MessageID DHCP6_CONFIG_PACKET_QUEUE;
index e411ecc6fe470a3dd2fdd0dd0a6e85d19bf50a00..cc239d0668dd812be234d08b1de5c3c127f739d6 100644 (file)
@@ -1173,3 +1173,10 @@ such modification. The clients will remember previous server-id, and will
 use it to extend their leases. As a result, they will have to go through
 a rebinding phase to re-acquire their leases and associate them with a
 new server id.
+
+% DHCP6_CLIENT_FQDN_SCRUBBED_EMPTY %1: sanitiziing client's FQDN option '%2' yielded an empty string
+Logged at debug log level 50.
+This debug message is issued when the result of sanitizing the
+FQDN option(81) sent by the client is an empty string. When this occurs
+the server will ignore the FQDN option. The arguments include the
+client and the FQDN option it sent.
index c7cb73f36008648b79e3878262eb40153cfd9f6a..ce67a47c4505fea70859fa2138f23aa1befc152f 100644 (file)
@@ -2338,7 +2338,14 @@ Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer,
     } else {
         // Adjust the domain name based on domain name value and type sent by
         // the client and current configuration.
-        d2_mgr.adjustDomainName<Option6ClientFqdn>(*fqdn, *fqdn_resp, *ddns_params);
+        try {
+            d2_mgr.adjustDomainName<Option6ClientFqdn>(*fqdn, *fqdn_resp, *ddns_params);
+        } catch(const FQDNScrubbedEmpty& scrubbed) {
+            LOG_DEBUG(ddns6_logger, DBG_DHCP6_DETAIL, DHCP6_CLIENT_FQDN_SCRUBBED_EMPTY)
+                .arg(question->getLabel())
+                .arg(scrubbed.what());
+            return;
+        }
     }
 
     // Once we have the FQDN setup to use it for the lease hostname.  This
index 7344f19a4097ecccb4b5a9bcfb0b1d7926d3df0e..b160b47fe186405f5980253bee826cea4f048032 100644 (file)
 namespace isc {
 namespace dhcp {
 
+/// @brief Exception thrown upon attempt to add subnet with an ID that belongs
+/// to the subnet that already exists.
+class FQDNScrubbedEmpty : public Exception {
+public:
+    FQDNScrubbedEmpty(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { }
+};
+
 /// @brief Defines the type for D2 IO error handler.
 /// This callback is invoked when a send to kea-dhcp-ddns completes with a
 /// failed status.  This provides the application layer (Kea) with a means to
@@ -264,6 +272,9 @@ public:
     /// @param ddns_params DDNS behavioral configuration parameters
     /// @tparam T  FQDN Option class containing the FQDN data such as
     /// dhcp::Option4ClientFqdn or dhcp::Option6ClientFqdn
+    ///
+    /// @throw FQDNScrubbedEmtpy if hostname sanitizing reduces the input domain
+    /// name to an empty string.
     template <class T>
     void adjustDomainName(const T& fqdn, T& fqdn_resp,
                           const DdnsParams& ddns_params);
@@ -515,7 +526,12 @@ D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp, const DdnsParams& ddn
                 ss << sanitizer->scrub(label);
             }
 
-            client_name = ss.str();
+            std::string clean_name = ss.str();
+            if (clean_name.empty() || clean_name == ".") {
+                isc_throw(FQDNScrubbedEmpty, client_name);
+            }
+
+            client_name = clean_name;
         }
 
         // If the supplied name is partial, qualify it by adding the suffix.