summaryrefslogtreecommitdiffstats
path: root/output
diff options
context:
space:
mode:
Diffstat (limited to 'output')
-rw-r--r--output/Makefile.am10
-rw-r--r--output/ulogd_output_JSON.c254
2 files changed, 264 insertions, 0 deletions
diff --git a/output/Makefile.am b/output/Makefile.am
index 17427d0..ff851ad 100644
--- a/output/Makefile.am
+++ b/output/Makefile.am
@@ -9,6 +9,10 @@ pkglib_LTLIBRARIES = ulogd_output_LOGEMU.la ulogd_output_SYSLOG.la \
ulogd_output_NACCT.la ulogd_output_XML.la \
ulogd_output_GRAPHITE.la
+if HAVE_JANSSON
+pkglib_LTLIBRARIES += ulogd_output_JSON.la
+endif
+
ulogd_output_GPRINT_la_SOURCES = ulogd_output_GPRINT.c
ulogd_output_GPRINT_la_LDFLAGS = -avoid-version -module
@@ -32,3 +36,9 @@ ulogd_output_XML_la_LDFLAGS = -avoid-version -module
ulogd_output_GRAPHITE_la_SOURCES = ulogd_output_GRAPHITE.c
ulogd_output_GRAPHITE_la_LDFLAGS = -avoid-version -module
+
+if HAVE_JANSSON
+ulogd_output_JSON_la_SOURCES = ulogd_output_JSON.c
+ulogd_output_JSON_la_LIBADD = ${libjansson_LIBS}
+ulogd_output_JSON_la_LDFLAGS = -avoid-version -module
+endif
diff --git a/output/ulogd_output_JSON.c b/output/ulogd_output_JSON.c
new file mode 100644
index 0000000..04158a8
--- /dev/null
+++ b/output/ulogd_output_JSON.c
@@ -0,0 +1,254 @@
+/* ulogd_output_JSON.c
+ *
+ * ulogd output target for logging to a file in JSON format.
+ *
+ * (C) 2014 by Eric Leblond <eric@regit.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+#include <jansson.h>
+
+#ifndef ULOGD_JSON_DEFAULT
+#define ULOGD_JSON_DEFAULT "/var/log/ulogd.json"
+#endif
+
+#ifndef ULOGD_JSON_DEFAULT_DEVICE
+#define ULOGD_JSON_DEFAULT_DEVICE "Netfilter"
+#endif
+
+struct json_priv {
+ FILE *of;
+};
+
+enum json_conf {
+ JSON_CONF_FILENAME = 0,
+ JSON_CONF_SYNC,
+ JSON_CONF_TIMESTAMP,
+ JSON_CONF_DEVICE,
+ JSON_CONF_BOOLEAN_LABEL,
+ JSON_CONF_MAX
+};
+
+static struct config_keyset json_kset = {
+ .num_ces = JSON_CONF_MAX,
+ .ces = {
+ [JSON_CONF_FILENAME] = {
+ .key = "file",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_NONE,
+ .u = {.string = ULOGD_JSON_DEFAULT },
+ },
+ [JSON_CONF_SYNC] = {
+ .key = "sync",
+ .type = CONFIG_TYPE_INT,
+ .options = CONFIG_OPT_NONE,
+ .u = { .value = 0 },
+ },
+ [JSON_CONF_TIMESTAMP] = {
+ .key = "timestamp",
+ .type = CONFIG_TYPE_INT,
+ .options = CONFIG_OPT_NONE,
+ .u = { .value = 1 },
+ },
+ [JSON_CONF_DEVICE] = {
+ .key = "device",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_NONE,
+ .u = { .string = ULOGD_JSON_DEFAULT_DEVICE },
+ },
+ [JSON_CONF_BOOLEAN_LABEL] = {
+ .key = "boolean_label",
+ .type = CONFIG_TYPE_INT,
+ .options = CONFIG_OPT_NONE,
+ .u = { .value = 0 },
+ },
+ },
+};
+
+static int json_interp(struct ulogd_pluginstance *upi)
+{
+ struct json_priv *opi = (struct json_priv *) &upi->private;
+ unsigned int i;
+ json_t *msg;
+
+ msg = json_object();
+ if (!msg) {
+ ulogd_log(ULOGD_ERROR, "Unable to create JSON object\n");
+ return ULOGD_IRET_ERR;
+ }
+
+ if (upi->config_kset->ces[JSON_CONF_TIMESTAMP].u.value != 0) {
+ time_t now;
+ char *timestr = NULL;
+ now = time(NULL);
+
+ timestr = ctime(&now);
+ timestr[strlen(timestr) - 1] = '\0';
+
+ json_object_set_new(msg, "timestamp", json_string(timestr));
+ }
+
+ if (upi->config_kset->ces[JSON_CONF_DEVICE].u.string) {
+ char *dvc = upi->config_kset->ces[JSON_CONF_DEVICE].u.string;
+ json_object_set_new(msg, "dvc", json_string(dvc));
+ }
+
+
+
+ for (i = 0; i < upi->input.num_keys; i++) {
+ struct ulogd_key *key = upi->input.keys[i].u.source;
+ char *field_name;
+
+ if (!key)
+ continue;
+
+ if (!IS_VALID(*key))
+ continue;
+
+ field_name = key->cim_name ? key->cim_name : key->name;
+
+ switch (key->type) {
+ case ULOGD_RET_STRING:
+ json_object_set_new(msg, field_name, json_string(key->u.value.ptr));
+ break;
+ case ULOGD_RET_BOOL:
+ case ULOGD_RET_INT8:
+ case ULOGD_RET_INT16:
+ case ULOGD_RET_INT32:
+ json_object_set_new(msg, field_name, json_integer(key->u.value.i32));
+ break;
+ case ULOGD_RET_UINT8:
+ if ((upi->config_kset->ces[JSON_CONF_BOOLEAN_LABEL].u.value != 0)
+ && (!strcmp(key->name, "raw.label"))) {
+ if (key->u.value.ui8)
+ json_object_set_new(msg, "action", json_string("allowed"));
+ else
+ json_object_set_new(msg, "action", json_string("blocked"));
+ break;
+ }
+ case ULOGD_RET_UINT16:
+ case ULOGD_RET_UINT32:
+ case ULOGD_RET_UINT64:
+ json_object_set_new(msg, field_name, json_integer(key->u.value.ui64));
+ default:
+ /* don't know how to interpret this key. */
+ break;
+ }
+ }
+
+ json_dumpf(msg, opi->of, 0);
+ fprintf(opi->of, "\n");
+
+ json_decref(msg);
+
+ if (upi->config_kset->ces[JSON_CONF_SYNC].u.value != 0)
+ fflush(opi->of);
+
+ return ULOGD_IRET_OK;
+}
+
+static void sighup_handler_print(struct ulogd_pluginstance *upi, int signal)
+{
+ struct json_priv *oi = (struct json_priv *) &upi->private;
+ FILE *old = oi->of;
+
+ switch (signal) {
+ case SIGHUP:
+ ulogd_log(ULOGD_NOTICE, "JSON: reopening logfile\n");
+ oi->of = fopen(upi->config_kset->ces[0].u.string, "a");
+ if (!oi->of) {
+ ulogd_log(ULOGD_ERROR, "can't open JSON "
+ "log file: %s\n",
+ strerror(errno));
+ oi->of = old;
+ } else {
+ fclose(old);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int json_configure(struct ulogd_pluginstance *upi,
+ struct ulogd_pluginstance_stack *stack)
+{
+ int ret;
+
+ ret = ulogd_wildcard_inputkeys(upi);
+ if (ret < 0)
+ return ret;
+
+ ret = config_parse_file(upi->id, upi->config_kset);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int json_init(struct ulogd_pluginstance *upi)
+{
+ struct json_priv *op = (struct json_priv *) &upi->private;
+
+ op->of = fopen(upi->config_kset->ces[0].u.string, "a");
+ if (!op->of) {
+ ulogd_log(ULOGD_FATAL, "can't open JSON log file: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int json_fini(struct ulogd_pluginstance *pi)
+{
+ struct json_priv *op = (struct json_priv *) &pi->private;
+
+ if (op->of != stdout)
+ fclose(op->of);
+
+ return 0;
+}
+
+static struct ulogd_plugin json_plugin = {
+ .name = "JSON",
+ .input = {
+ .type = ULOGD_DTYPE_PACKET | ULOGD_DTYPE_FLOW | ULOGD_DTYPE_SUM,
+ },
+ .output = {
+ .type = ULOGD_DTYPE_SINK,
+ },
+ .configure = &json_configure,
+ .interp = &json_interp,
+ .start = &json_init,
+ .stop = &json_fini,
+ .signal = &sighup_handler_print,
+ .config_kset = &json_kset,
+ .version = VERSION,
+};
+
+void __attribute__ ((constructor)) init(void);
+
+void init(void)
+{
+ ulogd_register_plugin(&json_plugin);
+}