Commit b767f944 authored by Thomas Markwalder's avatar Thomas Markwalder

[#35,!517] Modify D2ClientMgr functions to accept DdnsParams parameter

D2ClientMgr functions now get behavior parameters from a passed in
structure instead of D2ClientMgr::d2_client_config_.

src/lib/dhcpsrv/d2_client_cfg.h
    struct DdnsParams  - new structure to convey request specific
    (i.e.scopable) Ddns params

src/lib/dhcpsrv/alloc_engine.cc
src/lib/dhcpsrv/alloc_engine.h
    Added ddns_params_ to ClientContext4/6

src/lib/dhcpsrv/d2_client_mgr.*
    D2ClientMgr::adjustFqdnFlags()
    D2ClientMgr::adjustDomainName()
    D2ClientMgr::analyzeFqdn()
    D2ClientMgr::generateFqdn()
    D2ClientMgr::qualifyName() - now accept DdnsParams instance as
    parameter

src/lib/dhcpsrv/tests/d2_client_unittest.cc
    Reworked tests to use DdnsParams
parent cf6a766d
......@@ -430,7 +430,8 @@ namespace dhcp {
AllocEngine::ClientContext6::ClientContext6()
: query_(), fake_allocation_(false), subnet_(), host_subnet_(), duid_(),
hwaddr_(), host_identifiers_(), hosts_(), fwd_dns_update_(false),
rev_dns_update_(false), hostname_(), callout_handle_(), ias_() {
rev_dns_update_(false), hostname_(), callout_handle_(), ias_(),
ddns_params_(new DdnsParams()) {
}
AllocEngine::ClientContext6::ClientContext6(const Subnet6Ptr& subnet,
......@@ -445,7 +446,7 @@ AllocEngine::ClientContext6::ClientContext6(const Subnet6Ptr& subnet,
duid_(duid), hwaddr_(), host_identifiers_(), hosts_(),
fwd_dns_update_(fwd_dns), rev_dns_update_(rev_dns), hostname_(hostname),
callout_handle_(callout_handle), allocated_resources_(), new_leases_(),
ias_() {
ias_(), ddns_params_(new DdnsParams()) {
// Initialize host identifiers.
if (duid) {
......@@ -1156,7 +1157,8 @@ 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<bool>(fqdn));
qualifyName(host->getHostname(), *ctx.ddns_params_,
static_cast<bool>(fqdn));
}
}
}
......@@ -1228,7 +1230,8 @@ 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<bool>(fqdn));
qualifyName(host->getHostname(), *ctx.ddns_params_,
static_cast<bool>(fqdn));
}
}
......@@ -1303,7 +1306,8 @@ AllocEngine::allocateGlobalReservedLeases6(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(ghost->getHostname(), static_cast<bool>(fqdn));
qualifyName(ghost->getHostname(), *ctx.ddns_params_,
static_cast<bool>(fqdn));
}
// If this is a real allocation, we may need to extend the lease
......@@ -1353,7 +1357,8 @@ AllocEngine::allocateGlobalReservedLeases6(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(ghost->getHostname(), static_cast<bool>(fqdn));
qualifyName(ghost->getHostname(), *ctx.ddns_params_,
static_cast<bool>(fqdn));
}
// Ok, let's create a new lease...
......@@ -3002,7 +3007,8 @@ AllocEngine::ClientContext4::ClientContext4()
fwd_dns_update_(false), rev_dns_update_(false),
hostname_(""), callout_handle_(), fake_allocation_(false),
old_lease_(), new_lease_(), hosts_(), conflicting_lease_(),
query_(), host_identifiers_() {
query_(), host_identifiers_(),
ddns_params_(new DdnsParams()) {
}
AllocEngine::ClientContext4::ClientContext4(const Subnet4Ptr& subnet,
......@@ -3018,7 +3024,8 @@ AllocEngine::ClientContext4::ClientContext4(const Subnet4Ptr& subnet,
fwd_dns_update_(fwd_dns_update), rev_dns_update_(rev_dns_update),
hostname_(hostname), callout_handle_(),
fake_allocation_(fake_allocation), old_lease_(), new_lease_(),
hosts_(), host_identifiers_() {
hosts_(), host_identifiers_(),
ddns_params_(new DdnsParams()) {
// Initialize host identifiers.
if (hwaddr) {
......
......@@ -9,6 +9,7 @@
#include <asiolink/io_address.h>
#include <dhcp/classify.h>
#include <dhcpsrv/d2_client_cfg.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <dhcp/pkt4.h>
......@@ -552,6 +553,9 @@ public:
/// @brief Container holding IA specific contexts.
std::vector<IAContext> ias_;
/// @brief Holds scoped DDNS behavioral parameters
DdnsParamsPtr ddns_params_;
/// @brief Convenience method adding allocated prefix or address.
///
/// @param prefix Prefix or address.
......@@ -1319,6 +1323,9 @@ public:
/// received by the server.
IdentifierList host_identifiers_;
/// @brief Holds scoped DDNS behavioral parameters
DdnsParamsPtr ddns_params_;
/// @brief Convenience function adding host identifier into
/// @ref host_identifiers_ list.
///
......
......@@ -369,6 +369,41 @@ operator<<(std::ostream& os, const D2ClientConfig& config);
/// @brief Defines a pointer for D2ClientConfig instances.
typedef boost::shared_ptr<D2ClientConfig> D2ClientConfigPtr;
/// @Brief Convenience container for conveying DDNS behaviorial parameters
/// It is intended to be populated per Packet exchange and passed into
/// functions that require them
struct DdnsParams {
DdnsParams() :
enable_updates_(false), override_no_update_(false), override_client_update_(false),
replace_client_name_mode_(D2ClientConfig::RCM_NEVER),
generated_prefix_(""), qualifying_suffix_("") {};
/// @brief Indicates whether or not DHCP DDNS updating is enabled.
bool enable_updates_;
/// @brief Should Kea perform updates, even if client requested no updates.
/// Overrides the client request for no updates via the N flag.
bool override_no_update_;
/// @brief Should Kea perform updates, even if client requested delegation.
bool override_client_update_;
/// @brief How Kea should handle the domain-name supplied by the client.
D2ClientConfig::ReplaceClientNameMode replace_client_name_mode_;
/// @brief Prefix Kea should use when generating domain-names.
std::string generated_prefix_;
/// @brief Suffix Kea should use when to qualify partial domain-names.
std::string qualifying_suffix_;
/// @brief Pointer to compiled regular expression string sanitizer
util::str::StringSanitizerPtr hostname_sanitizer_;
};
/// @brief Defines a pointer for DdnsParams instances.
typedef boost::shared_ptr<DdnsParams> DdnsParamsPtr;
} // namespace isc
} // namespace dhcp
......
......@@ -114,7 +114,8 @@ D2ClientMgr::getD2ClientConfig() const {
void
D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n,
bool& server_s, bool& server_n) const {
bool& server_s, bool& server_n,
const DdnsParams& ddns_params) const {
// Per RFC 4702 & 4704, the client N and S flags allow the client to
// request one of three options:
//
......@@ -132,27 +133,27 @@ D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n,
switch (mask) {
case 0:
if (!d2_client_config_->getEnableUpdates()) {
if (!ddns_params.enable_updates_) {
server_s = false;
server_n = true;
} else {
// If updates are enabled and we are overriding client delegation
// then S flag should be true. N-flag should be false.
server_s = d2_client_config_->getOverrideClientUpdate();
server_s = ddns_params.override_client_update_;
server_n = false;
}
break;
case 1:
server_s = d2_client_config_->getEnableUpdates();
server_s = ddns_params.enable_updates_;
server_n = !server_s;
break;
case 2:
// If updates are enabled and we are overriding "no updates" then
// S flag should be true.
server_s = (d2_client_config_->getEnableUpdates() &&
d2_client_config_->getOverrideNoUpdate());
server_s = (ddns_params.enable_updates_ &&
ddns_params.override_no_update_);
server_n = !server_s;
break;
......@@ -166,31 +167,33 @@ D2ClientMgr::analyzeFqdn(const bool client_s, const bool client_n,
std::string
D2ClientMgr::generateFqdn(const asiolink::IOAddress& address,
const DdnsParams& ddns_params,
const bool trailing_dot) 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(), trailing_dot));
gen_name << ddns_params.generated_prefix_ << "-" << hostname;
return (qualifyName(gen_name.str(), ddns_params, trailing_dot));
}
std::string
D2ClientMgr::qualifyName(const std::string& partial_name,
const DdnsParams& ddns_params,
const bool trailing_dot) const {
std::ostringstream gen_name;
gen_name << partial_name;
if (!d2_client_config_->getQualifyingSuffix().empty()) {
if (!ddns_params.qualifying_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 << ddns_params.qualifying_suffix_;
}
std::string str = gen_name.str();
......
......@@ -147,11 +147,12 @@ public:
/// @param client_n N Flag from the client's FQDN
/// @param server_s [out] S Flag for the server's FQDN
/// @param server_n [out] N Flag for the server's FQDN
/// @param ddns_params DDNS behaviorial configuration parameters
///
/// @throw isc::BadValue if client_s and client_n are both 1 as this is
/// an invalid combination per RFCs.
void analyzeFqdn(const bool client_s, const bool client_n, bool& server_s,
bool& server_n) const;
bool& server_n, const DdnsParams& ddns_params) const;
/// @brief Builds a FQDN based on the configuration and given IP address.
///
......@@ -166,11 +167,13 @@ public:
/// ('.' for IPv4 or ':' for IPv6) replaced with a hyphen, '-'.
///
/// @param address IP address from which to derive the name (IPv4 or IPv6)
/// @param ddns_params DDNS behaviorial configuration parameters
/// @param trailing_dot A boolean value which indicates whether trailing
/// dot should be appended (if true) or not (false).
///
/// @return std::string containing the generated name.
std::string generateFqdn(const asiolink::IOAddress& address,
const DdnsParams& ddns_params,
const bool trailing_dot = true) const;
/// @brief Adds a qualifying suffix to a given domain name
......@@ -181,6 +184,7 @@ public:
/// <partial_name>.<qualifying-suffix>.
///
/// @param partial_name domain name to qualify
/// @param ddns_params DDNS behaviorial configuration parameters
/// @param trailing_dot A boolean value which when true guarantees the
/// result will end with a "." and when false that the result will not
/// end with a "." Note that this rule is applied even if the qualifying
......@@ -188,6 +192,7 @@ public:
///
/// @return std::string containing the qualified name.
std::string qualifyName(const std::string& partial_name,
const DdnsParams& ddns_params,
const bool trailing_dot) const;
/// @brief Set server FQDN flags based on configuration and a given FQDN
......@@ -199,10 +204,12 @@ public:
///
/// @param fqdn FQDN option from which to read client (inbound) flags
/// @param fqdn_resp FQDN option to update with the server (outbound) flags
/// @param ddns_params DDNS behaviorial configuration parameters
/// @tparam T FQDN Option class containing the FQDN data such as
/// dhcp::Option4ClientFqdn or dhcp::Option6ClientFqdn
template <class T>
void adjustFqdnFlags(const T& fqdn, T& fqdn_resp);
void adjustFqdnFlags(const T& fqdn, T& fqdn_resp,
const DdnsParams& ddns_params);
/// @brief Get directional update flags based on server FQDN flags
///
......@@ -248,10 +255,12 @@ public:
///
/// @param fqdn FQDN option from which to get client (inbound) name
/// @param fqdn_resp FQDN option to update with the adjusted name
/// @param ddns_params DDNS behaviorial configuration parameters
/// @tparam T FQDN Option class containing the FQDN data such as
/// dhcp::Option4ClientFqdn or dhcp::Option6ClientFqdn
template <class T>
void adjustDomainName(const T& fqdn, T& fqdn_resp);
void adjustDomainName(const T& fqdn, T& fqdn_resp,
const DdnsParams& ddns_params);
/// @brief Enables sending NameChangeRequests to kea-dhcp-ddns
///
......@@ -435,11 +444,11 @@ private:
template <class T>
void
D2ClientMgr::adjustFqdnFlags(const T& fqdn, T& fqdn_resp) {
D2ClientMgr::adjustFqdnFlags(const T& fqdn, T& fqdn_resp, const DdnsParams& ddns_params) {
bool server_s = false;
bool server_n = false;
analyzeFqdn(fqdn.getFlag(T::FLAG_S), fqdn.getFlag(T::FLAG_N),
server_s, server_n);
server_s, server_n, ddns_params);
// Reset the flags to zero to avoid triggering N and S both 1 check.
fqdn_resp.resetFlags();
......@@ -462,18 +471,18 @@ D2ClientMgr::getUpdateDirections(const T& fqdn_resp,
template <class T>
void
D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) {
D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp, const DdnsParams& ddns_params) {
// 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 ||
d2_client_config_->getReplaceClientNameMode() == D2ClientConfig::RCM_WHEN_PRESENT) ||
if ((ddns_params.replace_client_name_mode_ == D2ClientConfig::RCM_ALWAYS ||
ddns_params.replace_client_name_mode_ == D2ClientConfig::RCM_WHEN_PRESENT) ||
fqdn.getDomainName().empty()) {
fqdn_resp.setDomainName("", T::PARTIAL);
} else {
// Sanitize the name the client sent us, if we're configured to do so.
std::string client_name = fqdn.getDomainName();
if (d2_client_config_->getHostnameSanitizer()) {
if (ddns_params.hostname_sanitizer_) {
// We need the raw text form, so we can replace escaped chars
dns::Name tmp(client_name);
std::string raw_name = tmp.toRawText();
......@@ -490,7 +499,7 @@ D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) {
ss << ".";
}
ss << d2_client_config_->getHostnameSanitizer()->scrub(*label);
ss << ddns_params.hostname_sanitizer_->scrub(*label);
}
client_name = ss.str();
......@@ -498,7 +507,7 @@ D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) {
// If the supplied name is partial, qualify it by adding the suffix.
if (fqdn.getDomainNameType() == T::PARTIAL) {
fqdn_resp.setDomainName(qualifyName(client_name,true), T::FULL);
fqdn_resp.setDomainName(qualifyName(client_name, ddns_params, true), T::FULL);
}
else {
fqdn_resp.setDomainName(client_name, T::FULL);
......@@ -506,6 +515,7 @@ D2ClientMgr::adjustDomainName(const T& fqdn, T& fqdn_resp) {
}
}
/// @brief Defines a pointer for D2ClientMgr instances.
typedef boost::shared_ptr<D2ClientMgr> D2ClientMgrPtr;
......
......@@ -1440,11 +1440,13 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
// qualifying-suffix is the only parameter which has no default
std::string qualifying_suffix = "";
#if 0
bool found_qualifying_suffix = false;
if (client_config->contains("qualifying-suffix")) {
qualifying_suffix = getString(client_config, "qualifying-suffix");
found_qualifying_suffix = true;
}
#endif
IOAddress sender_ip(0);
if (sender_ip_str.empty()) {
......@@ -1461,6 +1463,7 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
}
}
#if 0
// Qualifying-suffix is required when updates are enabled
if (enable_updates && !found_qualifying_suffix) {
isc_throw(DhcpConfigError,
......@@ -1468,6 +1471,7 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
"updates are enabled ("
<< client_config->getPosition() << ")");
}
#endif
// Now we check for logical errors. This repeats what is done in
// D2ClientConfig::validate(), but doing it here permits us to
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment