summaryrefslogtreecommitdiffstats
path: root/src/bin/dhcp4
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2024-03-30 15:38:12 +0100
committerRazvan Becheriu <razvan@isc.org>2024-04-26 17:25:06 +0200
commit6213bed1355bac9c97511f0ce2542e2b87a5112e (patch)
treeca864c9ffe785694cd4b7208ee5f78a2d86fb574 /src/bin/dhcp4
parent[#2976] Disabled stashed RAI in updateLease4ExtendedInfo (diff)
downloadkea-6213bed1355bac9c97511f0ce2542e2b87a5112e.tar.xz
kea-6213bed1355bac9c97511f0ce2542e2b87a5112e.zip
[#2976] Added recoverStashedAgentOption
Diffstat (limited to 'src/bin/dhcp4')
-rw-r--r--src/bin/dhcp4/dhcp4_messages.cc2
-rw-r--r--src/bin/dhcp4/dhcp4_messages.h1
-rw-r--r--src/bin/dhcp4/dhcp4_messages.mes6
-rw-r--r--src/bin/dhcp4/dhcp4_srv.cc105
-rw-r--r--src/bin/dhcp4/dhcp4_srv.h37
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).