diff options
author | Francis Dupont <fdupont@isc.org> | 2024-03-30 15:38:12 +0100 |
---|---|---|
committer | Razvan Becheriu <razvan@isc.org> | 2024-04-26 17:25:06 +0200 |
commit | 6213bed1355bac9c97511f0ce2542e2b87a5112e (patch) | |
tree | ca864c9ffe785694cd4b7208ee5f78a2d86fb574 | |
parent | [#2976] Disabled stashed RAI in updateLease4ExtendedInfo (diff) | |
download | kea-6213bed1355bac9c97511f0ce2542e2b87a5112e.tar.xz kea-6213bed1355bac9c97511f0ce2542e2b87a5112e.zip |
[#2976] Added recoverStashedAgentOption
-rw-r--r-- | src/bin/dhcp4/dhcp4_messages.cc | 2 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_messages.h | 1 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_messages.mes | 6 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_srv.cc | 105 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_srv.h | 37 |
5 files changed, 141 insertions, 10 deletions
diff --git a/src/bin/dhcp4/dhcp4_messages.cc b/src/bin/dhcp4/dhcp4_messages.cc index 3ee62864d8..110dfe06ec 100644 --- a/src/bin/dhcp4/dhcp4_messages.cc +++ b/src/bin/dhcp4/dhcp4_messages.cc @@ -153,6 +153,7 @@ extern const isc::log::MessageID DHCP4_POST_ALLOCATION_NAME_UPDATE_FAIL = "DHCP4 extern const isc::log::MessageID DHCP4_QUERY_DATA = "DHCP4_QUERY_DATA"; extern const isc::log::MessageID DHCP4_QUERY_LABEL = "DHCP4_QUERY_LABEL"; extern const isc::log::MessageID DHCP4_RECLAIM_EXPIRED_LEASES_FAIL = "DHCP4_RECLAIM_EXPIRED_LEASES_FAIL"; +extern const isc::log::MessageID DHCP4_RECOVERED_STASHED_RELAY_AGENT_INFO = "DHCP4_RECOVERED_STASHED_RELAY_AGENT_INFO"; extern const isc::log::MessageID DHCP4_RELEASE = "DHCP4_RELEASE"; extern const isc::log::MessageID DHCP4_RELEASE_DELETED = "DHCP4_RELEASE_DELETED"; extern const isc::log::MessageID DHCP4_RELEASE_EXCEPTION = "DHCP4_RELEASE_EXCEPTION"; @@ -341,6 +342,7 @@ const char* values[] = { "DHCP4_QUERY_DATA", "%1, packet details: %2", "DHCP4_QUERY_LABEL", "received query: %1", "DHCP4_RECLAIM_EXPIRED_LEASES_FAIL", "failed to reclaim expired leases: %1", + "DHCP4_RECOVERED_STASHED_RELAY_AGENT_INFO", "recovered for query %1 relay agent option from lease %2: %3", "DHCP4_RELEASE", "%1: address %2 was released properly.", "DHCP4_RELEASE_DELETED", "%1: address %2 was deleted on release.", "DHCP4_RELEASE_EXCEPTION", "%1: while trying to release address %2 an exception occurred: %3", diff --git a/src/bin/dhcp4/dhcp4_messages.h b/src/bin/dhcp4/dhcp4_messages.h index 7f9ef8acff..9faa16296a 100644 --- a/src/bin/dhcp4/dhcp4_messages.h +++ b/src/bin/dhcp4/dhcp4_messages.h @@ -154,6 +154,7 @@ extern const isc::log::MessageID DHCP4_POST_ALLOCATION_NAME_UPDATE_FAIL; extern const isc::log::MessageID DHCP4_QUERY_DATA; extern const isc::log::MessageID DHCP4_QUERY_LABEL; extern const isc::log::MessageID DHCP4_RECLAIM_EXPIRED_LEASES_FAIL; +extern const isc::log::MessageID DHCP4_RECOVERED_STASHED_RELAY_AGENT_INFO; extern const isc::log::MessageID DHCP4_RELEASE; extern const isc::log::MessageID DHCP4_RELEASE_DELETED; extern const isc::log::MessageID DHCP4_RELEASE_EXCEPTION; diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index ea0d12922b..9638e47247 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -895,6 +895,12 @@ the client and the transaction identification information. This error message indicates that the reclaim expired leases operation failed and provides the cause of failure. +% DHCP4_RECOVERED_STASHED_RELAY_AGENT_INFO recovered for query %1 relay agent option from lease %2: %3 +This debug message indicates that agent options were stashed in the lease for +the client address of the request and were recovered. The first argument +includes the request information, the second the client address and the last +argument the content of the dhcp-agent-options option. + % DHCP4_RELEASE %1: address %2 was released properly. This informational message indicates that an address was released properly. It is a normal operation during client shutdown. The first argument includes diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 6f7d74b1d3..4c83daec67 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -50,6 +50,7 @@ #include <hooks/hooks_log.h> #include <hooks/hooks_manager.h> #include <stats/stats_mgr.h> +#include <util/encode/encode.h> #include <util/str.h> #include <log/logger.h> #include <cryptolink/cryptolink.h> @@ -399,7 +400,7 @@ Dhcpv4Exchange::copyDefaultOptions() { // Do not copy recovered stashed RAI. ConstElementPtr sao = CfgMgr::instance().getCurrentCfg()-> getConfiguredGlobal(CfgGlobals::STASH_AGENT_OPTIONS); - if (sao && (sao->getType() == data::Element::boolean) && + if (sao && (sao->getType() == Element::boolean) && sao->boolValue() && query_->inClass("STASH_AGENT_OPTIONS")) { return; } @@ -1369,6 +1370,13 @@ Dhcpv4Srv::processPacket(Pkt4Ptr query, bool allow_answer_park) { // Update statistics accordingly for received packet. processStatsReceived(query); + // Recover stashed RAI from client address lease. + try { + recoverStashedAgentOption(query); + } catch (const std::exception&) { + // Ignore exceptions. + } + // Assign this packet to one or more classes if needed. We need to do // this before calling accept(), because getSubnet4() may need client // class information. @@ -4320,6 +4328,101 @@ Dhcpv4Srv::processInform(Pkt4Ptr& inform, AllocEngine::ClientContext4Ptr& contex return (ex.getResponse()); } +void +Dhcpv4Srv::recoverStashedAgentOption(const Pkt4Ptr& query) { + if (query->getCiaddr().isV4Zero() || !query->getGiaddr().isV4Zero()) { + return; + } + ConstElementPtr sao = CfgMgr::instance().getCurrentCfg()-> + getConfiguredGlobal(CfgGlobals::STASH_AGENT_OPTIONS); + if (!sao || (sao->getType() != Element::boolean) || !sao->boolValue()) { + return; + } + if (query->getType() != DHCPREQUEST) { + return; + } + OptionPtr rai_opt = query->getOption(DHO_DHCP_AGENT_OPTIONS); + if (rai_opt && (rai_opt->len() > Option::OPTION4_HDR_LEN)) { + return; + } + // Should not happen but makes sense to check and gives a trivial way + // to disable the feature from previous callout points. + if (query->inClass("STASH_AGENT_OPTIONS")) { + return; + } + Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(query->getCiaddr()); + if (!lease || lease->expired()) { + return; + } + ConstElementPtr user_context = lease->getContext(); + if (!user_context || (user_context->getType() != Element::map)) { + return; + } + ConstElementPtr isc = user_context->get("ISC"); + if (!isc || (isc->getType() != Element::map)) { + return; + } + ConstElementPtr extended_info = isc->get("relay-agent-info"); + if (!extended_info || (extended_info->getType() != Element::map)) { + return; + } + ConstElementPtr relay_agent_info = extended_info->get("relay-agent-info"); + if (!relay_agent_info) { + return; + } + // Compatibility with the old layout. + if (relay_agent_info->getType() == Element::map) { + relay_agent_info = relay_agent_info->get("sub-options"); + if (!relay_agent_info) { + return; + } + } + if (relay_agent_info->getType() != Element::string) { + return; + } + // Check ownership before going further. + ClientIdPtr client_id; + OptionPtr opt_clientid = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER); + if (opt_clientid) { + client_id.reset(new ClientId(opt_clientid->getData())); + } + if (!lease->belongsToClient(query->getHWAddr(), client_id)) { + return; + } + // Extract the RAI. + string rai_hex = relay_agent_info->stringValue(); + vector<uint8_t> rai_data; + str::decodeFormattedHexString(rai_hex, rai_data); + if (rai_data.size() <= Option::OPTION4_HDR_LEN) { + // RAI is empty. + return; + } + static OptionDefinitionPtr rai_def; + if (!rai_def) { + rai_def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE, + DHO_DHCP_AGENT_OPTIONS); + } + if (!rai_def) { + // Should not happen. + return; + } + OptionCustomPtr rai(new OptionCustom(*rai_def, Option::V4, rai_data)); + if (!rai) { + return; + } + // Remove an existing empty RAI. + if (rai_opt) { + query->delOption(DHO_DHCP_AGENT_OPTIONS); + } + query->addOption(rai); + query->addClass("STASH_AGENT_OPTIONS"); + LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA, + DHCP4_RECOVERED_STASHED_RELAY_AGENT_INFO) + .arg(query->getLabel()) + .arg(query->getCiaddr()) + .arg(rai->toText()); +} + bool Dhcpv4Srv::accept(const Pkt4Ptr& query) { // Check that the message type is accepted by the server. We rely on the diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h index a8e1d3c013..3bb4bb9ddd 100644 --- a/src/bin/dhcp4/dhcp4_srv.h +++ b/src/bin/dhcp4/dhcp4_srv.h @@ -99,12 +99,12 @@ public: /// @brief Returns the pointer to the server's response. /// - /// The returned pointer is NULL if the query type is DHCPRELEASE or DHCPDECLINE. + /// The returned pointer is null if the query type is DHCPRELEASE or DHCPDECLINE. Pkt4Ptr getResponse() const { return (resp_); } - /// @brief Removes the response message by resetting the pointer to NULL. + /// @brief Removes the response message by resetting the pointer to null. void deleteResponse() { resp_.reset(); } @@ -202,7 +202,7 @@ private: /// @warning This message is called internally by @c initResponse and /// thus it doesn't check if the resp_ value has been initialized. The /// calling method is responsible for making sure that @c resp_ is - /// not NULL. + /// not null. void copyDefaultFields(); /// @brief Copies default options from client's to server's message @@ -213,7 +213,7 @@ private: /// @warning This message is called internally by @c initResponse and /// thus it doesn't check if the resp_ value has been initialized. The /// calling method is responsible for making sure that @c resp_ is - /// not NULL. + /// not null. void copyDefaultOptions(); /// @brief Pointer to the allocation engine used by the server. @@ -639,7 +639,7 @@ protected: /// @param discover DISCOVER message received from client /// @param context pointer to the client context /// - /// @return OFFER message or NULL + /// @return OFFER message or null Pkt4Ptr processDiscover(Pkt4Ptr& discover, AllocEngine::ClientContext4Ptr& context); /// @brief Processes incoming REQUEST and returns REPLY response. @@ -649,7 +649,7 @@ protected: /// is valid, not expired, not reserved, not used by other client and /// that requesting client is allowed to use it. /// - /// Returns ACK message, NAK message, or NULL + /// Returns ACK message, NAK message, or null /// /// @param request a message received from client /// @param context pointer to the client context where allocated and @@ -976,7 +976,7 @@ protected: /// @param lease A pointer to the new lease which has been acquired. /// @param old_lease A pointer to the instance of the old lease which has /// @param ddns_params DDNS configuration parameters - /// been replaced by the new lease passed in the first argument. The NULL + /// been replaced by the new lease passed in the first argument. The null /// value indicates that the new lease has been allocated, rather than /// lease being renewed. void createNameChangeRequests(const Lease4Ptr& lease, @@ -1091,7 +1091,7 @@ protected: /// @param drop if it is true the packet will be dropped /// @param sanity_only if it is true the callout won't be called /// @param allow_answer_park Indicates if parking a packet is allowed - /// @return selected subnet (or NULL if no suitable subnet was found) + /// @return selected subnet (or null if no suitable subnet was found) isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& query, bool& drop, bool sanity_only = false, @@ -1108,7 +1108,7 @@ protected: /// @param drop if it is true the packet will be dropped /// @param sanity_only if it is true the callout won't be called /// @param allow_answer_park Indicates if parking a packet is allowed - /// @return selected subnet (or NULL if no suitable subnet was found) + /// @return selected subnet (or null if no suitable subnet was found) isc::dhcp::Subnet4Ptr selectSubnet4o6(const Pkt4Ptr& query, bool& drop, bool sanity_only = false, @@ -1138,6 +1138,25 @@ protected: /// @param pkt packet to be classified void classifyPacket(const Pkt4Ptr& pkt); + /// @brief Recover stashed agent options from client address lease. + /// + /// This method checks: + /// - client address is not 0.0.0.0. + /// - relay address is 0.0.0.0. + /// - stash-agent-options is true (vs false, the default). + /// - the query is a DHCPREQUEST. + /// - there is no RAI or an empty RAI in the query. + /// - the query is not member of the STASH_AGENT_OPTIONS client class. + /// - there is a lease for the client address. + /// - the lease is not expired. + /// - the lease has a RAI in its extended info in its user context. + /// - the lease belongs to the client. + /// - a not empty RAI can be recovered from the lease. + /// when all checks pass: + /// - add the recovered RAI to the query. + /// - put the query in the STASH_AGENT_OPTIONS client class. + void recoverStashedAgentOption(const Pkt4Ptr& query); + protected: /// @brief Assigns incoming packet to zero or more classes (required pass). |