summaryrefslogtreecommitdiffstats
path: root/output/ulogd_output_XML.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2010-01-17 22:34:06 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2010-06-17 12:56:04 +0200
commit0e75d6dba81445f611b03b0157322c003fcdb8e2 (patch)
tree0fe0a5d815dfe5cfd6163ea18ebd20e420978391 /output/ulogd_output_XML.c
parent7338886bd4248ac360d7632962e5b8f363c40fdc (diff)
output: add new plugin XML to output logs in XML
This patch adds XML that allows to log information in XML for ulogd2. It supports packet and flow-based accounting. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'output/ulogd_output_XML.c')
-rw-r--r--output/ulogd_output_XML.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/output/ulogd_output_XML.c b/output/ulogd_output_XML.c
new file mode 100644
index 0000000..fcc130d
--- /dev/null
+++ b/output/ulogd_output_XML.c
@@ -0,0 +1,241 @@
+/* ulogd_XML.c.
+ *
+ * ulogd output target for XML logging.
+ *
+ * (C) 2010 by Pablo Neira Ayuso <pablo@netfilter.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 <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_log/libnetfilter_log.h>
+#include <ulogd/ulogd.h>
+#include <sys/param.h>
+#include <time.h>
+#include <errno.h>
+
+#ifndef ULOGD_XML_DEFAULT_DIR
+#define ULOGD_XML_DEFAULT_DIR "/var/log/"
+#endif
+
+enum {
+ KEY_CT,
+ KEY_PCKT,
+};
+
+static struct ulogd_key xml_inp[] = {
+ [KEY_CT] = {
+ .type = ULOGD_RET_RAW,
+ .flags = ULOGD_RETF_NONE | ULOGD_KEYF_OPTIONAL,
+ .name = "ct",
+ },
+ [KEY_PCKT] = {
+ .type = ULOGD_RET_RAW,
+ .flags = ULOGD_RETF_NONE | ULOGD_KEYF_OPTIONAL,
+ .name = "raw",
+ },
+};
+
+enum {
+ CFG_XML_DIR,
+ CFG_XML_SYNC,
+ CFG_XML_STDOUT,
+};
+
+static struct config_keyset xml_kset = {
+ .num_ces = 3,
+ .ces = {
+ [CFG_XML_DIR] = {
+ .key = "directory",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_NONE,
+ .u = { .string = ULOGD_XML_DEFAULT_DIR },
+ },
+ [CFG_XML_SYNC] = {
+ .key = "sync",
+ .type = CONFIG_TYPE_INT,
+ .options = CONFIG_OPT_NONE,
+ .u = { .value = 0 },
+ },
+ [CFG_XML_STDOUT] = {
+ .key = "stdout",
+ .type = CONFIG_TYPE_INT,
+ .options = CONFIG_OPT_NONE,
+ .u = { .value = 0 },
+ },
+ },
+};
+
+struct xml_priv {
+ FILE *of;
+};
+
+static int
+xml_output_flow(struct ulogd_key *inp, char *buf, ssize_t size)
+{
+ struct nf_conntrack *ct = ikey_get_ptr(&inp[KEY_CT]);
+ int tmp;
+
+ tmp = nfct_snprintf(buf, size, ct, 0, NFCT_O_XML,
+ NFCT_OF_SHOW_LAYER3 | NFCT_OF_ID | NFCT_OF_TIME);
+ if (tmp < 0 || tmp >= size)
+ return -1;
+
+ return 0;
+}
+
+static int
+xml_output_packet(struct ulogd_key *inp, char *buf, ssize_t size)
+{
+ struct nflog_data *ldata = ikey_get_ptr(&inp[KEY_PCKT]);
+ int tmp;
+
+ tmp = nflog_snprintf_xml(buf, size, ldata, NFLOG_XML_ALL);
+ if (tmp < 0 || tmp >= size)
+ return -1;
+
+ return 0;
+}
+
+static int xml_output(struct ulogd_pluginstance *upi)
+{
+ struct ulogd_key *inp = upi->input.keys;
+ struct xml_priv *opi = (struct xml_priv *) &upi->private;
+ static char buf[4096];
+ int ret = -1;
+
+ if (pp_is_valid(inp, KEY_CT))
+ ret = xml_output_flow(inp, buf, sizeof(buf));
+ else if (pp_is_valid(inp, KEY_PCKT))
+ ret = xml_output_packet(inp, buf, sizeof(buf));
+
+ if (ret < 0)
+ return ULOGD_IRET_ERR;
+
+ fprintf(opi->of, "%s\n", buf);
+ if (upi->config_kset->ces[CFG_XML_SYNC].u.value != 0)
+ fflush(opi->of);
+
+ return ULOGD_IRET_OK;
+}
+
+static int xml_configure(struct ulogd_pluginstance *upi,
+ struct ulogd_pluginstance_stack *stack)
+{
+ int ret;
+
+ ret = config_parse_file(upi->id, upi->config_kset);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int xml_fini(struct ulogd_pluginstance *pi)
+{
+ struct xml_priv *op = (struct xml_priv *) &pi->private;
+ /* XXX: provide generic function to get the input plugin. */
+ struct ulogd_pluginstance *input_plugin =
+ llist_entry(pi->stack->list.next,
+ struct ulogd_pluginstance, list);
+
+ /* the initial tag depends on the source. */
+ if (input_plugin->plugin->output.type & ULOGD_DTYPE_FLOW)
+ fprintf(op->of, "</conntrack>\n");
+ else if (input_plugin->plugin->output.type & ULOGD_DTYPE_RAW)
+ fprintf(op->of, "</packet>\n");
+
+ if (op->of != stdout)
+ fclose(op->of);
+
+ return 0;
+}
+
+static int xml_start(struct ulogd_pluginstance *upi)
+{
+ struct xml_priv *op = (struct xml_priv *) &upi->private;
+ char buf[PATH_MAX], filename[FILENAME_MAX];
+ time_t now;
+ struct tm *tm;
+ int ret;
+
+ if (upi->config_kset->ces[CFG_XML_STDOUT].u.value != 0) {
+ op->of = stdout;
+ } else {
+ now = time(NULL);
+ tm = localtime(&now);
+ ret = snprintf(filename, sizeof(filename),
+ "ulogd-%.2d%.2d%.4d-%.2d%.2d%.2d.xml",
+ tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (ret == -1 || ret >= (int)sizeof(filename))
+ return -1;
+
+ ret = snprintf(buf, sizeof(buf), "%s/%s",
+ upi->config_kset->ces[CFG_XML_DIR].u.string,
+ filename);
+ if (ret == -1 || ret >= (int)sizeof(buf))
+ return -1;
+
+ op->of = fopen(buf, "a");
+ if (!op->of) {
+ ulogd_log(ULOGD_FATAL, "can't open XML file: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ }
+ fprintf(op->of, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+
+ struct ulogd_pluginstance *input_plugin =
+ llist_entry(upi->stack->list.next,
+ struct ulogd_pluginstance, list);
+
+ if (input_plugin->plugin->output.type & ULOGD_DTYPE_FLOW)
+ fprintf(op->of, "<conntrack>\n");
+ else if (input_plugin->plugin->output.type & ULOGD_DTYPE_RAW)
+ fprintf(op->of, "<packet>\n");
+
+ if (upi->config_kset->ces[CFG_XML_SYNC].u.value != 0)
+ fflush(op->of);
+
+ return 0;
+}
+
+static struct ulogd_plugin xml_plugin = {
+ .name = "XML",
+ .input = {
+ .keys = xml_inp,
+ .num_keys = ARRAY_SIZE(xml_inp),
+ .type = ULOGD_DTYPE_FLOW,
+ },
+ .output = {
+ .type = ULOGD_DTYPE_SINK,
+ },
+ .config_kset = &xml_kset,
+ .priv_size = sizeof(struct xml_priv),
+
+ .configure = &xml_configure,
+ .start = &xml_start,
+ .stop = &xml_fini,
+ .interp = &xml_output,
+ .version = ULOGD_VERSION,
+};
+
+void __attribute__ ((constructor)) init(void);
+
+void init(void)
+{
+ ulogd_register_plugin(&xml_plugin);
+}