From 1cfe3cf24db29bd9274c2e59587cc0960e9db47c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 16 Oct 2011 17:50:55 +0200 Subject: intial import of libnetfilter_acct --- Make_global.am | 24 ++++ Makefile.am | 11 ++ configure.ac | 33 ++++++ examples/Makefile.am | 9 ++ examples/nfacct-add.c | 53 +++++++++ examples/nfacct-get.c | 48 ++++++++ include/Makefile.am | 1 + include/libnetfilter_acct/libnetfilter_acct.h | 19 ++++ include/linux/netfilter/Makefile.am | 1 + include/linux/netfilter/nfnetlink_acct.h | 35 ++++++ libnetfilter_acct.pc.in | 15 +++ m4/.gitignore | 2 + m4/gcc4_visibility.m4 | 21 ++++ src/Makefile.am | 8 ++ src/internal.h | 12 ++ src/libnetfilter_acct.c | 154 ++++++++++++++++++++++++++ src/libnetfilter_acct.map | 15 +++ 17 files changed, 461 insertions(+) create mode 100644 Make_global.am create mode 100644 Makefile.am create mode 100644 configure.ac create mode 100644 examples/Makefile.am create mode 100644 examples/nfacct-add.c create mode 100644 examples/nfacct-get.c create mode 100644 include/Makefile.am create mode 100644 include/libnetfilter_acct/libnetfilter_acct.h create mode 100644 include/linux/netfilter/Makefile.am create mode 100644 include/linux/netfilter/nfnetlink_acct.h create mode 100644 libnetfilter_acct.pc.in create mode 100644 m4/.gitignore create mode 100644 m4/gcc4_visibility.m4 create mode 100644 src/Makefile.am create mode 100644 src/internal.h create mode 100644 src/libnetfilter_acct.c create mode 100644 src/libnetfilter_acct.map 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. +# +# +# 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. +# +# +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 +#include +#include +#include + +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 +#include +#include +#include + +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 +#include + +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 + +/* 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 + * (C) 2011 by Intra2net AG + * + * 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 +#include +#include +#include + +#include + +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; -- cgit v1.2.3