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";
"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",
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;
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
#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>
// 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;
}
// 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.
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
/// @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();
}
/// @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
/// @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.
/// @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.
/// 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
/// @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,
/// @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,
/// @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,
/// @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).