]> git.ipfire.org Git - thirdparty/ulogd2.git/commitdiff
input: add nfacct plugin
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 21 Feb 2012 19:07:00 +0000 (20:07 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 22 Feb 2012 12:16:00 +0000 (13:16 +0100)
This patch adds the nfacct plugin.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
configure.ac
include/Makefile.am
include/linux/Makefile.am [new file with mode: 0644]
include/linux/netfilter/Makefile.am [new file with mode: 0644]
include/linux/netfilter/nfnetlink_acct.h [new file with mode: 0644]
input/Makefile.am
input/sum/Makefile.am [new file with mode: 0644]
input/sum/ulogd_inpflow_NFACCT.c [new file with mode: 0644]
ulogd.conf.in

index 132cdbff37a6106422968663af9b6706974d9df2..89fc338ecdae012f861c6083eab25c7526adaea6 100644 (file)
@@ -41,6 +41,8 @@ AC_SUBST([regular_CFLAGS])
 
 dnl Check for the right nfnetlink version
 PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 0.0.39])
+PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.0])
+PKG_CHECK_MODULES([LIBNETFILTER_ACCT], [libnetfilter_acct >= 1.0.0])
 PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 0.0.95])
 PKG_CHECK_MODULES([LIBNETFILTER_LOG], [libnetfilter_log >= 1.0.0])
 
@@ -74,8 +76,10 @@ dnl AM_CONDITIONAL(HAVE_MYSQL, test x$mysqldir != x)
 dnl AM_CONDITIONAL(HAVE_PGSQL, test x$pgsqldir != x)
 
 AC_CONFIG_FILES(include/Makefile include/ulogd/Makefile include/libipulog/Makefile \
+         include/linux/Makefile include/linux/netfilter/Makefile \
          libipulog/Makefile \
          input/Makefile input/packet/Makefile input/flow/Makefile \
+         input/sum/Makefile \
          filter/Makefile filter/raw2packet/Makefile filter/packet2flow/Makefile \
          output/Makefile output/pcap/Makefile output/mysql/Makefile output/pgsql/Makefile output/sqlite3/Makefile \
          output/dbi/Makefile \
index fa3447374ea1bd01db3e495c5b791c044db4702c..c62b497c4d8f40d2d225e7403a04610ca9bb8435 100644 (file)
@@ -1 +1 @@
-SUBDIRS = ulogd libipulog
+SUBDIRS = ulogd libipulog linux
diff --git a/include/linux/Makefile.am b/include/linux/Makefile.am
new file mode 100644 (file)
index 0000000..ca80d0d
--- /dev/null
@@ -0,0 +1,2 @@
+
+SUBDIRS = netfilter
diff --git a/include/linux/netfilter/Makefile.am b/include/linux/netfilter/Makefile.am
new file mode 100644 (file)
index 0000000..fc05a9c
--- /dev/null
@@ -0,0 +1,2 @@
+
+noinst_HEADERS = nfnetlink_acct.h
diff --git a/include/linux/netfilter/nfnetlink_acct.h b/include/linux/netfilter/nfnetlink_acct.h
new file mode 100644 (file)
index 0000000..7c4279b
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _NFNL_ACCT_H_
+#define _NFNL_ACCT_H_
+
+#ifndef NFACCT_NAME_MAX
+#define NFACCT_NAME_MAX                32
+#endif
+
+enum nfnl_acct_msg_types {
+       NFNL_MSG_ACCT_NEW,
+       NFNL_MSG_ACCT_GET,
+       NFNL_MSG_ACCT_GET_CTRZERO,
+       NFNL_MSG_ACCT_DEL,
+       NFNL_MSG_ACCT_MAX
+};
+
+enum nfnl_acct_type {
+       NFACCT_UNSPEC,
+       NFACCT_NAME,
+       NFACCT_PKTS,
+       NFACCT_BYTES,
+       NFACCT_USE,
+       __NFACCT_MAX
+};
+#define NFACCT_MAX (__NFACCT_MAX - 1)
+
+#ifdef __KERNEL__
+
+struct nf_acct;
+
+extern struct nf_acct *nfnl_acct_find_get(const char *filter_name);
+extern void nfnl_acct_put(struct nf_acct *acct);
+extern void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct);
+
+#endif /* __KERNEL__ */
+
+#endif /* _NFNL_ACCT_H */
index 77f2838ca59b1b333122c23d204a4dc9373043ed..5ffef1b4e711dbcb065f40b73d2f07cc9236bf1c 100644 (file)
@@ -1,2 +1,2 @@
 
-SUBDIRS = packet flow
+SUBDIRS = packet flow sum
diff --git a/input/sum/Makefile.am b/input/sum/Makefile.am
new file mode 100644 (file)
index 0000000..04051b4
--- /dev/null
@@ -0,0 +1,8 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+AM_CFLAGS = ${regular_CFLAGS}
+
+pkglibexec_LTLIBRARIES = ulogd_inpflow_NFACCT.la
+
+ulogd_inpflow_NFACCT_la_SOURCES = ulogd_inpflow_NFACCT.c
+ulogd_inpflow_NFACCT_la_LDFLAGS = -avoid-version -module $(LIBMNL_LIBS) $(LIBNETFILTER_ACCT_LIBS)
+ulogd_inpflow_NFACCT_la_CFLAGS = $(AM_CFLAGS) $(LIBMNL_LIBS) $(LIBNETFILTER_ACCT_CFLAGS)
diff --git a/input/sum/ulogd_inpflow_NFACCT.c b/input/sum/ulogd_inpflow_NFACCT.c
new file mode 100644 (file)
index 0000000..152cd48
--- /dev/null
@@ -0,0 +1,265 @@
+/* ulogd_input_NFACCT.c
+ *
+ * ulogd input plugin for nfacct
+ *
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2012 by Intra2net AG <http://www.intra2net.com>
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/time.h>
+#include <time.h>
+#include <netinet/in.h>
+
+#include <ulogd/ulogd.h>
+#include <ulogd/timer.h>
+
+#include <libmnl/libmnl.h>
+#include <libnetfilter_acct/libnetfilter_acct.h>
+
+struct nfacct_pluginstance {
+       struct mnl_socket       *nl;
+       uint32_t                portid;
+       uint32_t                seq;
+       struct ulogd_fd         ufd;
+       struct ulogd_timer      timer;
+};
+
+static struct config_keyset nfacct_kset = {
+       .ces = {
+               {
+                       .key     = "pollinterval",
+                       .type    = CONFIG_TYPE_INT,
+                       .options = CONFIG_OPT_NONE,
+                       .u.value = 0,
+               },
+       },
+       .num_ces = 1,
+};
+#define pollint_ce(x)  (x->ces[0])
+
+enum ulogd_nfacct_keys {
+       ULOGD_NFACCT_NAME,
+       ULOGD_NFACCT_PKTS,
+       ULOGD_NFACCT_BYTES,
+};
+
+static struct ulogd_key nfacct_okeys[] = {
+       [ULOGD_NFACCT_NAME] = {
+               .type   = ULOGD_RET_STRING,
+               .flags  = ULOGD_RETF_NONE,
+               .name   = "sum.name",
+       },
+       [ULOGD_NFACCT_PKTS] = {
+               .type   = ULOGD_RET_UINT64,
+               .flags  = ULOGD_RETF_NONE,
+               .name   = "sum.pkts",
+       },
+       [ULOGD_NFACCT_BYTES] = {
+               .type   = ULOGD_RET_UINT64,
+               .flags  = ULOGD_RETF_NONE,
+               .name   = "sum.bytes",
+       },
+};
+
+static void
+propagate_nfacct(struct ulogd_pluginstance *upi, struct nfacct *nfacct)
+{
+       struct ulogd_key *ret = upi->output.keys;
+
+       okey_set_ptr(&ret[ULOGD_NFACCT_NAME],
+                       (void *)nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME));
+       okey_set_u64(&ret[ULOGD_NFACCT_PKTS],
+                       nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS));
+       okey_set_u64(&ret[ULOGD_NFACCT_BYTES],
+                       nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES));
+
+       ulogd_propagate_results(upi);
+}
+
+static void
+do_propagate_nfacct(struct ulogd_pluginstance *upi, struct nfacct *nfacct)
+{
+       struct ulogd_pluginstance *npi = NULL;
+
+       llist_for_each_entry(npi, &upi->plist, plist)
+               propagate_nfacct(npi, nfacct);
+
+       propagate_nfacct(upi, nfacct);
+}
+
+static int nfacct_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nfacct *nfacct;
+       struct ulogd_pluginstance *upi = data;
+
+       nfacct = nfacct_alloc();
+       if (nfacct == NULL) {
+               ulogd_log(ULOGD_ERROR, "OOM");
+               goto err;
+       }
+
+       if (nfacct_nlmsg_parse_payload(nlh, nfacct) < 0) {
+               ulogd_log(ULOGD_ERROR, "Error parsing nfacct message");
+               goto err_free;
+       }
+
+       do_propagate_nfacct(upi, nfacct);
+
+err_free:
+       nfacct_free(nfacct);
+err:
+       return MNL_CB_OK;
+}
+
+static int nfacct_read_cb(int fd, unsigned int what, void *param)
+{
+       int ret;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct ulogd_pluginstance *upi = param;
+       struct nfacct_pluginstance *cpi =
+               (struct nfacct_pluginstance *) upi->private;
+
+       if (!(what & ULOGD_FD_READ))
+               return 0;
+
+       ret = mnl_socket_recvfrom(cpi->nl, buf, sizeof(buf));
+       if (ret > 0) {
+               ret = mnl_cb_run(buf, ret, cpi->seq,
+                                cpi->portid, nfacct_cb, upi);
+       }
+       return ret;
+}
+
+static int nfacct_send_request(struct nfacct_pluginstance *cpi)
+{
+       struct nlmsghdr *nlh;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+
+       cpi->seq = time(NULL);
+       nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET_CTRZERO,
+                                    NLM_F_DUMP, cpi->seq);
+
+       if (mnl_socket_sendto(cpi->nl, nlh, nlh->nlmsg_len) < 0) {
+               ulogd_log(ULOGD_ERROR, "Cannot send netlink message\n");
+               return -1;
+       }
+       return 0;
+}
+
+static void polling_timer_cb(struct ulogd_timer *t, void *data)
+{
+       struct ulogd_pluginstance *upi = data;
+       struct nfacct_pluginstance *cpi =
+               (struct nfacct_pluginstance *)upi->private;
+
+       nfacct_send_request(cpi);
+
+       ulogd_add_timer(&cpi->timer, pollint_ce(upi->config_kset).u.value);
+}
+
+static int configure_nfacct(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;
+
+       if (pollint_ce(upi->config_kset).u.value <= 0) {
+               ulogd_log(ULOGD_FATAL, "You have to set pollint\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int constructor_nfacct(struct ulogd_pluginstance *upi)
+{
+       struct nfacct_pluginstance *cpi =
+               (struct nfacct_pluginstance *)upi->private;
+
+       if (pollint_ce(upi->config_kset).u.value == 0)
+               return -1;
+
+       cpi->nl = mnl_socket_open(NETLINK_NETFILTER);
+       if (cpi->nl == NULL) {
+               ulogd_log(ULOGD_FATAL, "cannot open netlink socket\n");
+               return -1;
+       }
+
+       if (mnl_socket_bind(cpi->nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+               ulogd_log(ULOGD_FATAL, "cannot bind netlink socket\n");
+               return -1;
+       }
+       cpi->portid = mnl_socket_get_portid(cpi->nl);
+
+       cpi->ufd.fd = mnl_socket_get_fd(cpi->nl);
+       cpi->ufd.cb = &nfacct_read_cb;
+       cpi->ufd.data = upi;
+       cpi->ufd.when = ULOGD_FD_READ;
+
+       ulogd_register_fd(&cpi->ufd);
+       ulogd_init_timer(&cpi->timer, upi, polling_timer_cb);
+       ulogd_add_timer(&cpi->timer,
+                        pollint_ce(upi->config_kset).u.value);
+
+       return 0;
+}
+
+static int destructor_nfacct(struct ulogd_pluginstance *upi)
+{
+       struct nfacct_pluginstance *cpi = (void *)upi->private;
+
+       ulogd_del_timer(&cpi->timer);
+       ulogd_unregister_fd(&cpi->ufd);
+       mnl_socket_close(cpi->nl);
+
+       return 0;
+}
+
+static void signal_nfacct(struct ulogd_pluginstance *upi, int signal)
+{
+       struct nfacct_pluginstance *cpi =
+               (struct nfacct_pluginstance *)upi->private;
+
+       switch (signal) {
+       case SIGUSR2:
+               nfacct_send_request(cpi);
+               break;
+       }
+}
+
+static struct ulogd_plugin nfacct_plugin = {
+       .name = "NFACCT",
+       .input = {
+               .type = ULOGD_DTYPE_SOURCE,
+       },
+       .output = {
+               .keys = nfacct_okeys,
+               .num_keys = ARRAY_SIZE(nfacct_okeys),
+               .type = ULOGD_DTYPE_FLOW,
+       },
+       .config_kset    = &nfacct_kset,
+       .interp         = NULL,
+       .configure      = &configure_nfacct,
+       .start          = &constructor_nfacct,
+       .stop           = &destructor_nfacct,
+       .signal         = &signal_nfacct,
+       .priv_size      = sizeof(struct nfacct_pluginstance),
+       .version        = ULOGD_VERSION,
+};
+
+void __attribute__ ((constructor)) init(void);
+
+void init(void)
+{
+       ulogd_register_plugin(&nfacct_plugin);
+}
index c0c8559b44b63399dd024841dd1f0a0c423e086f..71e825577e4e500e4f58c29e68c04e933797add4 100644 (file)
@@ -49,6 +49,7 @@ plugin="@pkglibexecdir@/ulogd_output_GPRINT.so"
 #plugin="@pkglibexecdir@/ulogd_output_MYSQL.so"
 #plugin="@pkglibexecdir@/ulogd_output_DBI.so"
 plugin="@pkglibexecdir@/ulogd_raw2packet_BASE.so"
+plugin="@pkglibexecdir@/ulogd_inpflow_NFACCT.so"
 
 # this is a stack for logging packet send by system via LOGEMU
 #stack=log1:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU
@@ -107,6 +108,9 @@ plugin="@pkglibexecdir@/ulogd_raw2packet_BASE.so"
 # this is a stack for flow-based logging in NACCT compatible format
 #stack=ct1:NFCT,ip2str1:IP2STR,nacct1:NACCT
 
+# this is a stack for accounting-based logging via GPRINT
+#stack=acct1:NFACCT,gp1:GPRINT
+
 [ct1]
 #netlink_socket_buffer_size=217088
 #netlink_socket_buffer_maxsize=1085440
@@ -250,3 +254,6 @@ sync = 1
 
 [mark1]
 mark = 1
+
+[acct1]
+pollinterval = 2