diff --git a/net/ulogd/Makefile b/net/ulogd/Makefile index 188091a1e6..26a6b9297b 100644 --- a/net/ulogd/Makefile +++ b/net/ulogd/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ulogd -PKG_VERSION:=2.0.7 -PKG_RELEASE:=6 +PKG_VERSION:=2.0.8 +PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:=https://netfilter.org/projects/ulogd/files/ \ ftp://ftp.netfilter.org/pub/ulogd/ -PKG_HASH:=990a05494d9c16029ba0a83f3b7294fc05c756546b8d60d1c1572dc25249a92b +PKG_HASH:=4ead6c3970c3f57fa1e89fe2d7cc483ba6fe2bd1b08701521e0b3afd667df291 PKG_MAINTAINER:=Alexandru Ardelean PKG_LICENSE:=GPL-2.0-only @@ -41,7 +41,7 @@ endef define Package/ulogd $(call Package/ulogd/Default) - DEPENDS:=+libmnl +libnfnetlink +libpthread + DEPENDS:=+libmnl +libnfnetlink +libpthread +libnetfilter-conntrack TITLE:=Netfilter userspace logging daemon MENU:=1 endef diff --git a/net/ulogd/patches/010-json-remote.patch b/net/ulogd/patches/010-json-remote.patch deleted file mode 100644 index e217a11d84..0000000000 --- a/net/ulogd/patches/010-json-remote.patch +++ /dev/null @@ -1,434 +0,0 @@ -From 9d9ea2cd70a369a7f665a322e6c53631e01a2570 Mon Sep 17 00:00:00 2001 -From: Andreas Jaggi -Date: Wed, 30 May 2018 22:15:36 +0200 -Subject: ulogd: json: send messages to a remote host / unix socket - -Extend the JSON output plugin so that the generated JSON stream can be -sent to a remote host via TCP/UDP or to a local unix socket. - -Signed-off-by: Andreas Jaggi -Signed-off-by: Pablo Neira Ayuso ---- - output/ulogd_output_JSON.c | 291 +++++++++++++++++++++++++++++++++++++++++---- - ulogd.conf.in | 11 ++ - 2 files changed, 281 insertions(+), 21 deletions(-) - ---- a/output/ulogd_output_JSON.c -+++ b/output/ulogd_output_JSON.c -@@ -20,10 +20,15 @@ - - #include - #include -+#include - #include - #include - #include - #include -+#include -+#include -+#include -+#include - #include - #include - #include -@@ -36,6 +41,10 @@ - #define ULOGD_JSON_DEFAULT_DEVICE "Netfilter" - #endif - -+#define host_ce(x) (x->ces[JSON_CONF_HOST]) -+#define port_ce(x) (x->ces[JSON_CONF_PORT]) -+#define mode_ce(x) (x->ces[JSON_CONF_MODE]) -+#define file_ce(x) (x->ces[JSON_CONF_FILENAME]) - #define unlikely(x) __builtin_expect((x),0) - - struct json_priv { -@@ -44,6 +53,15 @@ struct json_priv { - int usec_idx; - long cached_gmtoff; - char cached_tz[6]; /* eg +0200 */ -+ int mode; -+ int sock; -+}; -+ -+enum json_mode { -+ JSON_MODE_FILE = 0, -+ JSON_MODE_TCP, -+ JSON_MODE_UDP, -+ JSON_MODE_UNIX - }; - - enum json_conf { -@@ -53,6 +71,9 @@ enum json_conf { - JSON_CONF_EVENTV1, - JSON_CONF_DEVICE, - JSON_CONF_BOOLEAN_LABEL, -+ JSON_CONF_MODE, -+ JSON_CONF_HOST, -+ JSON_CONF_PORT, - JSON_CONF_MAX - }; - -@@ -95,15 +116,167 @@ static struct config_keyset json_kset = - .options = CONFIG_OPT_NONE, - .u = { .value = 0 }, - }, -+ [JSON_CONF_MODE] = { -+ .key = "mode", -+ .type = CONFIG_TYPE_STRING, -+ .options = CONFIG_OPT_NONE, -+ .u = { .string = "file" }, -+ }, -+ [JSON_CONF_HOST] = { -+ .key = "host", -+ .type = CONFIG_TYPE_STRING, -+ .options = CONFIG_OPT_NONE, -+ .u = { .string = "127.0.0.1" }, -+ }, -+ [JSON_CONF_PORT] = { -+ .key = "port", -+ .type = CONFIG_TYPE_STRING, -+ .options = CONFIG_OPT_NONE, -+ .u = { .string = "12345" }, -+ }, - }, - }; - -+static void close_socket(struct json_priv *op) { -+ if (op->sock != -1) { -+ close(op->sock); -+ op->sock = -1; -+ } -+} -+ -+static int _connect_socket_unix(struct ulogd_pluginstance *pi) -+{ -+ struct json_priv *op = (struct json_priv *) &pi->private; -+ struct sockaddr_un u_addr; -+ int sfd; -+ -+ close_socket(op); -+ -+ ulogd_log(ULOGD_DEBUG, "connecting to unix:%s\n", -+ file_ce(pi->config_kset).u.string); -+ -+ sfd = socket(AF_UNIX, SOCK_STREAM, 0); -+ if (sfd == -1) { -+ return -1; -+ } -+ u_addr.sun_family = AF_UNIX; -+ strncpy(u_addr.sun_path, file_ce(pi->config_kset).u.string, -+ sizeof(u_addr.sun_path) - 1); -+ if (connect(sfd, (struct sockaddr *) &u_addr, sizeof(struct sockaddr_un)) == -1) { -+ close(sfd); -+ return -1; -+ } -+ -+ op->sock = sfd; -+ -+ return 0; -+} -+ -+static int _connect_socket_net(struct ulogd_pluginstance *pi) -+{ -+ struct json_priv *op = (struct json_priv *) &pi->private; -+ struct addrinfo hints; -+ struct addrinfo *result, *rp; -+ int sfd, s; -+ -+ close_socket(op); -+ -+ ulogd_log(ULOGD_DEBUG, "connecting to %s:%s\n", -+ host_ce(pi->config_kset).u.string, -+ port_ce(pi->config_kset).u.string); -+ -+ memset(&hints, 0, sizeof(struct addrinfo)); -+ hints.ai_family = AF_UNSPEC; -+ hints.ai_socktype = op->mode == JSON_MODE_UDP ? SOCK_DGRAM : SOCK_STREAM; -+ hints.ai_protocol = 0; -+ hints.ai_flags = 0; -+ -+ s = getaddrinfo(host_ce(pi->config_kset).u.string, -+ port_ce(pi->config_kset).u.string, &hints, &result); -+ if (s != 0) { -+ ulogd_log(ULOGD_ERROR, "getaddrinfo: %s\n", gai_strerror(s)); -+ return -1; -+ } -+ -+ for (rp = result; rp != NULL; rp = rp->ai_next) { -+ int on = 1; -+ -+ sfd = socket(rp->ai_family, rp->ai_socktype, -+ rp->ai_protocol); -+ if (sfd == -1) -+ continue; -+ -+ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, -+ (char *) &on, sizeof(on)); -+ -+ if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) -+ break; -+ -+ close(sfd); -+ } -+ -+ freeaddrinfo(result); -+ -+ if (rp == NULL) { -+ return -1; -+ } -+ -+ op->sock = sfd; -+ -+ return 0; -+} -+ -+static int _connect_socket(struct ulogd_pluginstance *pi) -+{ -+ struct json_priv *op = (struct json_priv *) &pi->private; -+ -+ if (op->mode == JSON_MODE_UNIX) -+ return _connect_socket_unix(pi); -+ else -+ return _connect_socket_net(pi); -+} -+ -+static int json_interp_socket(struct ulogd_pluginstance *upi, char *buf, int buflen) -+{ -+ struct json_priv *opi = (struct json_priv *) &upi->private; -+ int ret = 0; -+ -+ if (opi->sock != -1) -+ ret = send(opi->sock, buf, buflen, MSG_NOSIGNAL); -+ free(buf); -+ if (ret != buflen) { -+ ulogd_log(ULOGD_ERROR, "Failure sending message: %s\n", -+ strerror(errno)); -+ if (ret == -1 || opi->sock == -1) -+ return _connect_socket(upi); -+ else -+ return ULOGD_IRET_ERR; -+ } -+ -+ return ULOGD_IRET_OK; -+} -+ -+static int json_interp_file(struct ulogd_pluginstance *upi, char *buf) -+{ -+ struct json_priv *opi = (struct json_priv *) &upi->private; -+ -+ fprintf(opi->of, "%s", buf); -+ free(buf); -+ -+ if (upi->config_kset->ces[JSON_CONF_SYNC].u.value != 0) -+ fflush(opi->of); -+ -+ return ULOGD_IRET_OK; -+} -+ - #define MAX_LOCAL_TIME_STRING 38 - - static int json_interp(struct ulogd_pluginstance *upi) - { - struct json_priv *opi = (struct json_priv *) &upi->private; - unsigned int i; -+ char *buf; -+ int buflen; - json_t *msg; - - msg = json_object(); -@@ -218,34 +391,65 @@ static int json_interp(struct ulogd_plug - } - } - -- json_dumpf(msg, opi->of, 0); -- fprintf(opi->of, "\n"); - -+ buf = json_dumps(msg, 0); - json_decref(msg); -+ if (buf == NULL) { -+ ulogd_log(ULOGD_ERROR, "Could not create message\n"); -+ return ULOGD_IRET_ERR; -+ } -+ buflen = strlen(buf); -+ buf = realloc(buf, sizeof(char)*(buflen+2)); -+ if (buf == NULL) { -+ ulogd_log(ULOGD_ERROR, "Could not create message\n"); -+ return ULOGD_IRET_ERR; -+ } -+ strncat(buf, "\n", 1); -+ buflen++; - -- if (upi->config_kset->ces[JSON_CONF_SYNC].u.value != 0) -- fflush(opi->of); -+ if (opi->mode == JSON_MODE_FILE) -+ return json_interp_file(upi, buf); -+ else -+ return json_interp_socket(upi, buf, buflen); -+} - -- return ULOGD_IRET_OK; -+static void reopen_file(struct ulogd_pluginstance *upi) -+{ -+ struct json_priv *oi = (struct json_priv *) &upi->private; -+ FILE *old = oi->of; -+ -+ 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); -+ } -+} -+ -+static void reopen_socket(struct ulogd_pluginstance *upi) -+{ -+ ulogd_log(ULOGD_NOTICE, "JSON: reopening socket\n"); -+ if (_connect_socket(upi) < 0) { -+ ulogd_log(ULOGD_ERROR, "can't open JSON " -+ "socket: %s\n", -+ strerror(errno)); -+ } - } - - 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); -- } -+ if (oi->mode == JSON_MODE_FILE) -+ reopen_file(upi); -+ else -+ reopen_socket(upi); - break; - default: - break; -@@ -255,6 +459,8 @@ static void sighup_handler_print(struct - static int json_configure(struct ulogd_pluginstance *upi, - struct ulogd_pluginstance_stack *stack) - { -+ struct json_priv *op = (struct json_priv *) &upi->private; -+ char *mode_str = mode_ce(upi->config_kset).u.string; - int ret; - - ret = ulogd_wildcard_inputkeys(upi); -@@ -265,13 +471,25 @@ static int json_configure(struct ulogd_p - if (ret < 0) - return ret; - -+ if (!strcasecmp(mode_str, "udp")) { -+ op->mode = JSON_MODE_UDP; -+ } else if (!strcasecmp(mode_str, "tcp")) { -+ op->mode = JSON_MODE_TCP; -+ } else if (!strcasecmp(mode_str, "unix")) { -+ op->mode = JSON_MODE_UNIX; -+ } else if (!strcasecmp(mode_str, "file")) { -+ op->mode = JSON_MODE_FILE; -+ } else { -+ ulogd_log(ULOGD_ERROR, "unknown mode '%s'\n", mode_str); -+ return -EINVAL; -+ } -+ - return 0; - } - --static int json_init(struct ulogd_pluginstance *upi) -+static int json_init_file(struct ulogd_pluginstance *upi) - { - struct json_priv *op = (struct json_priv *) &upi->private; -- unsigned int i; - - op->of = fopen(upi->config_kset->ces[0].u.string, "a"); - if (!op->of) { -@@ -280,6 +498,27 @@ static int json_init(struct ulogd_plugin - return -1; - } - -+ return 0; -+} -+ -+static int json_init_socket(struct ulogd_pluginstance *upi) -+{ -+ struct json_priv *op = (struct json_priv *) &upi->private; -+ -+ if (host_ce(upi->config_kset).u.string == NULL) -+ return -1; -+ if (port_ce(upi->config_kset).u.string == NULL) -+ return -1; -+ -+ op->sock = -1; -+ return _connect_socket(upi); -+} -+ -+static int json_init(struct ulogd_pluginstance *upi) -+{ -+ struct json_priv *op = (struct json_priv *) &upi->private; -+ unsigned int i; -+ - /* search for time */ - op->sec_idx = -1; - op->usec_idx = -1; -@@ -293,15 +532,25 @@ static int json_init(struct ulogd_plugin - - *op->cached_tz = '\0'; - -- return 0; -+ if (op->mode == JSON_MODE_FILE) -+ return json_init_file(upi); -+ else -+ return json_init_socket(upi); -+} -+ -+static void close_file(FILE *of) { -+ if (of != stdout) -+ fclose(of); - } - - static int json_fini(struct ulogd_pluginstance *pi) - { - struct json_priv *op = (struct json_priv *) &pi->private; - -- if (op->of != stdout) -- fclose(op->of); -+ if (op->mode == JSON_MODE_FILE) -+ close_file(op->of); -+ else -+ close_socket(op); - - return 0; - } ---- a/ulogd.conf.in -+++ b/ulogd.conf.in -@@ -213,6 +213,17 @@ sync=1 - # Uncomment the following line to use JSON v1 event format that - # can provide better compatility with some JSON file reader. - #eventv1=1 -+# Uncomment the following lines to send the JSON logs to a remote host via UDP -+#mode="udp" -+#host="192.0.2.10" -+#port="10210" -+# Uncomment the following lines to send the JSON logs to a remote host via TCP -+#mode="tcp" -+#host="192.0.2.10" -+#port="10210" -+# Uncomment the following lines to send the JSON logs to a local unix socket -+#mode="unix" -+#file="/var/run/ulogd.socket" - - [pcap1] - #default file is /var/log/ulogd.pcap diff --git a/net/ulogd/patches/020-fix-musl.patch b/net/ulogd/patches/020-fix-musl.patch deleted file mode 100644 index afbc64cf47..0000000000 --- a/net/ulogd/patches/020-fix-musl.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 675e762091380590f78ff07a94a25caa459b786b Mon Sep 17 00:00:00 2001 -From: Cameron Norman -Date: Sat, 27 Oct 2018 13:05:45 -0700 -Subject: ulogd: fix build with musl libc - -The attached patch fixes building ulogd2 with musl libc. It is being -used on Void Linux right now. - -Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1278 -Signed-off-by: Pablo Neira Ayuso ---- - src/ulogd.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/src/ulogd.c -+++ b/src/ulogd.c -@@ -65,6 +65,7 @@ - #include - #include - #include -+#include - #include - #include - #ifdef DEBUG diff --git a/net/ulogd/patches/030-ipfix-add.patch b/net/ulogd/patches/030-ipfix-add.patch deleted file mode 100644 index 13d1472c92..0000000000 --- a/net/ulogd/patches/030-ipfix-add.patch +++ /dev/null @@ -1,858 +0,0 @@ -From 4f639231c83b09ea004c03e95c702b7750bf9930 Mon Sep 17 00:00:00 2001 -From: Ander Juaristi -Date: Fri, 26 Apr 2019 09:58:06 +0200 -Subject: IPFIX: Add IPFIX output plugin - -This patch adds an IPFIX output plugin to ulogd2. It generates NetFlow/IPFIX -traces and sends them to a remote server (collector) via TCP or UDP. - -Based on original work by Holger Eitzenberger . - -How to test this ----------------- - -I am currently testing this with the NFCT input and Wireshark. - -Place the following in ulogd.conf: - - # this will print all flows on screen - loglevel=1 - - # load NFCT and IPFIX plugins - plugin="/lib/ulogd/ulogd_inpflow_NFCT.so" - plugin="/lib/ulogd/ulogd_output_IPFIX.so" - - stack=ct1:NFCT,ipfix1:IPFIX - - [ct1] - netlink_socket_buffer_size=217088 - netlink_socket_buffer_maxsize=1085440 - accept_proto_filter=tcp,sctp - - [ipfix1] - oid=1 - host="127.0.0.1" - #port=4739 - #send_template="once" - -I am currently testing it by launching a plain NetCat listener on port -4739 (the default for IPFIX) and then running Wireshark and see that it -dissects the IPFIX/NetFlow traffic correctly (obviously this relies on -the Wireshark NetFlow dissector being correct). - -First: - - nc -vvvv -l 127.0.0.1 4739 - -Then: - - sudo ulogd -vc ulogd.conf - -Signed-off-by: Ander Juaristi -Signed-off-by: Pablo Neira Ayuso ---- - configure.ac | 2 +- - include/ulogd/ulogd.h | 5 + - input/flow/ulogd_inpflow_IPFIX.c | 2 - - output/Makefile.am | 2 +- - output/ipfix/Makefile.am | 7 + - output/ipfix/ipfix.c | 141 ++++++++++ - output/ipfix/ipfix.h | 89 +++++++ - output/ipfix/ulogd_output_IPFIX.c | 503 +++++++++++++++++++++++++++++++++++ - output/ulogd_output_IPFIX.c | 546 -------------------------------------- - 9 files changed, 747 insertions(+), 550 deletions(-) - delete mode 100644 input/flow/ulogd_inpflow_IPFIX.c - create mode 100644 output/ipfix/Makefile.am - create mode 100644 output/ipfix/ipfix.c - create mode 100644 output/ipfix/ipfix.h - create mode 100644 output/ipfix/ulogd_output_IPFIX.c - delete mode 100644 output/ulogd_output_IPFIX.c - ---- a/configure.ac -+++ b/configure.ac -@@ -179,7 +179,7 @@ AC_CONFIG_FILES(include/Makefile include - 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 \ -+ output/dbi/Makefile output/ipfix/Makefile \ - src/Makefile Makefile Rules.make) - AC_OUTPUT - ---- a/include/ulogd/ulogd.h -+++ b/include/ulogd/ulogd.h -@@ -28,6 +28,11 @@ - - /* types without length */ - #define ULOGD_RET_NONE 0x0000 -+#define __packed __attribute__((packed)) -+#define __noreturn __attribute__((noreturn)) -+#define __cold __attribute__((cold)) -+ -+#define __packed __attribute__((packed)) - - #define ULOGD_RET_INT8 0x0001 - #define ULOGD_RET_INT16 0x0002 ---- a/output/Makefile.am -+++ b/output/Makefile.am -@@ -2,7 +2,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include ${ - ${LIBNETFILTER_CONNTRACK_CFLAGS} ${LIBNETFILTER_LOG_CFLAGS} - AM_CFLAGS = ${regular_CFLAGS} - --SUBDIRS= pcap mysql pgsql sqlite3 dbi -+SUBDIRS= pcap mysql pgsql sqlite3 dbi ipfix - - pkglib_LTLIBRARIES = ulogd_output_LOGEMU.la ulogd_output_SYSLOG.la \ - ulogd_output_OPRINT.la ulogd_output_GPRINT.la \ ---- /dev/null -+++ b/output/ipfix/Makefile.am -@@ -0,0 +1,7 @@ -+AM_CPPFLAGS = -I$(top_srcdir)/include -+AM_CFLAGS = $(regular_CFLAGS) -+ -+pkglib_LTLIBRARIES = ulogd_output_IPFIX.la -+ -+ulogd_output_IPFIX_la_SOURCES = ulogd_output_IPFIX.c ipfix.c -+ulogd_output_IPFIX_la_LDFLAGS = -avoid-version -module ---- /dev/null -+++ b/output/ipfix/ipfix.c -@@ -0,0 +1,141 @@ -+/* -+ * ipfix.c -+ * -+ * Holger Eitzenberger, 2009. -+ */ -+ -+/* These forward declarations are needed since ulogd.h doesn't like to be the first */ -+#include -+ -+#define __packed __attribute__((packed)) -+ -+#include "ipfix.h" -+ -+#include -+#include -+ -+struct ipfix_msg *ipfix_msg_alloc(size_t len, uint32_t oid) -+{ -+ struct ipfix_msg *msg; -+ struct ipfix_hdr *hdr; -+ -+ if (len < IPFIX_HDRLEN + IPFIX_SET_HDRLEN) -+ return NULL; -+ -+ msg = malloc(sizeof(struct ipfix_msg) + len); -+ memset(msg, 0, sizeof(struct ipfix_msg)); -+ msg->tail = msg->data + IPFIX_HDRLEN; -+ msg->end = msg->data + len; -+ -+ hdr = ipfix_msg_hdr(msg); -+ memset(hdr, 0, IPFIX_HDRLEN); -+ hdr->version = htons(IPFIX_VERSION); -+ hdr->oid = htonl(oid); -+ -+ return msg; -+} -+ -+void ipfix_msg_free(struct ipfix_msg *msg) -+{ -+ if (!msg) -+ return; -+ -+ if (msg->nrecs > 0) -+ ulogd_log(ULOGD_DEBUG, "%s: %d flows have been lost\n", __func__, -+ msg->nrecs); -+ -+ free(msg); -+} -+ -+struct ipfix_hdr *ipfix_msg_hdr(const struct ipfix_msg *msg) -+{ -+ return (struct ipfix_hdr *)msg->data; -+} -+ -+void *ipfix_msg_data(struct ipfix_msg *msg) -+{ -+ return msg->data; -+} -+ -+size_t ipfix_msg_len(const struct ipfix_msg *msg) -+{ -+ return msg->tail - msg->data; -+} -+ -+struct ipfix_set_hdr *ipfix_msg_add_set(struct ipfix_msg *msg, uint16_t sid) -+{ -+ struct ipfix_set_hdr *shdr; -+ -+ if (msg->end - msg->tail < (int) IPFIX_SET_HDRLEN) -+ return NULL; -+ -+ shdr = (struct ipfix_set_hdr *)msg->tail; -+ shdr->id = sid; -+ shdr->len = IPFIX_SET_HDRLEN; -+ msg->tail += IPFIX_SET_HDRLEN; -+ msg->last_set = shdr; -+ return shdr; -+} -+ -+struct ipfix_set_hdr *ipfix_msg_get_set(const struct ipfix_msg *msg) -+{ -+ return msg->last_set; -+} -+ -+/** -+ * Add data record to an IPFIX message. The data is accounted properly. -+ * -+ * @return pointer to data or %NULL if not that much space left. -+ */ -+void *ipfix_msg_add_data(struct ipfix_msg *msg, size_t len) -+{ -+ void *data; -+ -+ if (!msg->last_set) { -+ ulogd_log(ULOGD_FATAL, "msg->last_set is NULL\n"); -+ return NULL; -+ } -+ -+ if ((ssize_t) len > msg->end - msg->tail) -+ return NULL; -+ -+ data = msg->tail; -+ msg->tail += len; -+ msg->nrecs++; -+ msg->last_set->len += len; -+ -+ return data; -+} -+ -+/* check and dump message */ -+int ipfix_dump_msg(const struct ipfix_msg *msg) -+{ -+ const struct ipfix_hdr *hdr = ipfix_msg_hdr(msg); -+ const struct ipfix_set_hdr *shdr = (struct ipfix_set_hdr *) hdr->data; -+ -+ if (ntohs(hdr->len) < IPFIX_HDRLEN) { -+ ulogd_log(ULOGD_FATAL, "Invalid IPFIX message header length\n"); -+ return -1; -+ } -+ if (ipfix_msg_len(msg) != IPFIX_HDRLEN + ntohs(shdr->len)) { -+ ulogd_log(ULOGD_FATAL, "Invalid IPFIX message length\n"); -+ return -1; -+ } -+ -+ ulogd_log(ULOGD_DEBUG, "msg: ver=%#x len=%#x t=%#x seq=%#x oid=%d\n", -+ ntohs(hdr->version), ntohs(hdr->len), htonl(hdr->time), -+ ntohl(hdr->seqno), ntohl(hdr->oid)); -+ -+ return 0; -+} -+ -+/* template management */ -+size_t ipfix_rec_len(uint16_t sid) -+{ -+ if (sid != htons(VY_IPFIX_SID)) { -+ ulogd_log(ULOGD_FATAL, "Invalid SID\n"); -+ return 0; -+ } -+ -+ return sizeof(struct vy_ipfix_data); -+} ---- /dev/null -+++ b/output/ipfix/ipfix.h -@@ -0,0 +1,89 @@ -+/* -+ * ipfix.h -+ * -+ * Holger Eitzenberger , 2009. -+ */ -+#ifndef IPFIX_H -+#define IPFIX_H -+ -+#include -+#include -+ -+ -+struct ipfix_hdr { -+#define IPFIX_VERSION 0xa -+ uint16_t version; -+ uint16_t len; -+ uint32_t time; -+ uint32_t seqno; -+ uint32_t oid; /* Observation Domain ID */ -+ uint8_t data[]; -+} __packed; -+ -+#define IPFIX_HDRLEN sizeof(struct ipfix_hdr) -+ -+/* -+ * IDs 0-255 are reserved for Template Sets. IDs of Data Sets are > 255. -+ */ -+struct ipfix_templ_hdr { -+ uint16_t id; -+ uint16_t cnt; -+ uint8_t data[]; -+} __packed; -+ -+struct ipfix_set_hdr { -+#define IPFIX_SET_TEMPL 2 -+#define IPFIX_SET_OPT_TEMPL 3 -+ uint16_t id; -+ uint16_t len; -+ uint8_t data[]; -+} __packed; -+ -+#define IPFIX_SET_HDRLEN sizeof(struct ipfix_set_hdr) -+ -+struct ipfix_msg { -+ struct llist_head link; -+ uint8_t *tail; -+ uint8_t *end; -+ unsigned nrecs; -+ struct ipfix_set_hdr *last_set; -+ uint8_t data[]; -+}; -+ -+struct vy_ipfix_data { -+ struct in_addr saddr; -+ struct in_addr daddr; -+ uint16_t ifi_in; -+ uint16_t ifi_out; -+ uint32_t packets; -+ uint32_t bytes; -+ uint32_t start; /* Unix time */ -+ uint32_t end; /* Unix time */ -+ uint16_t sport; -+ uint16_t dport; -+ uint32_t aid; /* Application ID */ -+ uint8_t l4_proto; -+ uint8_t dscp; -+ uint16_t __padding; -+} __packed; -+ -+#define VY_IPFIX_SID 256 -+ -+#define VY_IPFIX_FLOWS 36 -+#define VY_IPFIX_PKT_LEN (IPFIX_HDRLEN + IPFIX_SET_HDRLEN \ -+ + VY_IPFIX_FLOWS * sizeof(struct vy_ipfix_data)) -+ -+/* template management */ -+size_t ipfix_rec_len(uint16_t); -+ -+/* message handling */ -+struct ipfix_msg *ipfix_msg_alloc(size_t, uint32_t); -+void ipfix_msg_free(struct ipfix_msg *); -+struct ipfix_hdr *ipfix_msg_hdr(const struct ipfix_msg *); -+size_t ipfix_msg_len(const struct ipfix_msg *); -+void *ipfix_msg_data(struct ipfix_msg *); -+struct ipfix_set_hdr *ipfix_msg_add_set(struct ipfix_msg *, uint16_t); -+void *ipfix_msg_add_data(struct ipfix_msg *, size_t); -+int ipfix_dump_msg(const struct ipfix_msg *); -+ -+#endif /* IPFIX_H */ ---- /dev/null -+++ b/output/ipfix/ulogd_output_IPFIX.c -@@ -0,0 +1,503 @@ -+/* -+ * ulogd_output_IPFIX.c -+ * -+ * ulogd IPFIX Exporter plugin. -+ * -+ * 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 -+ * -+ * Holger Eitzenberger Astaro AG 2009 -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ipfix.h" -+ -+#define DEFAULT_MTU 512 /* RFC 5101, 10.3.3 */ -+#define DEFAULT_PORT 4739 /* RFC 5101, 10.3.4 */ -+#define DEFAULT_SPORT 4740 -+ -+enum { -+ OID_CE = 0, -+ HOST_CE, -+ PORT_CE, -+ PROTO_CE, -+ MTU_CE, -+}; -+ -+#define oid_ce(x) (x->ces[OID_CE]) -+#define host_ce(x) (x->ces[HOST_CE]) -+#define port_ce(x) (x->ces[PORT_CE]) -+#define proto_ce(x) (x->ces[PROTO_CE]) -+#define mtu_ce(x) (x->ces[MTU_CE]) -+ -+static const struct config_keyset ipfix_kset = { -+ .num_ces = 5, -+ .ces = { -+ { -+ .key = "oid", -+ .type = CONFIG_TYPE_INT, -+ .u.value = 0 -+ }, -+ { -+ .key = "host", -+ .type = CONFIG_TYPE_STRING, -+ .u.string = "" -+ }, -+ { -+ .key = "port", -+ .type = CONFIG_TYPE_INT, -+ .u.value = DEFAULT_PORT -+ }, -+ { -+ .key = "proto", -+ .type = CONFIG_TYPE_STRING, -+ .u.string = "tcp" -+ }, -+ { -+ .key = "mtu", -+ .type = CONFIG_TYPE_INT, -+ .u.value = DEFAULT_MTU -+ } -+ } -+}; -+ -+struct ipfix_templ { -+ struct ipfix_templ *next; -+}; -+ -+struct ipfix_priv { -+ struct ulogd_fd ufd; -+ uint32_t seqno; -+ struct ipfix_msg *msg; /* current message */ -+ struct llist_head list; -+ struct ipfix_templ *templates; -+ int proto; -+ struct ulogd_timer timer; -+ struct sockaddr_in sa; -+}; -+ -+enum { -+ InIpSaddr = 0, -+ InIpDaddr, -+ InRawInPktCount, -+ InRawInPktLen, -+ InRawOutPktCount, -+ InRawOutPktLen, -+ InFlowStartSec, -+ InFlowStartUsec, -+ InFlowEndSec, -+ InFlowEndUsec, -+ InL4SPort, -+ InL4DPort, -+ InIpProto, -+ InCtMark -+}; -+ -+static struct ulogd_key ipfix_in_keys[] = { -+ [InIpSaddr] = { -+ .type = ULOGD_RET_IPADDR, -+ .name = "orig.ip.saddr" -+ }, -+ [InIpDaddr] = { -+ .type = ULOGD_RET_IPADDR, -+ .name = "orig.ip.daddr" -+ }, -+ [InRawInPktCount] = { -+ .type = ULOGD_RET_UINT64, -+ .name = "orig.raw.pktcount" -+ }, -+ [InRawInPktLen] = { -+ .type = ULOGD_RET_UINT64, -+ .name = "orig.raw.pktlen" -+ }, -+ [InRawOutPktCount] = { -+ .type = ULOGD_RET_UINT64, -+ .name = "reply.raw.pktcount" -+ }, -+ [InRawOutPktLen] = { -+ .type = ULOGD_RET_UINT64, -+ .name = "reply.raw.pktlen" -+ }, -+ [InFlowStartSec] = { -+ .type = ULOGD_RET_UINT32, -+ .name = "flow.start.sec" -+ }, -+ [InFlowStartUsec] = { -+ .type = ULOGD_RET_UINT32, -+ .name = "flow.start.usec" -+ }, -+ [InFlowEndSec] = { -+ .type = ULOGD_RET_UINT32, -+ .name = "flow.end.sec" -+ }, -+ [InFlowEndUsec] = { -+ .type = ULOGD_RET_UINT32, -+ .name = "flow.end.usec" -+ }, -+ [InL4SPort] = { -+ .type = ULOGD_RET_UINT16, -+ .name = "orig.l4.sport" -+ }, -+ [InL4DPort] = { -+ .type = ULOGD_RET_UINT16, -+ .name = "orig.l4.dport" -+ }, -+ [InIpProto] = { -+ .type = ULOGD_RET_UINT8, -+ .name = "orig.ip.protocol" -+ }, -+ [InCtMark] = { -+ .type = ULOGD_RET_UINT32, -+ .name = "ct.mark" -+ } -+}; -+ -+/* do some polishing and enqueue it */ -+static void enqueue_msg(struct ipfix_priv *priv, struct ipfix_msg *msg) -+{ -+ struct ipfix_hdr *hdr = ipfix_msg_data(msg); -+ -+ if (!msg) -+ return; -+ -+ hdr->time = htonl(time(NULL)); -+ hdr->seqno = htonl(priv->seqno += msg->nrecs); -+ if (msg->last_set) { -+ msg->last_set->id = htons(msg->last_set->id); -+ msg->last_set->len = htons(msg->last_set->len); -+ msg->last_set = NULL; -+ } -+ hdr->len = htons(ipfix_msg_len(msg)); -+ -+ llist_add(&msg->link, &priv->list); -+} -+ -+/** -+ * @return %ULOGD_IRET_OK or error value -+ */ -+static int send_msgs(struct ulogd_pluginstance *pi) -+{ -+ struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ struct llist_head *curr, *tmp; -+ struct ipfix_msg *msg; -+ int ret = ULOGD_IRET_OK, sent; -+ -+ llist_for_each_prev(curr, &priv->list) { -+ msg = llist_entry(curr, struct ipfix_msg, link); -+ -+ sent = send(priv->ufd.fd, ipfix_msg_data(msg), ipfix_msg_len(msg), 0); -+ if (sent < 0) { -+ ulogd_log(ULOGD_ERROR, "send: %m\n"); -+ ret = ULOGD_IRET_ERR; -+ goto done; -+ } -+ -+ /* TODO handle short send() for other protocols */ -+ if ((size_t) sent < ipfix_msg_len(msg)) -+ ulogd_log(ULOGD_ERROR, "short send: %d < %d\n", -+ sent, ipfix_msg_len(msg)); -+ } -+ -+ llist_for_each_safe(curr, tmp, &priv->list) { -+ msg = llist_entry(curr, struct ipfix_msg, link); -+ llist_del(curr); -+ msg->nrecs = 0; -+ ipfix_msg_free(msg); -+ } -+ -+done: -+ return ret; -+} -+ -+static int ipfix_ufd_cb(int fd, unsigned what, void *arg) -+{ -+ struct ulogd_pluginstance *pi = arg; -+ struct ipfix_priv *priv = (struct ipfix_priv *) pi->private; -+ ssize_t nread; -+ char buf[16]; -+ -+ if (what & ULOGD_FD_READ) { -+ nread = recv(priv->ufd.fd, buf, sizeof(buf), MSG_DONTWAIT); -+ if (nread < 0) { -+ ulogd_log(ULOGD_ERROR, "recv: %m\n"); -+ } else if (!nread) { -+ ulogd_log(ULOGD_INFO, "connection reset by peer\n"); -+ ulogd_unregister_fd(&priv->ufd); -+ } else -+ ulogd_log(ULOGD_INFO, "unexpected data (%d bytes)\n", nread); -+ } -+ -+ return 0; -+} -+ -+static void ipfix_timer_cb(struct ulogd_timer *t, void *data) -+{ -+ struct ulogd_pluginstance *pi = data; -+ struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ -+ if (priv->msg && priv->msg->nrecs > 0) { -+ enqueue_msg(priv, priv->msg); -+ priv->msg = NULL; -+ send_msgs(pi); -+ } -+} -+ -+static int ipfix_configure(struct ulogd_pluginstance *pi, struct ulogd_pluginstance_stack *stack) -+{ -+ struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ int oid, port, mtu, ret; -+ char *host, *proto; -+ char addr[16]; -+ -+ ret = config_parse_file(pi->id, pi->config_kset); -+ if (ret < 0) -+ return ret; -+ -+ oid = oid_ce(pi->config_kset).u.value; -+ host = host_ce(pi->config_kset).u.string; -+ port = port_ce(pi->config_kset).u.value; -+ proto = proto_ce(pi->config_kset).u.string; -+ mtu = mtu_ce(pi->config_kset).u.value; -+ -+ if (!oid) { -+ ulogd_log(ULOGD_FATAL, "invalid Observation ID\n"); -+ return ULOGD_IRET_ERR; -+ } -+ if (!host || !strcmp(host, "")) { -+ ulogd_log(ULOGD_FATAL, "no destination host specified\n"); -+ return ULOGD_IRET_ERR; -+ } -+ -+ if (!strcmp(proto, "udp")) { -+ priv->proto = IPPROTO_UDP; -+ } else if (!strcmp(proto, "tcp")) { -+ priv->proto = IPPROTO_TCP; -+ } else { -+ ulogd_log(ULOGD_FATAL, "unsupported protocol '%s'\n", proto); -+ return ULOGD_IRET_ERR; -+ } -+ -+ memset(&priv->sa, 0, sizeof(priv->sa)); -+ priv->sa.sin_family = AF_INET; -+ priv->sa.sin_port = htons(port); -+ ret = inet_pton(AF_INET, host, &priv->sa.sin_addr); -+ if (ret <= 0) { -+ ulogd_log(ULOGD_FATAL, "inet_pton: %m\n"); -+ return ULOGD_IRET_ERR; -+ } -+ -+ INIT_LLIST_HEAD(&priv->list); -+ -+ ulogd_init_timer(&priv->timer, pi, ipfix_timer_cb); -+ -+ ulogd_log(ULOGD_INFO, "using IPFIX Collector at %s:%d (MTU %d)\n", -+ inet_ntop(AF_INET, &priv->sa.sin_addr, addr, sizeof(addr)), -+ port, mtu); -+ -+ return ULOGD_IRET_OK; -+} -+ -+static int tcp_connect(struct ulogd_pluginstance *pi) -+{ -+ struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ int ret = ULOGD_IRET_ERR; -+ -+ if ((priv->ufd.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ ulogd_log(ULOGD_FATAL, "socket: %m\n"); -+ return ULOGD_IRET_ERR; -+ } -+ -+ if (connect(priv->ufd.fd, (struct sockaddr *) &priv->sa, sizeof(priv->sa)) < 0) { -+ ulogd_log(ULOGD_ERROR, "connect: %m\n"); -+ ret = ULOGD_IRET_ERR; -+ goto err_close; -+ } -+ -+ return ULOGD_IRET_OK; -+ -+err_close: -+ close(priv->ufd.fd); -+ return ret; -+} -+ -+static int udp_connect(struct ulogd_pluginstance *pi) -+{ -+ struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ -+ if ((priv->ufd.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { -+ ulogd_log(ULOGD_FATAL, "socket: %m\n"); -+ return ULOGD_IRET_ERR; -+ } -+ -+ if (connect(priv->ufd.fd, (struct sockaddr *) &priv->sa, sizeof(priv->sa)) < 0) { -+ ulogd_log(ULOGD_ERROR, "connect: %m\n"); -+ return ULOGD_IRET_ERR; -+ } -+ -+ return 0; -+} -+ -+static int ipfix_start(struct ulogd_pluginstance *pi) -+{ -+ struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ char addr[16]; -+ int port, ret; -+ -+ switch (priv->proto) { -+ case IPPROTO_UDP: -+ if ((ret = udp_connect(pi)) < 0) -+ return ret; -+ break; -+ case IPPROTO_TCP: -+ if ((ret = tcp_connect(pi)) < 0) -+ return ret; -+ break; -+ -+ default: -+ break; -+ } -+ -+ priv->seqno = 0; -+ -+ port = port_ce(pi->config_kset).u.value; -+ ulogd_log(ULOGD_INFO, "connected to %s:%d\n", -+ inet_ntop(AF_INET, &priv->sa.sin_addr, addr, sizeof(addr)), -+ port); -+ -+ /* Register the socket FD */ -+ priv->ufd.when = ULOGD_FD_READ; -+ priv->ufd.cb = ipfix_ufd_cb; -+ priv->ufd.data = pi; -+ -+ if (ulogd_register_fd(&priv->ufd) < 0) -+ return ULOGD_IRET_ERR; -+ -+ /* Add a 1 second timer */ -+ ulogd_add_timer(&priv->timer, 1); -+ -+ return ULOGD_IRET_OK; -+} -+ -+static int ipfix_stop(struct ulogd_pluginstance *pi) -+{ -+ struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ -+ ulogd_unregister_fd(&priv->ufd); -+ close(priv->ufd.fd); -+ priv->ufd.fd = -1; -+ -+ ulogd_del_timer(&priv->timer); -+ -+ ipfix_msg_free(priv->msg); -+ priv->msg = NULL; -+ -+ return 0; -+} -+ -+static int ipfix_interp(struct ulogd_pluginstance *pi) -+{ -+ struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ struct vy_ipfix_data *data; -+ int oid, mtu, ret; -+ char addr[16]; -+ -+ if (!(GET_FLAGS(pi->input.keys, InIpSaddr) & ULOGD_RETF_VALID)) -+ return ULOGD_IRET_OK; -+ -+ oid = oid_ce(pi->config_kset).u.value; -+ mtu = mtu_ce(pi->config_kset).u.value; -+ -+again: -+ if (!priv->msg) { -+ priv->msg = ipfix_msg_alloc(mtu, oid); -+ if (!priv->msg) { -+ /* just drop this flow */ -+ ulogd_log(ULOGD_ERROR, "out of memory, dropping flow\n"); -+ return ULOGD_IRET_OK; -+ } -+ ipfix_msg_add_set(priv->msg, VY_IPFIX_SID); -+ } -+ -+ data = ipfix_msg_add_data(priv->msg, sizeof(struct vy_ipfix_data)); -+ if (!data) { -+ enqueue_msg(priv, priv->msg); -+ priv->msg = NULL; -+ /* can't loop because the next will definitely succeed */ -+ goto again; -+ } -+ -+ data->ifi_in = data->ifi_out = 0; -+ -+ data->saddr.s_addr = ikey_get_u32(&pi->input.keys[InIpSaddr]); -+ data->daddr.s_addr = ikey_get_u32(&pi->input.keys[InIpDaddr]); -+ -+ data->packets = htonl((uint32_t) (ikey_get_u64(&pi->input.keys[InRawInPktCount]) -+ + ikey_get_u64(&pi->input.keys[InRawOutPktCount]))); -+ data->bytes = htonl((uint32_t) (ikey_get_u64(&pi->input.keys[InRawInPktLen]) -+ + ikey_get_u64(&pi->input.keys[InRawOutPktLen]))); -+ -+ data->start = htonl(ikey_get_u32(&pi->input.keys[InFlowStartSec])); -+ data->end = htonl(ikey_get_u32(&pi->input.keys[InFlowEndSec])); -+ -+ if (GET_FLAGS(pi->input.keys, InL4SPort) & ULOGD_RETF_VALID) { -+ data->sport = htons(ikey_get_u16(&pi->input.keys[InL4SPort])); -+ data->dport = htons(ikey_get_u16(&pi->input.keys[InL4DPort])); -+ } -+ -+ data->aid = 0; -+ if (GET_FLAGS(pi->input.keys, InCtMark) & ULOGD_RETF_VALID) -+ data->aid = htonl(ikey_get_u32(&pi->input.keys[InCtMark])); -+ -+ data->l4_proto = ikey_get_u8(&pi->input.keys[InIpProto]); -+ data->__padding = 0; -+ -+ ulogd_log(ULOGD_DEBUG, "Got new packet (packets = %u, bytes = %u, flow = (%u, %u), saddr = %s, daddr = %s, sport = %u, dport = %u)\n", -+ ntohl(data->packets), ntohl(data->bytes), ntohl(data->start), ntohl(data->end), -+ inet_ntop(AF_INET, &data->saddr.s_addr, addr, sizeof(addr)), -+ inet_ntop(AF_INET, &data->daddr.s_addr, addr, sizeof(addr)), -+ ntohs(data->sport), ntohs(data->dport)); -+ -+ if ((ret = send_msgs(pi)) < 0) -+ return ret; -+ -+ return ULOGD_IRET_OK; -+} -+ -+static struct ulogd_plugin ipfix_plugin = { -+ .name = "IPFIX", -+ .input = { -+ .keys = ipfix_in_keys, -+ .num_keys = ARRAY_SIZE(ipfix_in_keys), -+ .type = ULOGD_DTYPE_PACKET | ULOGD_DTYPE_FLOW | ULOGD_DTYPE_SUM -+ }, -+ .output = { -+ .type = ULOGD_DTYPE_SINK -+ }, -+ .config_kset = (struct config_keyset *) &ipfix_kset, -+ .priv_size = sizeof(struct ipfix_priv), -+ .configure = ipfix_configure, -+ .start = ipfix_start, -+ .stop = ipfix_stop, -+ .interp = ipfix_interp, -+ .version = VERSION, -+}; -+ -+void __attribute__ ((constructor)) init(void); -+ -+void init(void) -+{ -+ ulogd_register_plugin(&ipfix_plugin); -+} diff --git a/net/ulogd/patches/040-ipfix-template.patch b/net/ulogd/patches/040-ipfix-template.patch deleted file mode 100644 index c7b9d8eeb9..0000000000 --- a/net/ulogd/patches/040-ipfix-template.patch +++ /dev/null @@ -1,421 +0,0 @@ -From cc919f7013d2d76c8bef0b9c562c1faf98a095a3 Mon Sep 17 00:00:00 2001 -From: Ander Juaristi -Date: Fri, 26 Apr 2019 09:58:07 +0200 -Subject: IPFIX: Introduce template record support - -This commit adds the ability to send template records -to the remote collector. - -In addition, it also introduces a new -configuration parameter 'send_template', which tells when template -records should be sent. It accepts the following string values: - - - "once": Send the template record only the first time (might be coalesced - with data records). - - "always": Send the template record always, with every data record that is sent - to the collector (multiple data records might be sent together). - - "never": Assume the collector knows the schema already. Do not send template records. - -If omitted, the default value for 'send_template' is "once". - -Signed-off-by: Ander Juaristi -Signed-off-by: Pablo Neira Ayuso ---- - include/ulogd/ipfix_protocol.h | 1 + - output/ipfix/ipfix.c | 97 +++++++++++++++++++++++++++++++++++++-- - output/ipfix/ipfix.h | 22 ++++----- - output/ipfix/ulogd_output_IPFIX.c | 56 ++++++++++++---------- - 4 files changed, 139 insertions(+), 37 deletions(-) - ---- a/include/ulogd/ipfix_protocol.h -+++ b/include/ulogd/ipfix_protocol.h -@@ -129,6 +129,7 @@ enum { - /* reserved */ - IPFIX_fragmentOffsetIPv4 = 88, - /* reserved */ -+ IPFIX_applicationId = 95, - IPFIX_bgpNextAdjacentAsNumber = 128, - IPFIX_bgpPrevAdjacentAsNumber = 129, - IPFIX_exporterIPv4Address = 130, ---- a/output/ipfix/ipfix.c -+++ b/output/ipfix/ipfix.c -@@ -2,6 +2,7 @@ - * ipfix.c - * - * Holger Eitzenberger, 2009. -+ * Ander Juaristi, 2019 - */ - - /* These forward declarations are needed since ulogd.h doesn't like to be the first */ -@@ -13,25 +14,107 @@ - - #include - #include -+#include - --struct ipfix_msg *ipfix_msg_alloc(size_t len, uint32_t oid) -+struct ipfix_templ_elem { -+ uint16_t id; -+ uint16_t len; -+}; -+ -+struct ipfix_templ { -+ unsigned int num_templ_elements; -+ struct ipfix_templ_elem templ_elements[]; -+}; -+ -+/* Template fields modeled after vy_ipfix_data */ -+static const struct ipfix_templ template = { -+ .num_templ_elements = 10, -+ .templ_elements = { -+ { -+ .id = IPFIX_sourceIPv4Address, -+ .len = sizeof(uint32_t) -+ }, -+ { -+ .id = IPFIX_destinationIPv4Address, -+ .len = sizeof(uint32_t) -+ }, -+ { -+ .id = IPFIX_packetTotalCount, -+ .len = sizeof(uint32_t) -+ }, -+ { -+ .id = IPFIX_octetTotalCount, -+ .len = sizeof(uint32_t) -+ }, -+ { -+ .id = IPFIX_flowStartSeconds, -+ .len = sizeof(uint32_t) -+ }, -+ { -+ .id = IPFIX_flowEndSeconds, -+ .len = sizeof(uint32_t) -+ }, -+ { -+ .id = IPFIX_sourceTransportPort, -+ .len = sizeof(uint16_t) -+ }, -+ { -+ .id = IPFIX_destinationTransportPort, -+ .len = sizeof(uint16_t) -+ }, -+ { -+ .id = IPFIX_protocolIdentifier, -+ .len = sizeof(uint8_t) -+ }, -+ { -+ .id = IPFIX_applicationId, -+ .len = sizeof(uint32_t) -+ } -+ } -+}; -+ -+struct ipfix_msg *ipfix_msg_alloc(size_t len, uint32_t oid, int tid) - { - struct ipfix_msg *msg; - struct ipfix_hdr *hdr; -+ struct ipfix_templ_hdr *templ_hdr; -+ struct ipfix_templ_elem *elem; -+ unsigned int i = 0; - -- if (len < IPFIX_HDRLEN + IPFIX_SET_HDRLEN) -+ if ((tid > 0 && len < IPFIX_HDRLEN + IPFIX_TEMPL_HDRLEN(template.num_templ_elements) + IPFIX_SET_HDRLEN) || -+ (len < IPFIX_HDRLEN + IPFIX_SET_HDRLEN)) - return NULL; - - msg = malloc(sizeof(struct ipfix_msg) + len); - memset(msg, 0, sizeof(struct ipfix_msg)); -- msg->tail = msg->data + IPFIX_HDRLEN; -+ msg->tid = tid; - msg->end = msg->data + len; -+ msg->tail = msg->data + IPFIX_HDRLEN; -+ if (tid > 0) -+ msg->tail += IPFIX_TEMPL_HDRLEN(template.num_templ_elements); - -+ /* Initialize message header */ - hdr = ipfix_msg_hdr(msg); - memset(hdr, 0, IPFIX_HDRLEN); - hdr->version = htons(IPFIX_VERSION); - hdr->oid = htonl(oid); - -+ if (tid > 0) { -+ /* Initialize template record header */ -+ templ_hdr = ipfix_msg_templ_hdr(msg); -+ templ_hdr->sid = htons(2); -+ templ_hdr->tid = htons(tid); -+ templ_hdr->len = htons(IPFIX_TEMPL_HDRLEN(template.num_templ_elements)); -+ templ_hdr->cnt = htons(template.num_templ_elements); -+ -+ while (i < template.num_templ_elements) { -+ elem = (struct ipfix_templ_elem *) &templ_hdr->data[i * 4]; -+ elem->id = htons(template.templ_elements[i].id); -+ elem->len = htons(template.templ_elements[i].len); -+ i++; -+ } -+ } -+ - return msg; - } - -@@ -47,6 +130,14 @@ void ipfix_msg_free(struct ipfix_msg *ms - free(msg); - } - -+struct ipfix_templ_hdr *ipfix_msg_templ_hdr(const struct ipfix_msg *msg) -+{ -+ if (msg->tid > 0) -+ return (struct ipfix_templ_hdr *) (msg->data + IPFIX_HDRLEN); -+ -+ return NULL; -+} -+ - struct ipfix_hdr *ipfix_msg_hdr(const struct ipfix_msg *msg) - { - return (struct ipfix_hdr *)msg->data; ---- a/output/ipfix/ipfix.h -+++ b/output/ipfix/ipfix.h -@@ -2,6 +2,7 @@ - * ipfix.h - * - * Holger Eitzenberger , 2009. -+ * Ander Juaristi , 2019 - */ - #ifndef IPFIX_H - #define IPFIX_H -@@ -20,17 +21,21 @@ struct ipfix_hdr { - uint8_t data[]; - } __packed; - --#define IPFIX_HDRLEN sizeof(struct ipfix_hdr) -+#define IPFIX_HDRLEN sizeof(struct ipfix_hdr) - - /* - * IDs 0-255 are reserved for Template Sets. IDs of Data Sets are > 255. - */ - struct ipfix_templ_hdr { -- uint16_t id; -+ uint16_t sid; -+ uint16_t len; -+ uint16_t tid; - uint16_t cnt; - uint8_t data[]; - } __packed; - -+#define IPFIX_TEMPL_HDRLEN(nfields) sizeof(struct ipfix_templ_hdr) + (sizeof(uint16_t) * 2 * nfields) -+ - struct ipfix_set_hdr { - #define IPFIX_SET_TEMPL 2 - #define IPFIX_SET_OPT_TEMPL 3 -@@ -46,6 +51,7 @@ struct ipfix_msg { - uint8_t *tail; - uint8_t *end; - unsigned nrecs; -+ int tid; - struct ipfix_set_hdr *last_set; - uint8_t data[]; - }; -@@ -53,18 +59,14 @@ struct ipfix_msg { - struct vy_ipfix_data { - struct in_addr saddr; - struct in_addr daddr; -- uint16_t ifi_in; -- uint16_t ifi_out; - uint32_t packets; - uint32_t bytes; - uint32_t start; /* Unix time */ - uint32_t end; /* Unix time */ - uint16_t sport; - uint16_t dport; -- uint32_t aid; /* Application ID */ - uint8_t l4_proto; -- uint8_t dscp; -- uint16_t __padding; -+ uint32_t aid; /* Application ID */ - } __packed; - - #define VY_IPFIX_SID 256 -@@ -73,13 +75,11 @@ struct vy_ipfix_data { - #define VY_IPFIX_PKT_LEN (IPFIX_HDRLEN + IPFIX_SET_HDRLEN \ - + VY_IPFIX_FLOWS * sizeof(struct vy_ipfix_data)) - --/* template management */ --size_t ipfix_rec_len(uint16_t); -- - /* message handling */ --struct ipfix_msg *ipfix_msg_alloc(size_t, uint32_t); -+struct ipfix_msg *ipfix_msg_alloc(size_t, uint32_t, int); - void ipfix_msg_free(struct ipfix_msg *); - struct ipfix_hdr *ipfix_msg_hdr(const struct ipfix_msg *); -+struct ipfix_templ_hdr *ipfix_msg_templ_hdr(const struct ipfix_msg *); - size_t ipfix_msg_len(const struct ipfix_msg *); - void *ipfix_msg_data(struct ipfix_msg *); - struct ipfix_set_hdr *ipfix_msg_add_set(struct ipfix_msg *, uint16_t); ---- a/output/ipfix/ulogd_output_IPFIX.c -+++ b/output/ipfix/ulogd_output_IPFIX.c -@@ -3,6 +3,9 @@ - * - * ulogd IPFIX Exporter plugin. - * -+ * (C) 2009 by Holger Eitzenberger , Astaro AG -+ * (C) 2019 by Ander Juaristi -+ * - * 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 -@@ -11,8 +14,6 @@ - * 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 -- * -- * Holger Eitzenberger Astaro AG 2009 - */ - #include - #include -@@ -28,6 +29,7 @@ - #define DEFAULT_MTU 512 /* RFC 5101, 10.3.3 */ - #define DEFAULT_PORT 4739 /* RFC 5101, 10.3.4 */ - #define DEFAULT_SPORT 4740 -+#define DEFAULT_SEND_TEMPLATE "once" - - enum { - OID_CE = 0, -@@ -35,16 +37,18 @@ enum { - PORT_CE, - PROTO_CE, - MTU_CE, -+ SEND_TEMPLATE_CE - }; - --#define oid_ce(x) (x->ces[OID_CE]) --#define host_ce(x) (x->ces[HOST_CE]) --#define port_ce(x) (x->ces[PORT_CE]) --#define proto_ce(x) (x->ces[PROTO_CE]) --#define mtu_ce(x) (x->ces[MTU_CE]) -+#define oid_ce(x) (x->ces[OID_CE]) -+#define host_ce(x) (x->ces[HOST_CE]) -+#define port_ce(x) (x->ces[PORT_CE]) -+#define proto_ce(x) (x->ces[PROTO_CE]) -+#define mtu_ce(x) (x->ces[MTU_CE]) -+#define send_template_ce(x) (x->ces[SEND_TEMPLATE_CE]) - - static const struct config_keyset ipfix_kset = { -- .num_ces = 5, -+ .num_ces = 6, - .ces = { - { - .key = "oid", -@@ -70,20 +74,21 @@ static const struct config_keyset ipfix_ - .key = "mtu", - .type = CONFIG_TYPE_INT, - .u.value = DEFAULT_MTU -+ }, -+ { -+ .key = "send_template", -+ .type = CONFIG_TYPE_STRING, -+ .u.string = DEFAULT_SEND_TEMPLATE - } - } - }; - --struct ipfix_templ { -- struct ipfix_templ *next; --}; -- - struct ipfix_priv { - struct ulogd_fd ufd; - uint32_t seqno; - struct ipfix_msg *msg; /* current message */ - struct llist_head list; -- struct ipfix_templ *templates; -+ int tid; - int proto; - struct ulogd_timer timer; - struct sockaddr_in sa; -@@ -258,8 +263,8 @@ static void ipfix_timer_cb(struct ulogd_ - static int ipfix_configure(struct ulogd_pluginstance *pi, struct ulogd_pluginstance_stack *stack) - { - struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ char *host, *proto, *send_template; - int oid, port, mtu, ret; -- char *host, *proto; - char addr[16]; - - ret = config_parse_file(pi->id, pi->config_kset); -@@ -271,6 +276,7 @@ static int ipfix_configure(struct ulogd_ - port = port_ce(pi->config_kset).u.value; - proto = proto_ce(pi->config_kset).u.string; - mtu = mtu_ce(pi->config_kset).u.value; -+ send_template = send_template_ce(pi->config_kset).u.string; - - if (!oid) { - ulogd_log(ULOGD_FATAL, "invalid Observation ID\n"); -@@ -303,6 +309,8 @@ static int ipfix_configure(struct ulogd_ - - ulogd_init_timer(&priv->timer, pi, ipfix_timer_cb); - -+ priv->tid = (strcmp(send_template, "never") ? VY_IPFIX_SID : -1); -+ - ulogd_log(ULOGD_INFO, "using IPFIX Collector at %s:%d (MTU %d)\n", - inet_ntop(AF_INET, &priv->sa.sin_addr, addr, sizeof(addr)), - port, mtu); -@@ -410,25 +418,30 @@ static int ipfix_stop(struct ulogd_plugi - static int ipfix_interp(struct ulogd_pluginstance *pi) - { - struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private; -+ char saddr[16], daddr[16], *send_template; - struct vy_ipfix_data *data; - int oid, mtu, ret; -- char addr[16]; - - if (!(GET_FLAGS(pi->input.keys, InIpSaddr) & ULOGD_RETF_VALID)) - return ULOGD_IRET_OK; - - oid = oid_ce(pi->config_kset).u.value; - mtu = mtu_ce(pi->config_kset).u.value; -+ send_template = send_template_ce(pi->config_kset).u.string; - - again: - if (!priv->msg) { -- priv->msg = ipfix_msg_alloc(mtu, oid); -+ priv->msg = ipfix_msg_alloc(mtu, oid, priv->tid); - if (!priv->msg) { - /* just drop this flow */ - ulogd_log(ULOGD_ERROR, "out of memory, dropping flow\n"); - return ULOGD_IRET_OK; - } - ipfix_msg_add_set(priv->msg, VY_IPFIX_SID); -+ -+ /* template sent - do not send it again the next time */ -+ if (priv->tid == VY_IPFIX_SID && strcmp(send_template, "once") == 0) -+ priv->tid = -1; - } - - data = ipfix_msg_add_data(priv->msg, sizeof(struct vy_ipfix_data)); -@@ -439,8 +452,6 @@ again: - goto again; - } - -- data->ifi_in = data->ifi_out = 0; -- - data->saddr.s_addr = ikey_get_u32(&pi->input.keys[InIpSaddr]); - data->daddr.s_addr = ikey_get_u32(&pi->input.keys[InIpDaddr]); - -@@ -462,13 +473,12 @@ again: - data->aid = htonl(ikey_get_u32(&pi->input.keys[InCtMark])); - - data->l4_proto = ikey_get_u8(&pi->input.keys[InIpProto]); -- data->__padding = 0; - - ulogd_log(ULOGD_DEBUG, "Got new packet (packets = %u, bytes = %u, flow = (%u, %u), saddr = %s, daddr = %s, sport = %u, dport = %u)\n", -- ntohl(data->packets), ntohl(data->bytes), ntohl(data->start), ntohl(data->end), -- inet_ntop(AF_INET, &data->saddr.s_addr, addr, sizeof(addr)), -- inet_ntop(AF_INET, &data->daddr.s_addr, addr, sizeof(addr)), -- ntohs(data->sport), ntohs(data->dport)); -+ ntohl(data->packets), ntohl(data->bytes), ntohl(data->start), ntohl(data->end), -+ inet_ntop(AF_INET, &data->saddr.s_addr, saddr, sizeof(saddr)), -+ inet_ntop(AF_INET, &data->daddr.s_addr, daddr, sizeof(daddr)), -+ ntohs(data->sport), ntohs(data->dport)); - - if ((ret = send_msgs(pi)) < 0) - return ret;