diff --git a/conf/Makefile.am b/conf/Makefile.am index 373be1631..08613708c 100644 --- a/conf/Makefile.am +++ b/conf/Makefile.am @@ -12,6 +12,7 @@ options = \ options/attest.opt \ options/charon.opt \ options/charon-logging.opt \ + options/charon-systemd.opt \ options/imcv.opt \ options/manager.opt \ options/medsrv.opt \ diff --git a/conf/options/charon-systemd.opt b/conf/options/charon-systemd.opt new file mode 100644 index 000000000..3482f449f --- /dev/null +++ b/conf/options/charon-systemd.opt @@ -0,0 +1,13 @@ +charon-systemd.journal {} + Section to configure native systemd journal logger, very similar to the + syslog logger as described in LOGGER CONFIGURATION in + **strongswan.conf**(5). + +charon-systemd.journal.default = 1 + Default loglevel. + + Specifies the default loglevel to be used for subsystems for which no + specific loglevel is defined. + +charon-systemd.journal. = + Loglevel for a specific subsystem. diff --git a/src/charon-systemd/Makefile.am b/src/charon-systemd/Makefile.am index 677ea3aff..b9a251f6c 100644 --- a/src/charon-systemd/Makefile.am +++ b/src/charon-systemd/Makefile.am @@ -15,4 +15,4 @@ charon_systemd_LDADD = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(top_builddir)/src/libhydra/libhydra.la \ $(top_builddir)/src/libcharon/libcharon.la \ - -lsystemd-daemon -lm $(PTHREADLIB) $(DLLIB) + -lsystemd-daemon -lsystemd-journal -lm $(PTHREADLIB) $(DLLIB) diff --git a/src/charon-systemd/charon-systemd.c b/src/charon-systemd/charon-systemd.c index de9d9b59c..07444e812 100644 --- a/src/charon-systemd/charon-systemd.c +++ b/src/charon-systemd/charon-systemd.c @@ -1,9 +1,10 @@ /* * Copyright (C) 2006-2012 Tobias Brunner - * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005-2014 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil + * Copyright (C) 2014 revosec AG * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -24,7 +25,11 @@ #include #include #include + +/* won't make sense from our logging hook */ +#define SD_JOURNAL_SUPPRESS_LOCATION #include +#include #include #include @@ -32,6 +37,7 @@ #include #include #include +#include /** * hook in library for debugging messages @@ -55,6 +61,168 @@ static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) } } +typedef struct journal_logger_t journal_logger_t; + +/** + * Logger implementation using systemd-journal + */ +struct journal_logger_t { + + /** + * Implements logger_t + */ + logger_t logger; + + /** + * Configured loglevels + */ + level_t levels[DBG_MAX]; + + /** + * Lock for levels + */ + rwlock_t *lock; +}; + +METHOD(logger_t, vlog, void, + journal_logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t *ike_sa, const char *fmt, va_list args) +{ + char buf[4096], *msg = buf; + ssize_t len; + va_list copy; + + va_copy(copy, args); + len = vsnprintf(msg, sizeof(buf), fmt, copy); + va_end(copy); + + if (len >= sizeof(buf)) + { + len++; + msg = malloc(len); + va_copy(copy, args); + len = vsnprintf(msg, len, fmt, copy); + va_end(copy); + } + if (len > 0) + { + char unique[64] = "", name[256] = ""; + int priority; + + if (ike_sa) + { + snprintf(unique, sizeof(unique), "IKE_SA_UNIQUE_ID=%u", + ike_sa->get_unique_id(ike_sa)); + if (ike_sa->get_peer_cfg(ike_sa)) + { + snprintf(name, sizeof(name), "IKE_SA_NAME=%s", + ike_sa->get_name(ike_sa)); + } + } + switch (level) + { + case LEVEL_AUDIT: + priority = LOG_NOTICE; + break; + case LEVEL_CTRL: + priority = LOG_INFO; + break; + default: + priority = LOG_DEBUG; + break; + } + sd_journal_send( + "MESSAGE=%s", msg, + "MESSAGE_ID=57d2708c-d607-43bd-8c39-66bf%.8x", + chunk_hash_static(chunk_from_str((char*)fmt)), + "PRIORITY=%d", priority, + "GROUP=%N", debug_names, group, + "LEVEL=%d", level, + "THREAD=%d", thread, + unique[0] ? unique : NULL, + name[0] ? name : NULL, + NULL); + } + if (msg != buf) + { + free(msg); + } +} + +METHOD(logger_t, get_level, level_t, + journal_logger_t *this, debug_t group) +{ + level_t level; + + this->lock->read_lock(this->lock); + level = this->levels[group]; + this->lock->unlock(this->lock); + + return level; +} + +/** + * Reload journal logger configuration + */ +CALLBACK(journal_reload, bool, + journal_logger_t **journal) +{ + journal_logger_t *this = *journal; + debug_t group; + level_t def; + + def = lib->settings->get_int(lib->settings, "%s.journal.default", 1, lib->ns); + + this->lock->write_lock(this->lock); + for (group = 0; group < DBG_MAX; group++) + { + this->levels[group] = + lib->settings->get_int(lib->settings, + "%s.journal.%N", def, lib->ns, debug_lower_names, group); + } + this->lock->unlock(this->lock); + + charon->bus->add_logger(charon->bus, &this->logger); + + return TRUE; +} + +/** + * Initialize/deinitialize journal logger + */ +static bool journal_register(void *plugin, plugin_feature_t *feature, + bool reg, journal_logger_t **logger) +{ + journal_logger_t *this; + + if (reg) + { + INIT(this, + .logger = { + .vlog = _vlog, + .get_level = _get_level, + }, + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + journal_reload(&this); + + *logger = this; + return TRUE; + } + else + { + this = *logger; + + charon->bus->remove_logger(charon->bus, &this->logger); + + this->lock->destroy(this->lock); + free(this); + + return TRUE; + } +} + /** * Run the daemon and handle unix signals */ @@ -132,6 +300,19 @@ static void segv_handler(int signal) abort(); } +/** + * The journal logger instance + */ +static journal_logger_t *journal; + +/** + * Journal static features + */ +static plugin_feature_t features[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)journal_register, &journal), + PLUGIN_PROVIDE(CUSTOM, "systemd-journal"), +}; + /** * Main function, starts the daemon. */ @@ -181,6 +362,9 @@ int main(int argc, char *argv[]) } charon->load_loggers(charon, NULL, FALSE); + lib->plugins->add_static_features(lib->plugins, lib->ns, features, + countof(features), TRUE, journal_reload, &journal); + if (!charon->initialize(charon, PLUGINS)) { sd_notifyf(0, "STATUS=charon initialization failed");