Configuration parameters are extended by standard lease database
parameters as defined in :ref:`database-configuration4`. The ``type``
-parameter should be ``mysql``, ``postgresql`` or ``logfile``; when
+parameter should be ``mysql``, ``postgresql``, ``logfile`` or ``syslog``; when
it is absent or set to ``logfile``, files are used.
No specific tools are provided to operate the database, but standard
If ``retry-on-startup`` is set to ``true``, the server starts reconnection
attempts even at server startup or on reconfigure events, and honors the
action specified in the ``on-fail`` parameter.
+
+.. _forensic-log-syslog:
+
+Syslog Backend
+~~~~~~~~~~~~~~
+
+Log entries can be inserted into syslog by setting the ``type`` to ``syslog``.
+When syslog type is configured, the ``pattern`` parameter specifies the details that
+are used for logging. For more details see :ref:`logging`. If not configured, it defaults
+to:
+
+::
+
+ "%-5p [%c.%t] %m\n"
+
+The ``facility`` parameter specifies the syslog facility and it defaults to ``local0``.
liblegl_la_SOURCES += lease6_callouts.cc
liblegl_la_SOURCES += legal_log_log.cc legal_log_log.h
liblegl_la_SOURCES += legal_log_messages.cc legal_log_messages.h
+liblegl_la_SOURCES += legal_syslog.cc legal_syslog.h
liblegl_la_SOURCES += rotating_file.cc rotating_file.h
liblegl_la_SOURCES += subnets_user_context.h
liblegl_la_SOURCES += version.cc
extern const isc::log::MessageID LEGAL_LOG_STORE_OPEN = "LEGAL_LOG_STORE_OPEN";
extern const isc::log::MessageID LEGAL_LOG_STORE_OPENED = "LEGAL_LOG_STORE_OPENED";
extern const isc::log::MessageID LEGAL_LOG_UNLOAD_ERROR = "LEGAL_LOG_UNLOAD_ERROR";
+extern const isc::log::MessageID LEGAL_SYSLOG_LOG = "LEGAL_SYSLOG_LOG";
+extern const isc::log::MessageID LEGAL_SYSLOG_STORE_OPEN = "LEGAL_SYSLOG_STORE_OPEN";
namespace {
"LEGAL_LOG_STORE_OPEN", "opening Legal Log file: %1",
"LEGAL_LOG_STORE_OPENED", "Legal store opened: %1",
"LEGAL_LOG_UNLOAD_ERROR", "An error occurred unloading the library: %1",
+ "LEGAL_SYSLOG_LOG", "%1",
+ "LEGAL_SYSLOG_STORE_OPEN", "opening Legal Syslog: %1",
NULL
};
extern const isc::log::MessageID LEGAL_LOG_STORE_OPEN;
extern const isc::log::MessageID LEGAL_LOG_STORE_OPENED;
extern const isc::log::MessageID LEGAL_LOG_UNLOAD_ERROR;
+extern const isc::log::MessageID LEGAL_SYSLOG_LOG;
+extern const isc::log::MessageID LEGAL_SYSLOG_STORE_OPEN;
#endif // LEGAL_LOG_MESSAGES_H
V6) is about to open a legal log file. The parameters of
the backend are logged.
+% LEGAL_SYSLOG_STORE_OPEN opening Legal Syslog: %1
+This informational message is logged when a DHCP server (either V4 or
+V6) is about to open a legal syslog store. The parameters of
+the backend are logged.
+
+% LEGAL_SYSLOG_LOG %1
+This informational message contains the message being logged to syslog.
+
% LEGAL_LOG_STORE_OPENED Legal store opened: %1
This is an informational message issued when the Legal Log library
has successfully opened the legal store.
--- /dev/null
+// Copyright (C) 2016-2025 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <dhcpsrv/cfgmgr.h>
+#include <legal_log_log.h>
+#include <legal_syslog.h>
+#include <log/logger_manager.h>
+#include <log/message_initializer.h>
+#include <log/macros.h>
+#include <process/logging_info.h>
+
+using namespace isc;
+using namespace isc::db;
+using namespace isc::dhcp;
+using namespace isc::log;
+using namespace isc::process;
+using namespace std;
+
+namespace isc {
+namespace legal_log {
+
+LegalSyslog::LegalSyslog(const DatabaseConnection::ParameterMap& parameters)
+ : LegalLogMgr(parameters) {
+ LoggingInfo info;
+ // Remove default destinations as we are going to replace them.
+ info.clearDestinations();
+ info.name_ = "legal-log-syslog-";
+ info.name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
+ logger_.reset(new Logger(info.name_.c_str()));
+ LoggingDestination dest;
+ dest.output_ = "syslog:";
+ if (parameters.find("facility") != parameters.end()) {
+ dest.output_ += parameters.at("facility");
+ } else {
+ dest.output_ += "LOCAL0";
+ }
+ if (parameters.find("pattern") != parameters.end()) {
+ dest.pattern_ = parameters.at("pattern");
+ }
+ info.destinations_.push_back(dest);
+ CfgMgr::instance().getStagingCfg()->addLoggingInfo(info);
+}
+
+void
+LegalSyslog::open() {
+}
+
+void
+LegalSyslog::close() {
+}
+
+void
+LegalSyslog::writeln(const string& text, const string&) {
+ LOG_INFO(*logger_, LEGAL_SYSLOG_LOG)
+ .arg(text);
+}
+
+string
+LegalSyslog::getType() const {
+ return ("syslog");
+}
+
+LegalLogMgrPtr
+LegalSyslog::factory(const DatabaseConnection::ParameterMap& parameters) {
+ LOG_INFO(legal_log_logger, LEGAL_SYSLOG_STORE_OPEN)
+ .arg(DatabaseConnection::redactedAccessString(parameters));
+ return (LegalLogMgrPtr(new LegalSyslog(parameters)));
+}
+
+} // namespace legal_log
+} // namespace isc
--- /dev/null
+// Copyright (C) 2025 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef LEGAL_SYSLOG_H
+#define LEGAL_SYSLOG_H
+
+#include <dhcpsrv/legal_log_mgr_factory.h>
+
+namespace isc {
+namespace legal_log {
+
+class LegalSyslog : public isc::dhcp::LegalLogMgr {
+public:
+ /// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the manager configuration.
+ LegalSyslog(const isc::db::DatabaseConnection::ParameterMap& parameters);
+
+ /// @brief Destructor.
+ ///
+ /// The destructor does call the close method.
+ virtual ~LegalSyslog() = default;
+
+ /// @brief Opens the store.
+ virtual void open();
+
+ /// @brief Closes the store.
+ virtual void close();
+
+ /// @brief Appends a string to the store with a timestamp and address.
+ ///
+ /// @param text String to append
+ /// @param addr Address or prefix
+ /// @throw LegalLogMgrError if the write fails
+ virtual void writeln(const std::string& text, const std::string& addr);
+
+ /// @brief Return backend type
+ ///
+ /// Returns the type of the backend (e.g. "mysql", "logfile" etc.)
+ ///
+ /// @return Type of the backend.
+ virtual std::string getType() const;
+
+private:
+ /// @brief Logger used to write to syslog.
+ std::shared_ptr<isc::log::Logger> logger_;
+
+public:
+ /// @brief Factory class method.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ ///
+ /// @return The Rotating File Store Backend.
+ static isc::dhcp::LegalLogMgrPtr
+ factory(const isc::db::DatabaseConnection::ParameterMap& parameters);
+};
+
+} // namespace legal_log
+} // namespace isc
+
+#endif
- the address (or prefix) column can be null / empty.
This allows to insert no address related log entries.
+## Syslog
+
+Log entries can be inserted into syslog by setting the "type" to "syslog".
+When syslog type is configured, the "pattern" parameter specifies the details that
+are used for logging. If not configured, it defaults to: "%-5p [%c.%t] %m\n".
+
+The "facility" parameter specifies the syslog facility and it defaults to "local0".
+
@section libdhcp_legal_logMTCompatibility Multi-Threading Compatibility
The libdhcp_legal_log hooks library is compatible with multi-threading.
#include <dhcpsrv/cfgmgr.h>
#include <process/daemon.h>
#include <legal_log_log.h>
+#include <legal_syslog.h>
#include <dhcpsrv/legal_log_mgr.h>
#include <rotating_file.h>
}
LegalLogMgrFactory::registerBackendFactory("logfile", RotatingFile::factory);
+ LegalLogMgrFactory::registerBackendFactory("syslog", LegalSyslog::factory);
// Get and decode parameters.
ConstElementPtr const& parameters(handle.getParameters());
LegalLogMgrFactory::delAllBackends();
LegalLogMgrFactory::unregisterBackendFactory("logfile");
+ LegalLogMgrFactory::unregisterBackendFactory("syslog");
} catch (const std::exception& ex) {
// On the off chance something goes awry, catch it and log it.
// @todo Not sure if we should return a non-zero result or not.
'lease6_callouts.cc',
'legal_log_log.cc',
'legal_log_messages.cc',
+ 'legal_syslog.cc',
'load_unload.cc',
'rotating_file.cc',
'version.cc',
/// 'count' number of days, months or years (when the write function call
/// detects that the day, month or year has changed).
///
- /// @param path Directory in which file(s) will be created.
- /// @param base_name Base file name to use when creating files.
- /// @param unit The time unit used to rotate the file.
- /// @param count The number of time units used to rotate the file (0 means
- /// disabled).
- /// @param prerotate The script to be run before closing the old file.
- /// @param postrotate The script to be run after opening the new file.
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the manager configuration.
///
/// @throw LegalLogMgrError if given file name is empty.
RotatingFile(const isc::db::DatabaseConnection::ParameterMap& parameters);
if (!parameters || !parameters->get("type") ||
parameters->get("type")->stringValue() == "logfile") {
parseFile(parameters, map);
+ } else if (parameters->get("type")->stringValue() == "syslog") {
+ parseSyslog(parameters, map);
} else {
parseDatabase(parameters, map);
}
map = db_parameters;
}
+void
+LegalLogMgr::parseSyslog(const ConstElementPtr& parameters, DatabaseConnection::ParameterMap& map) {
+ // Should never happen with the code flow at the time of writing, but
+ // let's get this check out of the way.
+ if (!parameters) {
+ isc_throw(BadValue, "no parameters specified for the hook library");
+ }
+
+ DatabaseConnection::ParameterMap syslog_parameters;
+
+ // Strings
+ for (char const* const& key : { "type", "pattern", "facility" }) {
+ ConstElementPtr const value(parameters->get(key));
+ if (value) {
+ syslog_parameters.emplace(key, value->stringValue());
+ }
+ }
+
+ map = syslog_parameters;
+}
+
void
LegalLogMgr::parseFile(const ConstElementPtr& parameters, DatabaseConnection::ParameterMap& map) {
DatabaseConnection::ParameterMap file_parameters;
class LegalLogMgr {
public:
/// @brief Constructor.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the manager configuration.
LegalLogMgr(const isc::db::DatabaseConnection::ParameterMap parameters) :
timestamp_format_("%Y-%m-%d %H:%M:%S %Z"),
parameters_(parameters) {
/// @param [out] map The parameter map.
static void parseFile(const isc::data::ConstElementPtr& parameters, isc::db::DatabaseConnection::ParameterMap& map);
+ /// @brief Parse syslog specification.
+ ///
+ /// Parse the configuration and check that the various keywords are
+ /// consistent.
+ ///
+ /// @param parameters The library parameters.
+ /// @param [out] map The parameter map.
+ static void parseSyslog(const isc::data::ConstElementPtr& parameters, isc::db::DatabaseConnection::ParameterMap& map);
+
/// @brief Parse extra parameters which are not related to backend
/// connection.
///
// Call the factory and push the pointer on sources.
auto backend = index->second.first(parameters);
if (!backend) {
- isc_throw(Unexpected, "Forensic log database " << db_type <<
+ isc_throw(Unexpected, "Forensic log backend " << db_type <<
" factory returned NULL");
}