diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 4f5c8fa521..8bf63f44d9 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -118,6 +118,43 @@ Dhcp4Hooks Hooks; namespace isc { namespace dhcp { +std::string AllocEngine::ClientContext4::get_domain_suffix()const { + + + // Subnet should have been already selected when the context was created. + Subnet4Ptr subnet = subnet_; + if (!subnet) { + // This particular client is out of luck today. We do not have + // information about the subnet he is connected to. This likely means + // misconfiguration of the server (or some relays). + + // Some other error, return an empty lease. + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_ASSIGNED) + .arg(query_->getLabel()) + .arg("NO SUBNET SELECTED FOR HOST") + .arg(currentHost()->getHostname()); + + return ""; + } + + if (subnet->getCfgOption()->empty()) { + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_ASSIGNED) + .arg(query_->getLabel()) + .arg("OPTIONS FOR SUBNET IS EMPTY") + .arg(currentHost()->getHostname()); + + return ""; + } + + std::string domain_suffix = subnet_->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_DOMAIN_NAME).formatted_value_; + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_ASSIGNED) + .arg(query_->getLabel()) + .arg("GOT DOMAIN SUFFIX") + .arg(domain_suffix); + + return domain_suffix; +} + Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, const Pkt4Ptr& query, const Subnet4Ptr& subnet) @@ -1638,16 +1675,18 @@ Dhcpv4Srv::processClientFqdnOption(Dhcpv4Exchange& ex) { fqdn_resp->setFlag(Option4ClientFqdn::FLAG_E, fqdn->getFlag(Option4ClientFqdn::FLAG_E)); + std::string domain_suffix = ex.getContext()->get_domain_suffix(); + if (ex.getContext()->currentHost() && !ex.getContext()->currentHost()->getHostname().empty()) { D2ClientMgr& d2_mgr = CfgMgr::instance().getD2ClientMgr(); - fqdn_resp->setDomainName(d2_mgr.qualifyName(ex.getContext()->currentHost()->getHostname(), + fqdn_resp->setDomainName(d2_mgr.qualifyName(ex.getContext()->currentHost()->getHostname(), domain_suffix, true), Option4ClientFqdn::FULL); } else { // Adjust the domain name based on domain name value and type sent by the // client and current configuration. - d2_mgr.adjustDomainName(*fqdn, *fqdn_resp); + d2_mgr.adjustDomainName(*fqdn, *fqdn_resp, domain_suffix); } // Add FQDN option to the response message. Note that, there may be some @@ -1684,6 +1723,7 @@ Dhcpv4Srv::processHostnameOption(Dhcpv4Exchange& ex) { } AllocEngine::ClientContext4Ptr ctx = ex.getContext(); + std::string domain_suffix = ex.getContext()->get_domain_suffix(); // Hostname reservations take precedence over any other configuration, // i.e. DDNS configuration. @@ -1720,7 +1760,7 @@ Dhcpv4Srv::processHostnameOption(Dhcpv4Exchange& ex) { // name for this client. if (should_send_hostname) { const std::string& hostname = - d2_mgr.qualifyName(ctx->currentHost()->getHostname(), + d2_mgr.qualifyName(ctx->currentHost()->getHostname(), domain_suffix, false); LOG_DEBUG(ddns4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_RESERVED_HOSTNAME_ASSIGNED) @@ -1815,7 +1855,7 @@ Dhcpv4Srv::processHostnameOption(Dhcpv4Exchange& ex) { // hostname. We don't want to append the trailing dot because // we don't know whether the hostname is partial or not and some // clients do not handle the hostnames with the trailing dot. - opt_hostname_resp->setValue(d2_mgr.qualifyName(hostname, false)); + opt_hostname_resp->setValue(d2_mgr.qualifyName(hostname, domain_suffix, false)); } LOG_DEBUG(ddns4_logger, DBG_DHCP4_DETAIL_DATA, DHCP4_RESPONSE_HOSTNAME_DATA) @@ -2107,7 +2147,7 @@ Dhcpv4Srv::assignLease(Dhcpv4Exchange& ex) { if (ctx->currentHost() && !ctx->currentHost()->getHostname().empty()) { lease->hostname_ = CfgMgr::instance().getD2ClientMgr() - .qualifyName(ctx->currentHost()->getHostname(), + .qualifyName(ctx->currentHost()->getHostname(), ctx->get_domain_suffix(), static_cast(fqdn)); should_update = true; diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 684ab39805..549777281d 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -1540,17 +1540,18 @@ Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer, // current configuration. d2_mgr.adjustFqdnFlags(*fqdn, *fqdn_resp); + std::string domain_suffix = ctx.get_domain_suffix(); // If there's a reservation and it has a hostname specified, use it! if (ctx.currentHost() && !ctx.currentHost()->getHostname().empty()) { // Add the qualifying suffix. // After #3765, this will only occur if the suffix is not empty. - fqdn_resp->setDomainName(d2_mgr.qualifyName(ctx.currentHost()->getHostname(), + fqdn_resp->setDomainName(d2_mgr.qualifyName(ctx.currentHost()->getHostname(), domain_suffix, true), Option6ClientFqdn::FULL); } else { // Adjust the domain name based on domain name value and type sent by // the client and current configuration. - d2_mgr.adjustDomainName(*fqdn, *fqdn_resp); + d2_mgr.adjustDomainName(*fqdn, *fqdn_resp, domain_suffix); } // Once we have the FQDN setup to use it for the lease hostname. This @@ -3521,7 +3522,7 @@ Dhcpv6Srv::updateReservedFqdn(const AllocEngine::ClientContext6& ctx, if (ctx.currentHost() && !ctx.currentHost()->getHostname().empty()) { std::string new_name = CfgMgr::instance().getD2ClientMgr(). - qualifyName(ctx.currentHost()->getHostname(), true); + qualifyName(ctx.currentHost()->getHostname(), ctx.get_domain_suffix(), true); if (new_name != name) { fqdn->setDomainName(new_name, Option6ClientFqdn::FULL); diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index c48f3857f5..1a63dbbfea 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -426,6 +426,42 @@ inAllowedPool(AllocEngine::ClientContext6& ctx, const Lease::Type& lease_type, namespace isc { namespace dhcp { +std::string AllocEngine::ClientContext6::get_domain_suffix()const { + + // Subnet should have been already selected when the context was created. + Subnet6Ptr subnet = subnet_; + if (!subnet) { + // This particular client is out of luck today. We do not have + // information about the subnet he is connected to. This likely means + // misconfiguration of the server (or some relays). + + // Some other error, return an empty lease. + LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_EXTEND_ERROR) + .arg(query_->getLabel()) + .arg("NO SUBNET SELECTED FOR HOST") + .arg(currentHost()->getHostname()); + + return ""; + } + + if (subnet->getCfgOption()->empty()) { + LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_EXTEND_ERROR) + .arg(query_->getLabel()) + .arg("OPTIONS FOR SUBNET IS EMPTY") + .arg(currentHost()->getHostname()); + + return ""; + } + + std::string domain_suffix = subnet_->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_DOMAIN_NAME).formatted_value_; + LOG_INFO(alloc_engine_logger, ALLOC_ENGINE_V6_EXTEND_ERROR) + .arg(query_->getLabel()) + .arg("GOT DOMAIN SUFFIX") + .arg(domain_suffix); + + return domain_suffix; +} + AllocEngine::ClientContext6::ClientContext6() : query_(), fake_allocation_(false), subnet_(), host_subnet_(), duid_(), hwaddr_(), host_identifiers_(), hosts_(), fwd_dns_update_(false), @@ -1075,7 +1111,7 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, // the hostname as it is specified for the reservation. OptionPtr fqdn = ctx.query_->getOption(D6O_CLIENT_FQDN); ctx.hostname_ = CfgMgr::instance().getD2ClientMgr(). - qualifyName(host->getHostname(), static_cast(fqdn)); + qualifyName(host->getHostname(), ctx.get_domain_suffix(), static_cast(fqdn)); } } } @@ -1147,7 +1183,7 @@ AllocEngine::allocateReservedLeases6(ClientContext6& ctx, // the hostname as it is specified for the reservation. OptionPtr fqdn = ctx.query_->getOption(D6O_CLIENT_FQDN); ctx.hostname_ = CfgMgr::instance().getD2ClientMgr(). - qualifyName(host->getHostname(), static_cast(fqdn)); + qualifyName(host->getHostname(), ctx.get_domain_suffix(), static_cast(fqdn)); } } diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index 3a64eb91a4..ea9d8c4d33 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -315,6 +315,8 @@ class AllocEngine : public boost::noncopyable { /// new information doesn't modify the API of the allocation engine. struct ClientContext6 : public boost::noncopyable { + std::string get_domain_suffix()const; + /// @name Parameters pertaining to DHCPv6 message //@{ @@ -1072,6 +1074,9 @@ class AllocEngine : public boost::noncopyable { /// information to the allocation engine methods is that adding /// new information doesn't modify the API of the allocation engine. struct ClientContext4 : public boost::noncopyable { + + std::string get_domain_suffix()const; + /// @brief Subnet selected for the client by the server. Subnet4Ptr subnet_; diff --git a/src/lib/dhcpsrv/d2_client_mgr.cc b/src/lib/dhcpsrv/d2_client_mgr.cc index 162eaf5443..8a43f22140 100644 --- a/src/lib/dhcpsrv/d2_client_mgr.cc +++ b/src/lib/dhcpsrv/d2_client_mgr.cc @@ -173,24 +173,29 @@ D2ClientMgr::generateFqdn(const asiolink::IOAddress& address, std::ostringstream gen_name; gen_name << d2_client_config_->getGeneratedPrefix() << "-" << hostname; - return (qualifyName(gen_name.str(), trailing_dot)); + return (qualifyName(gen_name.str(), "", trailing_dot)); } std::string -D2ClientMgr::qualifyName(const std::string& partial_name, +D2ClientMgr::qualifyName(const std::string& partial_name, const std::string& domain_suffix, const bool trailing_dot) const { std::ostringstream gen_name; gen_name << partial_name; - if (!d2_client_config_->getQualifyingSuffix().empty()) { + + std::string suffix = domain_suffix; + if(suffix.empty()) + suffix = d2_client_config_->getQualifyingSuffix(); + + if (!suffix.empty()) { std::string str = gen_name.str(); size_t len = str.length(); if ((len > 0) && (str[len - 1] != '.')) { gen_name << "."; } - gen_name << d2_client_config_->getQualifyingSuffix(); + gen_name << suffix; } std::string str = gen_name.str(); diff --git a/src/lib/dhcpsrv/d2_client_mgr.h b/src/lib/dhcpsrv/d2_client_mgr.h index 7a2de10d4c..4725e8a1cc 100644 --- a/src/lib/dhcpsrv/d2_client_mgr.h +++ b/src/lib/dhcpsrv/d2_client_mgr.h @@ -185,7 +185,7 @@ class D2ClientMgr : public dhcp_ddns::NameChangeSender::RequestSendHandler, /// suffix itself is empty (i.e. ""). /// /// @return std::string containing the qualified name. - std::string qualifyName(const std::string& partial_name, + std::string qualifyName(const std::string& partial_name, const std::string& domain_suffix, const bool trailing_dot) const; /// @brief Set server FQDN flags based on configuration and a given FQDN @@ -243,7 +243,7 @@ class D2ClientMgr : public dhcp_ddns::NameChangeSender::RequestSendHandler, /// @tparam T FQDN Option class containing the FQDN data such as /// dhcp::Option4ClientFqdn or dhcp::Option6ClientFqdn template - void adjustDomainName(const T& fqdn, T& fqdn_resp); + void adjustDomainName(const T& fqdn, T& fqdn_resp, const std::string& domain_suffix); /// @brief Enables sending NameChangeRequests to kea-dhcp-ddns /// @@ -454,7 +454,7 @@ D2ClientMgr::getUpdateDirections(const T& fqdn_resp, template void -D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) { +D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp, const std::string & domain_suffix) { // If we're configured to replace it or the supplied name is blank // set the response name to blank. if ((d2_client_config_->getReplaceClientNameMode() == D2ClientConfig::RCM_ALWAYS || @@ -464,7 +464,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(),true), T::FULL); + fqdn_resp.setDomainName(qualifyName(fqdn.getDomainName(), domain_suffix, true), T::FULL); } } }