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