summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2011-10-16 17:50:55 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2011-10-16 21:28:13 +0200
commit1cfe3cf24db29bd9274c2e59587cc0960e9db47c (patch)
tree4e71628daab46e7197d15960cbfd7618a5976db2
intial import of libnetfilter_acct
-rw-r--r--Make_global.am24
-rw-r--r--Makefile.am11
-rw-r--r--configure.ac33
-rw-r--r--examples/Makefile.am9
-rw-r--r--examples/nfacct-add.c53
-rw-r--r--examples/nfacct-get.c48
-rw-r--r--include/Makefile.am1
-rw-r--r--include/libnetfilter_acct/libnetfilter_acct.h19
-rw-r--r--include/linux/netfilter/Makefile.am1
-rw-r--r--include/linux/netfilter/nfnetlink_acct.h35
-rw-r--r--libnetfilter_acct.pc.in15
-rw-r--r--m4/.gitignore2
-rw-r--r--m4/gcc4_visibility.m421
-rw-r--r--src/Makefile.am8
-rw-r--r--src/internal.h12
-rw-r--r--src/libnetfilter_acct.c154
-rw-r--r--src/libnetfilter_acct.map15
17 files changed, 461 insertions, 0 deletions
diff --git a/Make_global.am b/Make_global.am
new file mode 100644
index 0000000..caab49a
--- /dev/null
+++ b/Make_global.am
@@ -0,0 +1,24 @@
+# This is _NOT_ the library release version, it's an API version.
+# Extracted from Chapter 6 "Library interface versions" of the libtool docs.
+#
+# <snippet>
+# Here are a set of rules to help you update your library version information:
+#
+# 1. Start with version information of `0:0:0' for each libtool library.
+# 2. Update the version information only immediately before a public release
+# of your software. More frequent updates are unnecessary, and only guarantee
+# that the current interface number gets larger faster.
+# 3. If the library source code has changed at all since the last update,
+# then increment revision (`c:r:a' becomes `c:r+1:a').
+# 4. If any interfaces have been added, removed, or changed since the last
+# update, increment current, and set revision to 0.
+# 5. If any interfaces have been added since the last public release, then
+# increment age.
+# 6. If any interfaces have been removed since the last public release, then
+# set age to 0.
+# </snippet>
+#
+LIBVERSION=0:0:0
+
+AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include
+AM_CFLAGS = ${regular_CFLAGS} ${GCC_FVISIBILITY_HIDDEN}
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..b3e4aea
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,11 @@
+include $(top_srcdir)/Make_global.am
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = src include examples
+DIST_SUBDIRS = src include examples
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libnetfilter_acct.pc
+
+${pkgconfig_DATA}: ${top_builddir}/config.status
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..0f8da1f
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,33 @@
+dnl Process this file with autoconf to create configure.
+
+AC_INIT([libnetfilter_acct], [1.0.0])
+AC_CANONICAL_HOST
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([foreign dist-bzip2 1.6 subdir-objects])
+
+dnl kernel style compile messages
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+dnl Dependencies
+PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.1])
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_EXEEXT
+AC_DISABLE_STATIC
+LT_INIT
+CHECK_GCC_FVISIBILITY
+case "$host" in
+*-*-linux*) ;;
+*) AC_MSG_ERROR([Linux only, dude!]);;
+esac
+
+regular_CPPFLAGS="-D_FILE_OFFSET_BITS=64 -D_REENTRANT"
+regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
+ -Wmissing-prototypes -Wshadow -Wstrict-prototypes \
+ -Wformat=2 -pipe"
+AC_SUBST([regular_CPPFLAGS])
+AC_SUBST([regular_CFLAGS])
+AC_CONFIG_FILES([Makefile src/Makefile include/Makefile include/libnetfilter_acct/Makefile include/linux/Makefile include/linux/netfilter/Makefile examples/Makefile libnetfilter_acct.pc])
+AC_OUTPUT
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..07387f0
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/Make_global.am
+
+check_PROGRAMS = nfacct-get nfacct-add
+
+nfacct_add_SOURCES = nfacct-add.c
+nfacct_add_LDADD = ../src/libnetfilter_acct.la ${LIBMNL_LIBS}
+
+nfacct_get_SOURCES = nfacct-get.c
+nfacct_get_LDADD = ../src/libnetfilter_acct.la ${LIBMNL_LIBS}
diff --git a/examples/nfacct-add.c b/examples/nfacct-add.c
new file mode 100644
index 0000000..df3175e
--- /dev/null
+++ b/examples/nfacct-add.c
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include <time.h>
+#include <libmnl/libmnl.h>
+#include <libnetfilter_acct/libnetfilter_acct.h>
+
+int main(void)
+{
+ struct mnl_socket *nl;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t portid, seq;
+ struct nfacct nfacct = {
+ .name = "example",
+ .pkts = 10,
+ .bytes = 10,
+ };
+ int ret;
+
+ nlh = nfacct_add(buf, &nfacct);
+ seq = nlh->nlmsg_seq = time(NULL);
+
+ nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (nl == NULL) {
+ perror("mnl_socket_open");
+ exit(EXIT_FAILURE);
+ }
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ perror("mnl_socket_bind");
+ exit(EXIT_FAILURE);
+ }
+ portid = mnl_socket_get_portid(nl);
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_send");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, seq, portid, nfacct_list_cb, NULL);
+ if (ret <= 0)
+ break;
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ }
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+ mnl_socket_close(nl);
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/nfacct-get.c b/examples/nfacct-get.c
new file mode 100644
index 0000000..8ded1f4
--- /dev/null
+++ b/examples/nfacct-get.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include <time.h>
+#include <libmnl/libmnl.h>
+#include <libnetfilter_acct/libnetfilter_acct.h>
+
+int main(void)
+{
+ struct mnl_socket *nl;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t portid, seq;
+ int ret;
+
+ nlh = nfacct_list(buf);
+ seq = nlh->nlmsg_seq = time(NULL);
+
+ nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (nl == NULL) {
+ perror("mnl_socket_open");
+ exit(EXIT_FAILURE);
+ }
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ perror("mnl_socket_bind");
+ exit(EXIT_FAILURE);
+ }
+ portid = mnl_socket_get_portid(nl);
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_send");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, seq, portid, nfacct_list_cb, NULL);
+ if (ret <= 0)
+ break;
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ }
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+ mnl_socket_close(nl);
+
+ return EXIT_SUCCESS;
+}
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..9760a52
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libnetfilter_acct linux
diff --git a/include/libnetfilter_acct/libnetfilter_acct.h b/include/libnetfilter_acct/libnetfilter_acct.h
new file mode 100644
index 0000000..5a162b3
--- /dev/null
+++ b/include/libnetfilter_acct/libnetfilter_acct.h
@@ -0,0 +1,19 @@
+#ifndef _LIBNETFILTER_ACCT_H_
+#define _LIBNETFILTER_ACCT_H_
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_acct.h>
+
+struct nfacct {
+ char name[NFACCT_NAME_MAX];
+ uint64_t pkts;
+ uint64_t bytes;
+};
+
+struct nlmsghdr *nfacct_add(char *buf, struct nfacct *nfacct);
+struct nlmsghdr *nfacct_list(char *buf);
+int nfacct_list_cb(const struct nlmsghdr *nlh, void *data);
+struct nlmsghdr *nfacct_flush(char *buf);
+struct nlmsghdr *nfacct_delete(char *buf, const char *filter_name);
+
+#endif
diff --git a/include/linux/netfilter/Makefile.am b/include/linux/netfilter/Makefile.am
new file mode 100644
index 0000000..05c1924
--- /dev/null
+++ b/include/linux/netfilter/Makefile.am
@@ -0,0 +1 @@
+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
index 0000000..99c68eb
--- /dev/null
+++ b/include/linux/netfilter/nfnetlink_acct.h
@@ -0,0 +1,35 @@
+#ifndef _NFNL_ACCT_H_
+#define _NFNL_ACCT_H_
+#include <linux/netfilter/nfnetlink.h>
+
+/* FIXME: tweak to get it working with external headers. */
+#define NFNL_SUBSYS_ACCT NFNL_SUBSYS_OSF
+
+#define NFACCT_NAME_MAX 64
+
+enum nfnl_acct_msg_types {
+ NFNL_MSG_ACCT_NEW,
+ NFNL_MSG_ACCT_GET,
+ NFNL_MSG_ACCT_DEL,
+ NFNL_MSG_ACCT_MAX
+};
+
+enum nfnl_acct_type {
+ NFACCT_UNSPEC,
+ NFACCT_NAME,
+ NFACCT_PKTS,
+ NFACCT_BYTES,
+ __NFACCT_MAX
+};
+#define NFACCT_MAX (__NFACCT_MAX - 1)
+
+#ifdef __KERNEL__
+
+struct nf_acct;
+
+extern struct nf_acct *nfnl_acct_find_get(char *filter_name);
+extern void nfnl_acct_put(struct nf_acct *acct);
+
+#endif /* __KERNEL__ */
+
+#endif /* _NFNL_ACCT_H */
diff --git a/libnetfilter_acct.pc.in b/libnetfilter_acct.pc.in
new file mode 100644
index 0000000..54e37a7
--- /dev/null
+++ b/libnetfilter_acct.pc.in
@@ -0,0 +1,15 @@
+# libnetfilter_acct pkg-config file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libnetfilter_acct
+Description: Netfilter extended accounting infrastructure library
+URL: http://netfilter.org/projects/libnetfilter_acct/
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -lnetfilter_acct
+Cflags: -I${includedir}
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644
index 0000000..64d9bbc
--- /dev/null
+++ b/m4/.gitignore
@@ -0,0 +1,2 @@
+/libtool.m4
+/lt*.m4
diff --git a/m4/gcc4_visibility.m4 b/m4/gcc4_visibility.m4
new file mode 100644
index 0000000..84959f3
--- /dev/null
+++ b/m4/gcc4_visibility.m4
@@ -0,0 +1,21 @@
+
+# GCC 4.x -fvisibility=hidden
+
+AC_DEFUN([CHECK_GCC_FVISIBILITY], [
+ AC_LANG_PUSH([C])
+ saved_CFLAGS="$CFLAGS"
+ CFLAGS="$saved_CFLAGS -fvisibility=hidden"
+ AC_CACHE_CHECK([whether compiler accepts -fvisibility=hidden],
+ [ac_cv_fvisibility_hidden], AC_COMPILE_IFELSE(
+ AC_LANG_PROGRAM([], []),
+ [ac_cv_fvisibility_hidden=yes],
+ [ac_cv_fvisibility_hidden=no]
+ ))
+ if test "$ac_cv_fvisibility_hidden" = "yes"; then
+ AC_DEFINE([HAVE_VISIBILITY_HIDDEN], [1],
+ [True if compiler supports -fvisibility=hidden])
+ AC_SUBST([GCC_FVISIBILITY_HIDDEN], [-fvisibility=hidden])
+ fi
+ CFLAGS="$saved_CFLAGS"
+ AC_LANG_POP([C])
+])
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..bbcfe51
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,8 @@
+include $(top_srcdir)/Make_global.am
+lib_LTLIBRARIES = libnetfilter_acct.la
+
+libnetfilter_acct_la_LIBADD = ${LIBMNL_LIBS}
+libnetfilter_acct_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnetfilter_acct.map -version-info $(LIBVERSION)
+libnetfilter_acct_la_SOURCES = libnetfilter_acct.c \
+ libnetfilter_acct.map \
+ internal.h
diff --git a/src/internal.h b/src/internal.h
new file mode 100644
index 0000000..3a88d1a
--- /dev/null
+++ b/src/internal.h
@@ -0,0 +1,12 @@
+#ifndef INTERNAL_H
+#define INTERNAL_H 1
+
+#include "config.h"
+#ifdef HAVE_VISIBILITY_HIDDEN
+# define __visible __attribute__((visibility("default")))
+# define EXPORT_SYMBOL(x) typeof(x) (x) __visible
+#else
+# define EXPORT_SYMBOL
+#endif
+
+#endif
diff --git a/src/libnetfilter_acct.c b/src/libnetfilter_acct.c
new file mode 100644
index 0000000..5311430
--- /dev/null
+++ b/src/libnetfilter_acct.c
@@ -0,0 +1,154 @@
+/*
+ * (C) 2011 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2011 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 Lesser GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include "internal.h"
+
+#include <time.h>
+#include <libmnl/libmnl.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_acct.h>
+
+#include <libnetfilter_acct/libnetfilter_acct.h>
+
+struct nlmsghdr *nfacct_add(char *buf, struct nfacct *nfacct)
+{
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_NEW;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
+ nlh->nlmsg_seq = time(NULL);
+
+ nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+ nfh->nfgen_family = AF_UNSPEC;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = 0;
+
+ mnl_attr_put_strz(nlh, NFACCT_NAME, nfacct->name);
+ mnl_attr_put_u64(nlh, NFACCT_PKTS, nfacct->pkts);
+ mnl_attr_put_u64(nlh, NFACCT_PKTS, nfacct->bytes);
+
+ return nlh;
+}
+EXPORT_SYMBOL(nfacct_add);
+
+struct nlmsghdr *nfacct_list(char *buf)
+{
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_GET;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ nlh->nlmsg_seq = time(NULL);
+
+ nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+ nfh->nfgen_family = AF_UNSPEC;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = 0;
+
+ return nlh;
+}
+EXPORT_SYMBOL(nfacct_list);
+
+static int nfacct_list_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, NFACCT_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFACCT_NAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case NFACCT_PKTS:
+ if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ case NFACCT_BYTES:
+ if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+int nfacct_list_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nlattr *tb[NFACCT_MAX+1] = {};
+ struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+ bool *full = data;
+
+ mnl_attr_parse(nlh, sizeof(*nfg), nfacct_list_attr_cb, tb);
+ if (!tb[NFACCT_NAME] && !tb[NFACCT_PKTS] && !tb[NFACCT_BYTES])
+ return MNL_CB_OK;
+
+ if (*full) {
+ printf("%s = { pkts = %.12llu,\tbytes = %.12llu }; \n",
+ mnl_attr_get_str(tb[NFACCT_NAME]),
+ mnl_attr_get_u64(tb[NFACCT_PKTS]),
+ mnl_attr_get_u64(tb[NFACCT_BYTES]));
+ } else {
+ printf("%s\n", mnl_attr_get_str(tb[NFACCT_NAME]));
+ }
+
+ return MNL_CB_OK;
+}
+EXPORT_SYMBOL(nfacct_list_cb);
+
+struct nlmsghdr *nfacct_flush(char *buf)
+{
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_DEL;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
+ nlh->nlmsg_seq = time(NULL);
+
+ nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+ nfh->nfgen_family = AF_UNSPEC;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = 0;
+
+ return nlh;
+}
+EXPORT_SYMBOL(nfacct_flush);
+
+struct nlmsghdr *nfacct_delete(char *buf, const char *filter_name)
+{
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfh;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_DEL;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
+ nlh->nlmsg_seq = time(NULL);
+
+ nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+ nfh->nfgen_family = AF_UNSPEC;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = 0;
+
+ mnl_attr_put_strz(nlh, NFACCT_NAME, filter_name);
+
+ return nlh;
+}
+EXPORT_SYMBOL(nfacct_delete);
diff --git a/src/libnetfilter_acct.map b/src/libnetfilter_acct.map
new file mode 100644
index 0000000..f5c3172
--- /dev/null
+++ b/src/libnetfilter_acct.map
@@ -0,0 +1,15 @@
+LIBNETFILTER_ACCT_1.0 {
+global:
+ nfacct_add;
+ nfacct_list;
+ nfacct_list_cb;
+ nfacct_flush;
+ nfacct_delete;
+ nfacct_list;
+
+local: *;
+};
+
+#LIBNETFILTER_ACCT_1.1 {
+# _my_new_func;
+#} LIBNETFILTER_ACCT_1.0;