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 --- output/ipfix/ipfix.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 output/ipfix/ipfix.c (limited to 'output/ipfix/ipfix.c') 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 + +#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); +} -- cgit v1.2.3