Kea 2.7.7
legal_log_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2020-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>
8
9#include <legal_log_mgr.h>
11
13#include <dhcpsrv/cfgmgr.h>
14#include <eval/eval_context.h>
15#include <util/reconnect_ctl.h>
16
17#include <boost/date_time/posix_time/posix_time.hpp>
18
19#include <errno.h>
20#include <iostream>
21#include <sstream>
22#include <time.h>
23
24namespace isc {
25namespace dhcp {
26
27using namespace isc::asiolink;
28using namespace isc::data;
29using namespace isc::db;
30using namespace isc::dhcp;
31using namespace isc::eval;
32using namespace isc::hooks;
33using namespace isc::util;
34using namespace std;
35
36void
38 if (!parameters || !parameters->get("type") ||
39 parameters->get("type")->stringValue() == "logfile") {
40 parseFile(parameters, map);
41 } else {
42 parseDatabase(parameters, map);
43 }
44 parseExtraParameters(parameters, map);
45}
46
47void
49 // Should never happen with the code flow at the time of writing, but
50 // let's get this check out of the way.
51 if (!parameters) {
52 isc_throw(BadValue, "no parameters specified for the hook library");
53 }
54
56
57 // Strings
58 for (char const* const& key : {
59 "type", "user", "password", "host", "name", "trust-anchor",
60 "cert-file", "key-file", "cipher-list" }) {
61 ConstElementPtr const value(parameters->get(key));
62 if (value) {
63 db_parameters.emplace(key, value->stringValue());
64 }
65 }
66
67 // uint32_t
68 for (char const* const& key : {
69 "connect-timeout", "reconnect-wait-time", "max-reconnect-tries"}) {
70 ConstElementPtr const value(parameters->get(key));
71 if (value) {
72 int64_t integer_value(value->intValue());
73 auto const max(numeric_limits<uint32_t>::max());
74 if (integer_value < 0 || max < integer_value) {
76 key << " value: " << integer_value
77 << " is out of range, expected value: 0.."
78 << max);
79 }
80 db_parameters[key] =
81 boost::lexical_cast<string>(integer_value);
82 }
83 }
84
85 string param_name = "tcp-nodelay";
86 ConstElementPtr param = parameters->get(param_name);
87 if (param) {
88 db_parameters.emplace(param_name,
89 param->boolValue() ? "true" : "false");
90 }
91
92 // Always set "on-fail" to "serve-retry-continue" if not explicitly
93 // configured.
94 string on_fail_action = ReconnectCtl::onFailActionToText(OnFailAction::SERVE_RETRY_CONTINUE);
95 param_name = "on-fail";
96 param = parameters->get(param_name);
97 if (param) {
98 on_fail_action = param->stringValue();
100 }
101 db_parameters.emplace(param_name, on_fail_action);
102
103 param_name = "retry-on-startup";
104 param = parameters->get(param_name);
105 if (param) {
106 db_parameters.emplace(param_name,
107 param->boolValue() ? "true" : "false");
108 }
109
110 int64_t port = 0;
111 param_name = "port";
112 param = parameters->get(param_name);
113 if (param) {
114 port = param->intValue();
115 if ((port < 0) || (port > numeric_limits<uint16_t>::max())) {
116 isc_throw(OutOfRange, param_name << " value: " << port
117 << " is out of range, expected value: 0.."
118 << numeric_limits<uint16_t>::max());
119 }
120 db_parameters.emplace(param_name,
121 boost::lexical_cast<string>(port));
122 }
123
124 string redacted =
126
127 string const db_type(db_parameters["type"]);
128 map = db_parameters;
129}
130
131void
133 DatabaseConnection::ParameterMap file_parameters;
134 file_parameters["type"] = "logfile";
135
136 if (!parameters) {
137 map = file_parameters;
138 return;
139 }
140
141 // Strings
142 for (char const* const& key : { "path", "base-name", "time-unit", "prerotate", "postrotate" }) {
143 ConstElementPtr const value(parameters->get(key));
144 if (value) {
145 file_parameters.emplace(key, value->stringValue());
146 }
147 }
148
149 // uint32_t
150 for (char const* const& key : { "count" }) {
151 ConstElementPtr const value(parameters->get(key));
152 if (value) {
153 int64_t integer_value(value->intValue());
154 auto const max(numeric_limits<uint32_t>::max());
155 if (integer_value < 0 || max < integer_value) {
157 key << " value: " << integer_value
158 << " is out of range, expected value: 0.."
159 << max);
160 }
161 file_parameters[key] = boost::lexical_cast<string>(integer_value);
162 }
163 }
164 map = file_parameters;
165}
166
167void
169 if (!parameters) {
170 return;
171 }
172
173 // Strings
174 for (char const* const& key : { "request-parser-format", "response-parser-format", "timestamp-format" }) {
175 ConstElementPtr const value(parameters->get(key));
176 if (value && !value->stringValue().empty()) {
177 map.emplace(key, value->stringValue());
178 }
179 }
180}
181
182struct tm
183LegalLogMgr::currentTimeInfo() const {
184 struct tm time_info;
185 struct timespec timestamp = now();
186 localtime_r(&timestamp.tv_sec, &time_info);
187 return (time_info);
188}
189
190struct timespec
191LegalLogMgr::now() const {
192 struct timespec now;
193 clock_gettime(CLOCK_REALTIME, &now);
194 return (now);
195}
196
197string
199 // Get a text representation of the current time.
200 return (getNowString(timestamp_format_));
201}
202
203string
204LegalLogMgr::getNowString(const string& format) const {
205 // Get a text representation of the current time.
206 return (getTimeString(now(), format));
207}
208
209string
210LegalLogMgr::getTimeString(const struct timespec& time, const string& format) {
211 // Get a text representation of the requested time.
212
213 // First a quick and dirty support for fractional seconds: Replace any "%Q"
214 // tokens in the format string with the microsecond count from the timespec,
215 // before handing it off to strftime().
216 string tmp_format = format;
217 for (auto it = tmp_format.begin(); it < tmp_format.end(); ++it) {
218 if (*it == '%' && ((it + 1) < tmp_format.end())) {
219 if (*(it + 1) == 'Q') {
220 // Save the current position.
221 string::size_type pos = it - tmp_format.begin();
222 // Render the microsecond count.
223 ostringstream usec;
224 usec << setw(6) << setfill('0') << (time.tv_nsec / 1000);
225 string microseconds = usec.str();
226 microseconds.insert(3, 1, '.');
227 tmp_format.replace(it, it + 2, microseconds);
228 // Reinitialize the iterator after manipulating the string.
229 it = tmp_format.begin() + pos + microseconds.length() - 1;
230 } else {
231 ++it;
232 }
233 }
234 }
235
236 char buffer[128];
237 struct tm time_info;
238 localtime_r(&time.tv_sec, &time_info);
239
240 if (!strftime(buffer, sizeof(buffer), tmp_format.c_str(), &time_info)) {
242 "strftime returned 0. Maybe the timestamp format '"
243 << tmp_format
244 << "' result is too long, maximum length allowed: "
245 << sizeof(buffer));
246 }
247 return (string(buffer));
248}
249
250string
251LegalLogMgr::genDurationString(const uint32_t secs) {
252 // Because Kea handles lease lifetimes as uint32_t and supports
253 // a value of 0xFFFFFFFF (infinite lifetime), we don't use things like
254 // boost:posix_time::time_duration as they work on longs. Therefore
255 // we'll figure it out ourselves. Besides, the math ain't that hard.
256 if (secs == 0xffffffff) {
257 return ("infinite duration");
258 }
259
260 uint32_t seconds = secs % 60;
261 uint32_t remainder = secs / 60;
262 uint32_t minutes = remainder % 60;
263 remainder /= 60;
264 uint32_t hours = remainder % 24;
265 uint32_t days = remainder / 24;
266
267 ostringstream os;
268 // Only spit out days if we have em.
269 if (days) {
270 os << days << " days ";
271 }
272
273 os << hours << " hrs "
274 << minutes << " mins "
275 << seconds << " secs";
276
277 return (os.str());
278}
279
280string
281LegalLogMgr::vectorHexDump(const vector<uint8_t>& bytes,
282 const string& delimiter) {
283 stringstream tmp;
284 tmp << hex;
285 bool delim = false;
286 for (auto const& it : bytes) {
287 if (delim) {
288 tmp << delimiter;
289 }
290 tmp << setw(2) << setfill('0') << static_cast<unsigned int>(it);
291 delim = true;
292 }
293 return (tmp.str());
294}
295
296string
297LegalLogMgr::vectorDump(const vector<uint8_t>& bytes) {
298 if (bytes.empty()) {
299 return (string());
300 }
301 return (string(bytes.cbegin(), bytes.cend()));
302}
303
304void
305LegalLogMgr::setRequestFormatExpression(const string& extended_format) {
306 Option::Universe universe;
307 if (CfgMgr::instance().getFamily() == AF_INET) {
308 universe = Option::V4;
309 } else {
310 universe = Option::V6;
311 }
312 EvalContext eval_ctx(universe);
313 eval_ctx.parseString(extended_format, EvalContext::PARSER_STRING);
314 request_expression_.reset(new Expression(eval_ctx.expression_));
315}
316
317void
318LegalLogMgr::setResponseFormatExpression(const string& extended_format) {
319 Option::Universe universe;
320 if (CfgMgr::instance().getFamily() == AF_INET) {
321 universe = Option::V4;
322 } else {
323 universe = Option::V6;
324 }
325 EvalContext eval_ctx(universe);
326 eval_ctx.parseString(extended_format, EvalContext::PARSER_STRING);
327 response_expression_.reset(new Expression(eval_ctx.expression_));
328}
329
330void
331LegalLogMgr::setTimestampFormat(const string& timestamp_format) {
332 timestamp_format_ = timestamp_format;
333}
334
335const string
337 switch (action) {
338 case Action::ASSIGN:
339 return ("assigned");
340 case Action::RELEASE:
341 return ("released");
342 default:
343 return ("unknown-action");
344 }
345}
346
347} // namespace dhcp
348} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
static std::string redactedAccessString(const ParameterMap &parameters)
Redact database access string.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:28
Thrown if a LegalLogMgr encounters an error.
LegalLogMgr abstract class.
void setRequestFormatExpression(const std::string &extended_format)
Sets request extended format expression for custom logging.
static void parseFile(const isc::data::ConstElementPtr &parameters, isc::db::DatabaseConnection::ParameterMap &map)
Parse file specification.
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 void parseDatabase(const isc::data::ConstElementPtr &parameters, isc::db::DatabaseConnection::ParameterMap &map)
Parse database specification.
void setResponseFormatExpression(const std::string &extended_format)
Sets response extended format expression for custom logging.
static std::string genDurationString(const uint32_t secs)
Translates seconds into a text string of days, hours, minutes and seconds.
virtual struct timespec now() const
Returns the current system time.
static std::string getTimeString(const struct timespec &time, const std::string &format)
Returns a time as string.
static std::string vectorDump(const std::vector< uint8_t > &bytes)
Creates a string from a vector of printable bytes.
static void parseConfig(const isc::data::ConstElementPtr &parameters, isc::db::DatabaseConnection::ParameterMap &map)
Parse database specification.
void setTimestampFormat(const std::string &timestamp_format)
Sets the timestamp format used for logging.
static void parseExtraParameters(const isc::data::ConstElementPtr &parameters, isc::db::DatabaseConnection::ParameterMap &map)
Parse extra parameters which are not related to backend connection.
virtual std::string getNowString() const
Returns the current date and time as string.
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:90
Evaluation context, an interface to the expression evaluation.
bool parseString(const std::string &str, ParserType type=PARSER_BOOL)
Run the parser on the string specified.
@ PARSER_STRING
expression is expected to evaluate to string
isc::dhcp::Expression expression_
Parsed expression (output tokens are stored here)
static std::string onFailActionToText(OnFailAction action)
Convert action to string.
static OnFailAction onFailActionFromText(const std::string &text)
Convert string to action.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Defines the abstract class for backend stores.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
const string actionToVerb(Action action)
Translates an Action into its corresponding verb.
std::vector< TokenPtr > Expression
This is a structure that holds an expression converted to RPN.
Definition token.h:29
Action
Describe what kind of event is being logged.
Defines the logger used by the top-level component of kea-lfc.