Kea 3.3.1
lease4_callouts.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2026 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 isc::util::str;
28using namespace hooks;
29using namespace legal_log;
30using namespace std;
31
39bool getCustomEntry(CalloutHandle& handle, const Pkt4Ptr& query, const Pkt4Ptr& response,
40 const Lease4Ptr& lease, std::string& value) {
41 bool using_custom_format = false;
42 auto library = LegalLogMgrFactory::instance(handle.getCurrentLibrary());
43 try {
44 auto expression = library->getRequestFormatExpression();
45 if (expression && query) {
46 value = evaluateString(*expression, *query);
47 using_custom_format = true;
48 }
49
50 expression = library->getResponseFormatExpression();
51 if (expression && response) {
52 value += evaluateString(*expression, *response);
53 using_custom_format = true;
54 }
55 } catch (const std::exception& ex) {
57 .arg(lease ? lease->addr_.toText() : "<none>")
58 .arg(lease && lease->hwaddr_ ? lease->hwaddr_->toText() : "<none>")
59 .arg(ex.what());
60 value.clear();
61 return (false);
62 }
63
64 return (using_custom_format);
65}
66
103/// @param lease DHCPv4 lease for which the entry should be created
104/// @param action Kind of event to log.
105std::string genLease4Entry(CalloutHandle& handle,
106 const Pkt4Ptr& query,
107 const Pkt4Ptr& response,
108 const Lease4Ptr& lease,
109 const Action& action) {
110 std::string value;
111 if (getCustomEntry(handle, query, response, lease, value)) {
112 return (value);
113 }
114
115 std::stringstream stream;
116
117 // <address>
118 stream << "Address: " << lease->addr_ << " has been " << actionToVerb(action);
119
120 if (action != Action::RELEASE) {
121 // <duration>
122 stream << " for " << LegalLogMgr::genDurationString(lease->valid_lft_) << " to";
123 } else {
124 stream << " from";
125 }
126
127 // <device-id>
128 stream << " a device with hardware address: " << lease->hwaddr_->toText();
129
130 // <client-info>
131 if (lease->client_id_) {
132 stream << ", client-id: " << lease->client_id_->toText();
133
134 // It is not uncommon to provide a printable client ID
135 auto bin = lease->client_id_->getClientId();
136
137 if (isPrintable(bin)) {
138 stream << " (" << LegalLogMgr::vectorDump(bin) << ")";
139 }
140 }
141
142 // <relay-info>
143 const isc::asiolink::IOAddress& giaddr = query->getGiaddr();
144 if (!giaddr.isV4Zero()) {
145 stream << " connected via relay at address: " << giaddr.toText();
146
147 // Look for relay agent information option (option 82)
148 OptionPtr rai = query->getOption(DHO_DHCP_AGENT_OPTIONS);
149 if (rai) {
150 // Look for circuit-id (sub-option 1)
151 std::stringstream idstream;
152 OptionPtr opt = rai->getOption(RAI_OPTION_AGENT_CIRCUIT_ID);
153 if (opt) {
154 const OptionBuffer& id = opt->getData();
155 if (!id.empty()) {
156 idstream << "circuit-id: " << dumpAsHex(id);
157
158 if (isPrintable(id)) {
159 idstream << " (" << LegalLogMgr::vectorDump(id) << ")";
160 }
161 }
162 }
163
164 // Look for remote-id (sub-option 2)
165 opt = rai->getOption(RAI_OPTION_REMOTE_ID);
166 if (opt) {
167 const OptionBuffer& id = opt->getData();
168 if (!id.empty()) {
169 if (!idstream.str().empty()) {
170 idstream << " and ";
171 }
172
173 idstream << "remote-id: " << dumpAsHex(id);
174
175 if (isPrintable(id)) {
176 idstream << " (" << LegalLogMgr::vectorDump(id) << ")";
177 }
178 }
179 }
180
181 // Look for subscriber-id (sub-option 6)
182 opt = rai->getOption(RAI_OPTION_SUBSCRIBER_ID);
183 if (opt) {
184 const OptionBuffer& id = opt->getData();
185 if (!id.empty()) {
186 if (!idstream.str().empty()) {
187 idstream << " and ";
188 }
189
190 idstream << "subscriber-id: " << dumpAsHex(id);
191
192 if (isPrintable(id)) {
193 idstream << " (" << LegalLogMgr::vectorDump(id) << ")";
194 }
195 }
196 }
197
198 if (!idstream.str().empty()) {
199 stream << ", identified by " << idstream.str();
200 }
201 }
202 }
203
204 ConstElementPtr ctx = lease->getContext();
205 if (ctx) {
206 stream << ", context: " << ctx->str();
207 }
208
209 return (stream.str());
210}
211
227///
228/// @return returns 0 upon success, non-zero otherwise
229int legalLog4Handler(CalloutHandle& handle, const Action& action) {
233 return (1);
234 }
235
236 // Fetch the client's packet and the lease callout arguments.
237 Pkt4Ptr query;
238 handle.getArgument("query4", query);
239
240 Pkt4Ptr response;
241 handle.getArgument("response4", response);
242
243 Lease4Ptr lease;
244 handle.getContext("lease4", lease);
245
246 if (!lease) {
247 return (0);
248 }
249
250 ConstCfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
251 try {
252 ConstSubnet4Ptr subnet = cfg->getBySubnetId(lease->subnet_id_);
253
254 if (!isLoggingDisabled(subnet)) {
255 LegalLogMgrFactory::instance(handle.getCurrentLibrary())->writeln(genLease4Entry(handle, query, response,
256 lease, action),
257 lease->addr_.toText());
258 }
259
260 } catch (const std::exception& ex) {
262 .arg(ex.what());
263 return (1);
264 }
265
266 return (0);
267}
268
269// Functions accessed by the hooks framework use C linkage to avoid the name
270// mangling that accompanies use of the C++ compiler as well as to avoid
271// issues related to namespaces.
272extern "C" {
273
279///
280/// @return 0 upon success, non-zero otherwise.
281int pkt4_receive(CalloutHandle& handle) {
282 handle.setContext("lease4", Lease4Ptr());
283 handle.setContext("leases4", Lease4CollectionPtr());
284 handle.setContext("deleted_leases4", Lease4CollectionPtr());
285 return (0);
286}
287
294///
295/// @return 0 upon success, non-zero otherwise.
296int leases4_committed(CalloutHandle& handle) {
298 if (status == CalloutHandle::NEXT_STEP_DROP ||
300 return (0);
301 }
302
303 Lease4CollectionPtr leases;
304 handle.getArgument("leases4", leases);
305 handle.setContext("leases4", leases);
306
307 Lease4CollectionPtr deleted_leases;
308 handle.getArgument("deleted_leases4", deleted_leases);
309 handle.setContext("deleted_leases4", deleted_leases);
310 return (0);
311}
312
319///
320/// @return 0 upon success, non-zero otherwise.
321int pkt4_send(CalloutHandle& handle) {
323 if (status == CalloutHandle::NEXT_STEP_DROP ||
325 return (0);
326 }
327
328 Lease4CollectionPtr leases;
329 handle.getContext("leases4", leases);
330
331 int current = 0;
332 int result = current;
333
334 if (leases) {
335 for (auto const& lease : *leases) {
336 handle.setContext("lease4", lease);
337 current = legalLog4Handler(handle, Action::ASSIGN);
338 if (current) {
339 result = current;
340 }
341 }
342 }
343
344 handle.getContext("deleted_leases4", leases);
345
346 if (leases) {
347 for (auto const& lease : *leases) {
348 handle.setContext("lease4", lease);
349 current = legalLog4Handler(handle, Action::RELEASE);
350 if (current) {
351 result = current;
352 }
353 }
354 }
355
356 return (result);
357}
358
365///
366/// @return 0 upon success, non-zero otherwise.
367int lease4_release(CalloutHandle& handle) {
369 if (status == CalloutHandle::NEXT_STEP_DROP ||
371 return (0);
372 }
373
374 Lease4Ptr lease;
375 handle.getArgument("lease4", lease);
376 handle.setContext("lease4", lease);
377
378 Pkt4Ptr response;
379 handle.setArgument("response4", response);
380
381 return (legalLog4Handler(handle, Action::RELEASE));
382}
383
390///
391/// @return 0 upon success, non-zero otherwise.
392int lease4_decline(CalloutHandle& handle) {
394 if (status == CalloutHandle::NEXT_STEP_DROP ||
396 return (0);
397 }
398
399 Lease4Ptr lease;
400 handle.getArgument("lease4", lease);
401 handle.setContext("lease4", lease);
402
403 Pkt4Ptr response;
404 handle.setArgument("response4", response);
405
406 return (legalLog4Handler(handle, Action::RELEASE));
407}
408
409} // 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 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.
bool getCustomEntry(CalloutHandle &handle, const Pkt4Ptr &query, const Pkt4Ptr &response, const Lease4Ptr &lease, std::string &value)
Create custom log entry for the current 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.
const isc::log::MessageID LEGAL_LOG_LEASE4_RENDER_ERROR
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:30
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:455
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.
string dumpAsHex(const uint8_t *data, size_t length)
Dumps a buffer of bytes as a string of hexadecimal digits.
Definition str.cc:330
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.