diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds.cc b/src/hooks/dhcp/lease_cmds/lease_cmds.cc index 54bc8d3b6e..90e22b77d6 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds.cc +++ b/src/hooks/dhcp/lease_cmds/lease_cmds.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ using namespace isc::dhcp; using namespace isc::data; +using namespace isc::dhcp_ddns; using namespace isc::config; using namespace isc::asiolink; using namespace isc::hooks; @@ -282,6 +284,24 @@ public: int lease6WipeHandler(CalloutHandle& handle); + /// @brief lease4-resend-ddns handler + /// + /// Provides the implementation for @ref isc::lease_cmds::LeaseCmds::lease4ResendDdnsHandler + /// + /// @param handle Callout context - which is expected to contain the + /// wipe command JSON text in the "command" argument + /// @return 0 upon success, non-zero otherwise + int lease4ResendDdnsHandler(CalloutHandle& handle); + + /// @brief lease6-resend-ddns handler + /// + /// Provides the implementation for @ref isc::lease_cmds::LeaseCmds::lease6ResendDdnsHandler + /// + /// @param handle Callout context - which is expected to contain the + /// wipe command JSON text in the "command" argument + /// @return 0 upon success, non-zero otherwise + int lease6ResendDdnsHandler(CalloutHandle& handle); + /// @brief Extracts parameters required for reservation-get and reservation-del /// /// See @ref Parameters class for detailed description of what is expected @@ -329,6 +349,16 @@ public: const DuidPtr& duid, const int control_result, const std::string& error_message) const; + + /// @brief Fetches an IP address parameter from a map of parameters + /// @param map of parameters in which to look + /// @name name of the parameter desired + /// @family expected protocol family of the address parameter, AF_INET + /// or AF_INET6 + /// @return IOAddress containing the value of the parameter. + /// @throw BadValue if the parameter is missing or invalid + IOAddress getAddressParam(ConstElementPtr params, const std::string name, + short family = AF_INET) const; }; int @@ -1543,6 +1573,121 @@ LeaseCmdsImpl::getIPv6LeaseForDelete(const Parameters& parameters) const { return (lease6); } +IOAddress +LeaseCmdsImpl::getAddressParam(ConstElementPtr params, const std::string name, + short family) const { + ConstElementPtr param = params->get(name); + if (!param) { + isc_throw(BadValue, "'" << name << "' parameter is missing."); + } + + if (param->getType() != Element::string) { + isc_throw(BadValue, "'" << name << "' is not a string."); + } + + IOAddress addr(0); + try { + addr = IOAddress(param->stringValue()); + } catch (const std::exception& ex) { + isc_throw(BadValue, "'" << param->stringValue() + << "' is not a valid IP address."); + } + + if (addr.getFamily() != family) { + isc_throw(BadValue, "Invalid " + << (family == AF_INET6 ? "IPv6" : "IPv4") + << " address specified: " << param->stringValue()); + } + + return (addr); +} + +int +LeaseCmdsImpl::lease4ResendDdnsHandler(CalloutHandle& handle) { + Lease4Ptr lease; + std::stringstream ss; + + try { + extractCommand(handle); + + // Get the target lease address. Invalid value will throw. + IOAddress addr = getAddressParam(cmd_args_, "ip-address", AF_INET); + + // Find the lease. + lease = LeaseMgrFactory::instance().getLease4(addr); + if (!lease) { + ss << "No lease found for: " << addr.toText(); + } else if (lease->hostname_.empty()) { + ss << "Lease for: " << addr.toText() + << ", has no hostname, nothing to update"; + } else if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) { + ss << "Neither forward nor reverse updates enabled for lease for: " + << addr.toText(); + } else if (!CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) { + ss << "DDNS updating is not enabled"; + } else { + // We have a lease with a hostname and updates in at least + // one direction enabled. Queue an NCR for it. + queueNCR(CHG_ADD, lease); + ss << "NCR generated for: " << addr.toText() + << ", hostname: " << lease->hostname_; + setSuccessResponse(handle, ss.str()); + LOG_INFO(lease_cmds_logger, LEASE_CMDS_RESEND_DDNS4).arg(ss.str()); + return (CONTROL_RESULT_SUCCESS); + } + } catch (const std::exception& ex) { + ss << ex.what(); + } + + LOG_ERROR(lease_cmds_logger, LEASE_CMDS_RESEND_DDNS4_FAILED).arg(ss.str()); + setErrorResponse(handle, ss.str()); + return (CONTROL_RESULT_ERROR); +} + +int +LeaseCmdsImpl::lease6ResendDdnsHandler(CalloutHandle& handle) { + Lease6Ptr lease; + std::stringstream ss; + + try { + extractCommand(handle); + + // Get the target lease address. Invalid value will throw. + IOAddress addr = getAddressParam(cmd_args_, "ip-address", AF_INET6); + + // Find the lease. + lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr); + if (!lease) { + ss << "No lease found for: " << addr.toText(); + } else if (lease->hostname_.empty()) { + ss << "Lease for: " << addr.toText() + << ", has no hostname, nothing to update"; + } else if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) { + ss << "Neither forward nor reverse updates enabled for lease for: " + << addr.toText(); + } else if (!CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) { + ss << "DDNS updating is not enabled"; + } else { + // We have a lease with a hostname and updates in at least + // one direction enabled. Queue an NCR for it. + queueNCR(CHG_ADD, lease); + ss << "NCR generated for: " << addr.toText() + << ", hostname: " << lease->hostname_; + setSuccessResponse(handle, ss.str()); + LOG_INFO(lease_cmds_logger, LEASE_CMDS_RESEND_DDNS6).arg(ss.str()); + return (CONTROL_RESULT_SUCCESS); + } + } catch (const std::exception& ex) { + ss << ex.what(); + } + + LOG_ERROR(lease_cmds_logger, LEASE_CMDS_RESEND_DDNS6_FAILED).arg(ss.str()); + setErrorResponse(handle, ss.str()); + return (CONTROL_RESULT_ERROR); +} + + + ElementPtr LeaseCmdsImpl::createFailedLeaseMap(const Lease::Type& lease_type, const IOAddress& lease_address, @@ -1651,6 +1796,16 @@ LeaseCmds::lease6WipeHandler(CalloutHandle& handle) { return (impl_->lease6WipeHandler(handle)); } +int +LeaseCmds::lease4ResendDdnsHandler(CalloutHandle& handle) { + return (impl_->lease4ResendDdnsHandler(handle)); +} + +int +LeaseCmds::lease6ResendDdnsHandler(CalloutHandle& handle) { + return (impl_->lease6ResendDdnsHandler(handle)); +} + LeaseCmds::LeaseCmds() :impl_(new LeaseCmdsImpl()) { } diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds.h b/src/hooks/dhcp/lease_cmds/lease_cmds.h index 86245f7f80..af8185661b 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds.h +++ b/src/hooks/dhcp/lease_cmds/lease_cmds.h @@ -525,6 +525,56 @@ public: int lease6WipeHandler(hooks::CalloutHandle& handle); + /// @brief lease4-resend-ddns command handler + /// + /// This command attempts to resend the DDNS updates for the IPv4 lease that + /// matches the selection criteria. + /// + /// It extracts the command name and arguments from the given Callouthandle, + /// attempts to process them, and then set's the handle's "response" + /// argument accordingly. + /// + /// A single parameter is supported: ip-address: + /// + /// Example command to resend DDNS based on existing FDQN and flags + /// { + /// "command": "lease4-resend-ddns", + /// "arguments": { + /// "ip-address": "192.0.2.202" + /// } + /// } + /// + /// @param handle Callout context - which is expected to contain the + /// delete command JSON text in the "command" argument + /// @return result of the operation + int + lease4ResendDdnsHandler(hooks::CalloutHandle& handle); + + /// @brief lease6-resend-ddns command handler + /// + /// This command attempts to resend the DDNS updates for the IPv6 lease that + /// matches the selection criteria. + /// + /// It extracts the command name and arguments from the given Callouthandle, + /// attempts to process them, and then set's the handle's "response" + /// argument accordingly. + /// + /// A single parameter is supported: ip-address: + /// + /// Example command to resend DDNS based on existing FDQN and flags + /// { + /// "command": "lease6-resend-ddns", + /// "arguments": { + /// "ip-address": "2001:db8:abcd::", + /// } + /// } + /// + /// @param handle Callout context - which is expected to contain the + /// delete command JSON text in the "command" argument + /// @return result of the operation + int + lease6ResendDdnsHandler(hooks::CalloutHandle& handle); + private: /// Pointer to the actual implementation boost::shared_ptr impl_; diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc b/src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc index f261256213..4136deb5cc 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc +++ b/src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc @@ -242,6 +242,28 @@ int lease6_wipe(CalloutHandle& handle) { return(lease_cmds.lease6WipeHandler(handle)); } +/// @brief This is a command callout for 'lease4-resend-ddns' command. +/// +/// @param handle Callout handle used to retrieve a command and +/// provide a response. +/// @return 0 if this callout has been invoked successfully, +/// 1 otherwise. +int lease4_resend_ddns(CalloutHandle& handle) { + LeaseCmds lease_cmds; + return(lease_cmds.lease4ResendDdnsHandler(handle)); +} + +/// @brief This is a command callout for 'lease6-resend-ddns' command. +/// +/// @param handle Callout handle used to retrieve a command and +/// provide a response. +/// @return 0 if this callout has been invoked successfully, +/// 1 otherwise. +int lease6_resend_ddns(CalloutHandle& handle) { + LeaseCmds lease_cmds; + return(lease_cmds.lease6ResendDdnsHandler(handle)); +} + /// @brief This function is called when the library is loaded. /// /// @param handle library handle @@ -271,6 +293,8 @@ int load(LibraryHandle& handle) { handle.registerCommandCallout("lease6-update", lease6_update); handle.registerCommandCallout("lease4-wipe", lease4_wipe); handle.registerCommandCallout("lease6-wipe", lease6_wipe); + handle.registerCommandCallout("lease4-resend-ddns", lease4_resend_ddns); + handle.registerCommandCallout("lease6-resend-ddns", lease6_resend_ddns); LOG_INFO(lease_cmds_logger, LEASE_CMDS_INIT_OK); return (0); diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds_messages.cc b/src/hooks/dhcp/lease_cmds/lease_cmds_messages.cc index dad1ccb580..648e5d4f96 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds_messages.cc +++ b/src/hooks/dhcp/lease_cmds/lease_cmds_messages.cc @@ -1,4 +1,4 @@ -// File created from ../../../../src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes on Fri Feb 08 2019 20:34 +// File created from ../../../../src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes on Fri Mar 13 2020 14:35 #include #include @@ -16,6 +16,10 @@ extern const isc::log::MessageID LEASE_CMDS_DEL6 = "LEASE_CMDS_DEL6"; extern const isc::log::MessageID LEASE_CMDS_DEL6_FAILED = "LEASE_CMDS_DEL6_FAILED"; extern const isc::log::MessageID LEASE_CMDS_INIT_FAILED = "LEASE_CMDS_INIT_FAILED"; extern const isc::log::MessageID LEASE_CMDS_INIT_OK = "LEASE_CMDS_INIT_OK"; +extern const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4 = "LEASE_CMDS_RESEND_DDNS4"; +extern const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4_FAILED = "LEASE_CMDS_RESEND_DDNS4_FAILED"; +extern const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6 = "LEASE_CMDS_RESEND_DDNS6"; +extern const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6_FAILED = "LEASE_CMDS_RESEND_DDNS6_FAILED"; namespace { @@ -32,6 +36,10 @@ const char* values[] = { "LEASE_CMDS_DEL6_FAILED", "lease6-del command failed (parameters: %1, reason: %2)", "LEASE_CMDS_INIT_FAILED", "loading Lease Commands hooks library failed: %1", "LEASE_CMDS_INIT_OK", "loading Lease Commands hooks library successful", + "LEASE_CMDS_RESEND_DDNS4", "lease6-resend-ddns command successful: %1", + "LEASE_CMDS_RESEND_DDNS4_FAILED", "lease6-resend-ddns command failed: %1", + "LEASE_CMDS_RESEND_DDNS6", "lease6-resend-ddns command successful: %1", + "LEASE_CMDS_RESEND_DDNS6_FAILED", "lease6-resend-ddns command failed: %1", NULL }; diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds_messages.h b/src/hooks/dhcp/lease_cmds/lease_cmds_messages.h index 7fa71b2713..ed897e0b48 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds_messages.h +++ b/src/hooks/dhcp/lease_cmds/lease_cmds_messages.h @@ -1,4 +1,4 @@ -// File created from ../../../../src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes on Fri Feb 08 2019 20:34 +// File created from ../../../../src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes on Fri Mar 13 2020 14:35 #ifndef LEASE_CMDS_MESSAGES_H #define LEASE_CMDS_MESSAGES_H @@ -17,5 +17,9 @@ extern const isc::log::MessageID LEASE_CMDS_DEL6; extern const isc::log::MessageID LEASE_CMDS_DEL6_FAILED; extern const isc::log::MessageID LEASE_CMDS_INIT_FAILED; extern const isc::log::MessageID LEASE_CMDS_INIT_OK; +extern const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4; +extern const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4_FAILED; +extern const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6; +extern const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6_FAILED; #endif // LEASE_CMDS_MESSAGES_H diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes b/src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes index 0684281701..bcedf903e7 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes +++ b/src/hooks/dhcp/lease_cmds/lease_cmds_messages.mes @@ -49,3 +49,19 @@ the log message. % LEASE_CMDS_INIT_OK loading Lease Commands hooks library successful This info message indicates that the Lease Commands hooks library has been loaded successfully. Enjoy! + +% LEASE_CMDS_RESEND_DDNS4 lease6-resend-ddns command successful: %1 +A request to update DNS for the requested IPv4 lease address has been +successfully queued for transmission to kea-dhcp-ddns. + +% LEASE_CMDS_RESEND_DDNS4_FAILED lease6-resend-ddns command failed: %1 +A request to update DNS for the requested IPv4 lease has failed. The +reason for the failure is logged. + +% LEASE_CMDS_RESEND_DDNS6 lease6-resend-ddns command successful: %1 +A request to update DNS for the requested IPv6 lease address has been +successfully queued for transmission to kea-dhcp-ddns. + +% LEASE_CMDS_RESEND_DDNS6_FAILED lease6-resend-ddns command failed: %1 +A request to update DNS for the requested IPv6 lease has failed. The +reason for the failure is logged.