Kea 3.1.1
lease4_callouts.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
9#include <cc/data.h>
10#include <dhcp/pkt4.h>
11#include <dhcpsrv/cfgmgr.h>
13#include <dhcpsrv/lease.h>
14#include <eval/evaluate.h>
15#include <hooks/hooks.h>
16#include <util/str.h>
17#include <legal_log_log.h>
20
21#include <sstream>
22
23using namespace isc;
24using namespace isc::data;
25using namespace isc::dhcp;
26using namespace isc::util;
27using namespace hooks;
28using namespace legal_log;
29using namespace std;
30
38bool getCustomEntry(CalloutHandle& handle, const Pkt4Ptr& query, const Pkt4Ptr& response,
39 const Lease4Ptr& /*lease*/, std::string& value) {
40 bool using_custom_format = false;
41
42 auto expression = LegalLogMgrFactory::instance(handle.getCurrentLibrary())->getRequestFormatExpression();
43 if (expression && query) {
44 value = evaluateString(*expression, *query);
45 using_custom_format = true;
46 }
47
48 expression = LegalLogMgrFactory::instance(handle.getCurrentLibrary())->getResponseFormatExpression();
49 if (expression && response) {
50 value += evaluateString(*expression, *response);
51 using_custom_format = true;
52 }
53
54 return (using_custom_format);
55}
56
93/// @param lease DHCPv4 lease for which the entry should be created
94/// @param action Kind of event to log.
95std::string genLease4Entry(CalloutHandle& handle,
96 const Pkt4Ptr& query,
97 const Pkt4Ptr& response,
98 const Lease4Ptr& lease,
99 const Action& action) {
100 std::string value;
101 if (getCustomEntry(handle, query, response, lease, value)) {
102 return (value);
103 }
104
105 std::stringstream stream;
106
107 // <address>
108 stream << "Address: " << lease->addr_ << " has been " << actionToVerb(action);
109
110 if (action != Action::RELEASE) {
111 // <duration>
112 stream << " for " << LegalLogMgr::genDurationString(lease->valid_lft_) << " to";
113 } else {
114 stream << " from";
115 }
116
117 // <device-id>
118 stream << " a device with hardware address: " << lease->hwaddr_->toText();
119
120 // <client-info>
121 if (lease->client_id_) {
122 stream << ", client-id: " << lease->client_id_->toText();
123
124 // It is not uncommon to provide a printable client ID
125 auto bin = lease->client_id_->getClientId();
126
127 if (str::isPrintable(bin)) {
128 stream << " (" << LegalLogMgr::vectorDump(bin) << ")";
129 }
130 }
131
132 // <relay-info>
133 const isc::asiolink::IOAddress& giaddr = query->getGiaddr();
134 if (!giaddr.isV4Zero()) {
135 stream << " connected via relay at address: " << giaddr.toText();
136
137 // Look for relay agent information option (option 82)
138 OptionPtr rai = query->getOption(DHO_DHCP_AGENT_OPTIONS);
139 if (rai) {
140 // Look for circuit-id (sub-option 1)
141 std::stringstream idstream;
142 OptionPtr opt = rai->getOption(RAI_OPTION_AGENT_CIRCUIT_ID);
143 if (opt) {
144 const OptionBuffer& id = opt->getData();
145 if (!id.empty()) {
146 idstream << "circuit-id: " << LegalLogMgr::vectorHexDump(id);
147
148 if (str::isPrintable(id)) {
149 idstream << " (" << LegalLogMgr::vectorDump(id) << ")";
150 }
151 }
152 }
153
154 // Look for remote-id (sub-option 2)
155 opt = rai->getOption(RAI_OPTION_REMOTE_ID);
156 if (opt) {
157 const OptionBuffer& id = opt->getData();
158 if (!id.empty()) {
159 if (!idstream.str().empty()) {
160 idstream << " and ";
161 }
162
163 idstream << "remote-id: " << LegalLogMgr::vectorHexDump(id);
164
165 if (str::isPrintable(id)) {
166 idstream << " (" << LegalLogMgr::vectorDump(id) << ")";
167 }
168 }
169 }
170
171 // Look for subscriber-id (sub-option 6)
172 opt = rai->getOption(RAI_OPTION_SUBSCRIBER_ID);
173 if (opt) {
174 const OptionBuffer& id = opt->getData();
175 if (!id.empty()) {
176 if (!idstream.str().empty()) {
177 idstream << " and ";
178 }
179
180 idstream << "subscriber-id: " << LegalLogMgr::vectorHexDump(id);
181
182 if (str::isPrintable(id)) {
183 idstream << " (" << LegalLogMgr::vectorDump(id) << ")";
184 }
185 }
186 }
187
188 if (!idstream.str().empty()) {
189 stream << ", identified by " << idstream.str();
190 }
191 }
192 }
193
194 ConstElementPtr ctx = lease->getContext();
195 if (ctx) {
196 stream << ", context: " << ctx->str();
197 }
198
199 return (stream.str());
200}
201
217///
218/// @return returns 0 upon success, non-zero otherwise
219int legalLog4Handler(CalloutHandle& handle, const Action& action) {
223 return (1);
224 }
225
226 // Fetch the client's packet and the lease callout arguments.
227 Pkt4Ptr query;
228 handle.getArgument("query4", query);
229
230 Pkt4Ptr response;
231 handle.getArgument("response4", response);
232
233 Lease4Ptr lease;
234 handle.getContext("lease4", lease);
235
236 if (!lease) {
237 return (0);
238 }
239
240 ConstCfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
241 try {
242 ConstSubnet4Ptr subnet = cfg->getBySubnetId(lease->subnet_id_);
243
244 if (!isLoggingDisabled(subnet)) {
245 LegalLogMgrFactory::instance(handle.getCurrentLibrary())->writeln(genLease4Entry(handle, query, response,
246 lease, action),
247 lease->addr_.toText());
248 }
249
250 } catch (const std::exception& ex) {
252 .arg(ex.what());
253 return (1);
254 }
255
256 return (0);
257}
258
259// Functions accessed by the hooks framework use C linkage to avoid the name
260// mangling that accompanies use of the C++ compiler as well as to avoid
261// issues related to namespaces.
262extern "C" {
263
269///
270/// @return 0 upon success, non-zero otherwise.
271int pkt4_receive(CalloutHandle& handle) {
272 handle.setContext("lease4", Lease4Ptr());
273 handle.setContext("leases4", Lease4CollectionPtr());
274 handle.setContext("deleted_leases4", Lease4CollectionPtr());
275 return (0);
276}
277
284///
285/// @return 0 upon success, non-zero otherwise.
286int leases4_committed(CalloutHandle& handle) {
288 if (status == CalloutHandle::NEXT_STEP_DROP ||
290 return (0);
291 }
292
293 Lease4CollectionPtr leases;
294 handle.getArgument("leases4", leases);
295 handle.setContext("leases4", leases);
296
297 Lease4CollectionPtr deleted_leases;
298 handle.getArgument("deleted_leases4", deleted_leases);
299 handle.setContext("deleted_leases4", deleted_leases);
300 return (0);
301}
302
309///
310/// @return 0 upon success, non-zero otherwise.
311int pkt4_send(CalloutHandle& handle) {
313 if (status == CalloutHandle::NEXT_STEP_DROP ||
315 return (0);
316 }
317
318 Lease4CollectionPtr leases;
319 handle.getContext("leases4", leases);
320
321 int current = 0;
322 int result = current;
323
324 if (leases) {
325 for (auto const& lease : *leases) {
326 handle.setContext("lease4", lease);
327 current = legalLog4Handler(handle, Action::ASSIGN);
328 if (current) {
329 result = current;
330 }
331 }
332 }
333
334 handle.getContext("deleted_leases4", leases);
335
336 if (leases) {
337 for (auto const& lease : *leases) {
338 handle.setContext("lease4", lease);
339 current = legalLog4Handler(handle, Action::RELEASE);
340 if (current) {
341 result = current;
342 }
343 }
344 }
345
346 return (result);
347}
348
355///
356/// @return 0 upon success, non-zero otherwise.
357int lease4_release(CalloutHandle& handle) {
359 if (status == CalloutHandle::NEXT_STEP_DROP ||
361 return (0);
362 }
363
364 Lease4Ptr lease;
365 handle.getArgument("lease4", lease);
366 handle.setContext("lease4", lease);
367
368 Pkt4Ptr response;
369 handle.setArgument("response4", response);
370
371 return (legalLog4Handler(handle, Action::RELEASE));
372}
373
380///
381/// @return 0 upon success, non-zero otherwise.
382int lease4_decline(CalloutHandle& handle) {
384 if (status == CalloutHandle::NEXT_STEP_DROP ||
386 return (0);
387 }
388
389 Lease4Ptr lease;
390 handle.getArgument("lease4", lease);
391 handle.setContext("lease4", lease);
392
393 Pkt4Ptr response;
394 handle.setArgument("response4", response);
395
396 return (legalLog4Handler(handle, Action::RELEASE));
397}
398
399} // end extern "C"
CalloutNextStep
Specifies allowed next steps.
@ NEXT_STEP_DROP
drop the packet
@ NEXT_STEP_SKIP
skip the next processing step
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
static LegalLogMgrPtr & instance(ManagerID id=0)
Returns the forensic backend manager with specified ID.
static std::string vectorHexDump(const std::vector< uint8_t > &bytes, const std::string &delimiter=":")
Creates a string of hex digit pairs from a vector of bytes.
static std::string genDurationString(const uint32_t secs)
Translates seconds into a text string of days, hours, minutes and seconds.
static std::string vectorDump(const std::vector< uint8_t > &bytes)
Creates a string from a vector of printable bytes.
Per-packet callout handle.
void getContext(const std::string &name, T &value) const
Get context.
void setContext(const std::string &name, T value)
Set context.
CalloutNextStep getStatus() const
Returns the next processing step.
void getArgument(const std::string &name, T &value) const
Get argument.
int getCurrentLibrary() const
Get current library index.
void setArgument(const std::string &name, T value)
Set argument.
int lease4_release(CalloutHandle &handle)
This callout is called at the "lease4_release" hook.
int lease4_decline(CalloutHandle &handle)
This callout is called at the "lease4_decline" hook.
int leases4_committed(CalloutHandle &handle)
This callout is called at the "leases4_committed" hook.
std::string genLease4Entry(CalloutHandle &handle, const Pkt4Ptr &query, const Pkt4Ptr &response, const Lease4Ptr &lease, const Action &action)
Creates legal store entry for a DHCPv4 Lease.
int pkt4_send(CalloutHandle &handle)
This callout is called at the "pkt4_send" hook.
int pkt4_receive(CalloutHandle &handle)
This callout is called at the "pkt4_receive" hook.
int legalLog4Handler(CalloutHandle &handle, const Action &action)
Produces an DHCPv4 legal log entry from a callout handle.
bool getCustomEntry(CalloutHandle &handle, const Pkt4Ptr &query, const Pkt4Ptr &response, const Lease4Ptr &, std::string &value)
Create custom log entry for the current lease.
const isc::log::MessageID LEGAL_LOG_LEASE4_NO_LEGAL_STORE
const isc::log::MessageID LEGAL_LOG_LEASE4_WRITE_ERROR
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Lease4Collection > Lease4CollectionPtr
A shared pointer to the collection of IPv4 leases.
Definition lease.h:523
@ DHO_DHCP_AGENT_OPTIONS
Definition dhcp4.h:151
boost::shared_ptr< const Subnet4 > ConstSubnet4Ptr
A const pointer to a Subnet4 object.
Definition subnet.h:458
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
std::string evaluateString(const Expression &expr, Pkt &pkt)
Evaluate a RPN expression for a v4 or v6 packet and return a string value.
Definition evaluate.cc:45
const string actionToVerb(Action action)
Translates an Action into its corresponding verb.
boost::shared_ptr< const CfgSubnets4 > ConstCfgSubnets4Ptr
Const pointer.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
@ RAI_OPTION_SUBSCRIBER_ID
Definition dhcp4.h:270
@ RAI_OPTION_AGENT_CIRCUIT_ID
Definition dhcp4.h:265
@ RAI_OPTION_REMOTE_ID
Definition dhcp4.h:266
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition lease.h:315
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
Action
Describe what kind of event is being logged.
isc::log::Logger legal_log_logger("legal-log-hooks")
Legal Log Logger.
bool isLoggingDisabled(const SubnetPtrType &subnet)
Checks if legal logging is disabled for a subnet.
bool isPrintable(const string &content)
Check if a string is printable.
Definition str.cc:310
Defines the logger used by the top-level component of kea-lfc.