summaryrefslogtreecommitdiffstats
path: root/output/ipfix/ipfix.c
diff options
context:
space:
mode:
authorAnder Juaristi <a@juaristi.eus>2019-04-26 09:58:06 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2019-04-30 14:11:54 +0200
commit4f639231c83b09ea004c03e95c702b7750bf9930 (patch)
tree99bb7210f52d5530f21efcb3f4d45020113b22e2 /output/ipfix/ipfix.c
parent675e762091380590f78ff07a94a25caa459b786b (diff)
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 <holger@eitzenberger.org>. 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 <a@juaristi.eus> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'output/ipfix/ipfix.c')
-rw-r--r--output/ipfix/ipfix.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/output/ipfix/ipfix.c b/output/ipfix/ipfix.c
new file mode 100644
index 0000000..60a4c7f
--- /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 <ulogd/linuxlist.h>
+
+#define __packed __attribute__((packed))
+
+#include "ipfix.h"
+
+#include <ulogd/ulogd.h>
+#include <ulogd/common.h>
+
+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);
+}