summaryrefslogtreecommitdiffstats
path: root/output/ulogd_output_IPFIX.c
diff options
context:
space:
mode:
Diffstat (limited to 'output/ulogd_output_IPFIX.c')
-rw-r--r--output/ulogd_output_IPFIX.c546
1 files changed, 0 insertions, 546 deletions
diff --git a/output/ulogd_output_IPFIX.c b/output/ulogd_output_IPFIX.c
deleted file mode 100644
index 62f1d60..0000000
--- a/output/ulogd_output_IPFIX.c
+++ /dev/null
@@ -1,546 +0,0 @@
-/* ulogd_output_IPFIX.c
- *
- * ulogd output plugin for IPFIX
- *
- * This target produces a file which looks the same like the syslog-entries
- * of the LOG target.
- *
- * (C) 2005 by Harald Welte <laforge@gnumonks.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * 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
- *
- * TODO:
- * - where to get a useable <sctp.h> for linux ?
- * - implement PR-SCTP (no api definition in draft sockets api)
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include <ulogd/linuxlist.h>
-
-#ifdef IPPROTO_SCTP
-/* temporarily disable sctp until we know which headers to use */
-#undef IPPROTO_SCTP
-#endif
-
-#ifdef IPPROTO_SCTP
-typedef uint32_t sctp_assoc_t;
-
-/* glibc doesn't yet have this, as defined by
- * draft-ietf-tsvwg-sctpsocket-11.txt */
-struct sctp_sndrcvinfo {
- uint16_t sinfo_stream;
- uint16_t sinfo_ssn;
- uint16_t sinfo_flags;
- uint32_t sinfo_ppid;
- uint32_t sinfo_context;
- uint32_t sinfo_timetolive;
- uint32_t sinfo_tsn;
- uint32_t sinfo_cumtsn;
- sctp_assoc_t sinfo_assoc_id;
-};
-#endif
-
-#include <ulogd/ulogd.h>
-#include <ulogd/conffile.h>
-#include <ulogd/linuxlist.h>
-#include <ulogd/ipfix_protocol.h>
-
-#define IPFIX_DEFAULT_TCPUDP_PORT 4739
-
-/* bitmask stuff */
-struct bitmask {
- int size_bits;
- char *buf;
-};
-
-#define SIZE_OCTETS(x) ((x/8)+1)
-
-void bitmask_clear(struct bitmask *bm)
-{
- memset(bm->buf, 0, SIZE_OCTETS(bm->size_bits));
-}
-
-struct bitmask *bitmask_alloc(unsigned int num_bits)
-{
- struct bitmask *bm;
- unsigned int size_octets = SIZE_OCTETS(num_bits);
-
- bm = malloc(sizeof(*bm) + size_octets);
- if (!bm)
- return NULL;
-
- bm->size_bits = num_bits;
- bm->buf = (void *)bm + sizeof(*bm);
-
- bitmask_clear(bm);
-
- return bm;
-}
-
-void bitmask_free(struct bitmask *bm)
-{
- free(bm);
-}
-
-int bitmask_set_bit_to(struct bitmask *bm, unsigned int bits, int to)
-{
- unsigned int byte = bits / 8;
- unsigned int bit = bits % 8;
- unsigned char *ptr;
-
- if (byte > SIZE_OCTETS(bm->size_bits))
- return -EINVAL;
-
- if (to == 0)
- bm->buf[byte] &= ~(1 << bit);
- else
- bm->buf[byte] |= (1 << bit);
-
- return 0;
-}
-
-#define bitmask_clear_bit(bm, bit) \
- bitmask_set_bit_to(bm, bit, 0)
-
-#define bitmask_set_bit(bm, bit) \
- bitmask_set_bit_to(bm, bit, 1)
-
-int bitmasks_equal(const struct bitmask *bm1, const struct bitmask *bm2)
-{
- if (bm1->size_bits != bm2->size_bits)
- return -1;
-
- if (!memcmp(bm1->buf, bm2->buf, SIZE_OCTETS(bm1->size_bits)))
- return 1;
- else
- return 0;
-}
-
-struct bitmask *bitmask_dup(const struct bitmask *bm_orig)
-{
- struct bitmask *bm_new;
- int size = sizeof(*bm_new) + SIZE_OCTETS(bm_orig->size_bits);
-
- bm_new = malloc(size);
- if (!bm_new)
- return NULL;
-
- memcpy(bm_new, bm_orig, size);
-
- return bm_new;
-}
-
-static struct config_keyset ipfix_kset = {
- .num_ces = 3,
- .ces = {
- {
- .key = "host",
- .type = CONFIG_TYPE_STRING,
- .options = CONFIG_OPT_NONE,
- },
- {
- .key = "port",
- .type = CONFIG_TYPE_STRING,
- .options = CONFIG_OPT_NONE,
- .u = { .string = "4739" },
- },
- {
- .key = "protocol",
- .type = CONFIG_TYPE_STRING,
- .options = CONFIG_OPT_NONE,
- .u = { .string = "udp" },
- },
- },
-};
-
-#define host_ce(x) (x->ces[0])
-#define port_ce(x) (x->ces[1])
-#define proto_ce(x) (x->ces[2])
-
-struct ipfix_template {
- struct ipfix_templ_rec_hdr hdr;
- char buf[0];
-};
-
-struct ulogd_ipfix_template {
- struct llist_head list;
- struct bitmask *bitmask;
- unsigned int total_length; /* length of the DATA */
- char *tmpl_cur; /* cursor into current template position */
- struct ipfix_template tmpl;
-};
-
-struct ipfix_instance {
- int fd; /* socket that we use for sending IPFIX data */
- int sock_type; /* type (SOCK_*) */
- int sock_proto; /* protocol (IPPROTO_*) */
-
- struct llist_head template_list;
-
- struct ipfix_template *tmpl;
- unsigned int tmpl_len;
-
- struct bitmask *valid_bitmask; /* bitmask of valid keys */
-
- unsigned int total_length; /* total size of all data elements */
-};
-
-#define ULOGD_IPFIX_TEMPL_BASE 1024
-static uint16_t next_template_id = ULOGD_IPFIX_TEMPL_BASE;
-
-/* Build the IPFIX template from the input keys */
-struct ulogd_ipfix_template *
-build_template_for_bitmask(struct ulogd_pluginstance *upi,
- struct bitmask *bm)
-{
- struct ipfix_instance *ii = (struct ipfix_instance *) &upi->private;
- struct ipfix_templ_rec_hdr *rhdr;
- struct ulogd_ipfix_template *tmpl;
- unsigned int i, j;
- int size = sizeof(struct ulogd_ipfix_template)
- + (upi->input.num_keys * sizeof(struct ipfix_vendor_field));
-
- tmpl = malloc(size);
- if (!tmpl)
- return NULL;
- memset(tmpl, 0, size);
-
- tmpl->bitmask = bitmask_dup(bm);
- if (!tmpl->bitmask) {
- free(tmpl);
- return NULL;
- }
-
- /* initialize template header */
- tmpl->tmpl.hdr.templ_id = htons(next_template_id++);
-
- tmpl->tmpl_cur = tmpl->tmpl.buf;
-
- tmpl->total_length = 0;
-
- for (i = 0, j = 0; i < upi->input.num_keys; i++) {
- struct ulogd_key *key = &upi->input.keys[i];
- int length = ulogd_key_size(key);
-
- if (!(key->u.source->flags & ULOGD_RETF_VALID))
- continue;
-
- if (length < 0 || length > 0xfffe) {
- ulogd_log(ULOGD_INFO, "ignoring key `%s' because "
- "it has an ipfix incompatible length\n",
- key->name);
- continue;
- }
-
- if (key->ipfix.field_id == 0) {
- ulogd_log(ULOGD_INFO, "ignoring key `%s' because "
- "it has no field_id\n", key->name);
- continue;
- }
-
- if (key->ipfix.vendor == IPFIX_VENDOR_IETF) {
- struct ipfix_ietf_field *field =
- (struct ipfix_ietf_field *) tmpl->tmpl_cur;
-
- field->type = htons(key->ipfix.field_id | 0x8000000);
- field->length = htons(length);
- tmpl->tmpl_cur += sizeof(*field);
- } else {
- struct ipfix_vendor_field *field =
- (struct ipfix_vendor_field *) tmpl->tmpl_cur;
-
- field->enterprise_num = htonl(key->ipfix.vendor);
- field->type = htons(key->ipfix.field_id);
- field->length = htons(length);
- tmpl->tmpl_cur += sizeof(*field);
- }
- tmpl->total_length += length;
- j++;
- }
-
- tmpl->tmpl.hdr.field_count = htons(j);
-
- return tmpl;
-}
-
-
-
-static struct ulogd_ipfix_template *
-find_template_for_bitmask(struct ulogd_pluginstance *upi,
- struct bitmask *bm)
-{
- struct ipfix_instance *ii = (struct ipfix_instance *) &upi->private;
- struct ulogd_ipfix_template *tmpl;
-
- /* FIXME: this can be done more efficient! */
- llist_for_each_entry(tmpl, &ii->template_list, list) {
- if (bitmasks_equal(bm, tmpl->bitmask))
- return tmpl;
- }
- return NULL;
-}
-
-static int output_ipfix(struct ulogd_pluginstance *upi)
-{
- struct ipfix_instance *ii = (struct ipfix_instance *) &upi->private;
- struct ulogd_ipfix_template *template;
- unsigned int total_size;
- int i;
-
- /* FIXME: it would be more cache efficient if the IS_VALID
- * flags would be a separate bitmask outside of the array.
- * ulogd core could very easily flush it after every packet,
- * too. */
-
- bitmask_clear(ii->valid_bitmask);
-
- for (i = 0; i < upi->input.num_keys; i++) {
- struct ulogd_key *key = upi->input.keys[i].u.source;
-
- if (key->flags & ULOGD_RETF_VALID)
- bitmask_set_bit(ii->valid_bitmask, i);
- }
-
- /* lookup template ID for this bitmask */
- template = find_template_for_bitmask(upi, ii->valid_bitmask);
- if (!template) {
- ulogd_log(ULOGD_INFO, "building new template\n");
- template = build_template_for_bitmask(upi, ii->valid_bitmask);
- if (!template) {
- ulogd_log(ULOGD_ERROR, "can't build new template!\n");
- return ULOGD_IRET_ERR;
- }
- llist_add(&template->list, &ii->template_list);
- }
-
- total_size = template->total_length;
-
- /* decide if it's time to retransmit our template and (optionally)
- * prepend it into the to-be-sent IPFIX message */
- if (0 /* FIXME */) {
- /* add size of template */
- //total_size += (template->tmpl_cur - (void *)&template->tmpl);
- total_size += sizeof(template->tmpl);
- }
-
- return ULOGD_IRET_OK;
-}
-
-static int open_connect_socket(struct ulogd_pluginstance *pi)
-{
- struct ipfix_instance *ii = (struct ipfix_instance *) &pi->private;
- struct addrinfo hint, *res, *resave;
- int ret;
-
- memset(&hint, 0, sizeof(hint));
- hint.ai_socktype = ii->sock_type;
- hint.ai_protocol = ii->sock_proto;
- hint.ai_flags = AI_ADDRCONFIG;
-
- ret = getaddrinfo(host_ce(pi->config_kset).u.string,
- port_ce(pi->config_kset).u.string,
- &hint, &res);
- if (ret != 0) {
- ulogd_log(ULOGD_ERROR, "can't resolve host/service: %s\n",
- gai_strerror(ret));
- return -1;
- }
-
- resave = res;
-
- for (; res; res = res->ai_next) {
- ii->fd = socket(res->ai_family, res->ai_socktype,
- res->ai_protocol);
- if (ii->fd < 0) {
- switch (errno) {
- case EACCES:
- case EAFNOSUPPORT:
- case EINVAL:
- case EPROTONOSUPPORT:
- /* try next result */
- continue;
- default:
- ulogd_log(ULOGD_ERROR, "error: %s\n",
- strerror(errno));
- break;
- }
- }
-
-#ifdef IPPROTO_SCTP
- /* Set the number of SCTP output streams */
- if (res->ai_protocol == IPPROTO_SCTP) {
- struct sctp_initmsg initmsg;
- int ret;
- memset(&initmsg, 0, sizeof(initmsg));
- initmsg.sinit_num_ostreams = 2;
- ret = setsockopt(ii->fd, IPPROTO_SCTP, SCTP_INITMSG,
- &initmsg, sizeof(initmsg));
- if (ret < 0) {
- ulogd_log(ULOGD_ERROR, "cannot set number of"
- "sctp streams: %s\n",
- strerror(errno));
- close(ii->fd);
- freeaddrinfo(resave);
- return ret;
- }
- }
-#endif
-
- if (connect(ii->fd, res->ai_addr, res->ai_addrlen) != 0) {
- close(ii->fd);
- /* try next result */
- continue;
- }
-
- /* if we reach this, we have a working connection */
- ulogd_log(ULOGD_NOTICE, "connection established\n");
- freeaddrinfo(resave);
- return 0;
- }
-
- freeaddrinfo(resave);
- return -1;
-}
-
-static int start_ipfix(struct ulogd_pluginstance *pi)
-{
- struct ipfix_instance *ii = (struct ipfix_instance *) &pi->private;
- int ret;
-
- ulogd_log(ULOGD_DEBUG, "starting ipfix\n");
-
- ii->valid_bitmask = bitmask_alloc(pi->input.num_keys);
- if (!ii->valid_bitmask)
- return -ENOMEM;
-
- INIT_LLIST_HEAD(&ii->template_list);
-
- ret = open_connect_socket(pi);
- if (ret < 0)
- goto out_bm_free;
-
- return 0;
-
-out_bm_free:
- bitmask_free(ii->valid_bitmask);
- ii->valid_bitmask = NULL;
-
- return ret;
-}
-
-static int stop_ipfix(struct ulogd_pluginstance *pi)
-{
- struct ipfix_instance *ii = (struct ipfix_instance *) &pi->private;
-
- close(ii->fd);
-
- bitmask_free(ii->valid_bitmask);
- ii->valid_bitmask = NULL;
-
- return 0;
-}
-
-static void signal_handler_ipfix(struct ulogd_pluginstance *pi, int signal)
-{
- struct ipfix_instance *li = (struct ipfix_instance *) &pi->private;
-
- switch (signal) {
- case SIGHUP:
- ulogd_log(ULOGD_NOTICE, "ipfix: reopening connection\n");
- stop_ipfix(pi);
- start_ipfix(pi);
- break;
- default:
- break;
- }
-}
-
-static int configure_ipfix(struct ulogd_pluginstance *pi,
- struct ulogd_pluginstance_stack *stack)
-{
- struct ipfix_instance *ii = (struct ipfix_instance *) &pi->private;
- char *proto_str = proto_ce(pi->config_kset).u.string;
- int ret;
-
- /* FIXME: error handling */
- ulogd_log(ULOGD_DEBUG, "parsing config file section %s\n", pi->id);
- ret = config_parse_file(pi->id, pi->config_kset);
- if (ret < 0)
- return ret;
-
- /* determine underlying protocol */
- if (!strcasecmp(proto_str, "udp")) {
- ii->sock_type = SOCK_DGRAM;
- ii->sock_proto = IPPROTO_UDP;
- } else if (!strcasecmp(proto_str, "tcp")) {
- ii->sock_type = SOCK_STREAM;
- ii->sock_proto = IPPROTO_TCP;
-#ifdef IPPROTO_SCTP
- } else if (!strcasecmp(proto_str, "sctp")) {
- ii->sock_type = SOCK_SEQPACKET;
- ii->sock_proto = IPPROTO_SCTP;
-#endif
-#ifdef _HAVE_DCCP
- } else if (!strcasecmp(proto_str, "dccp")) {
- ii->sock_type = SOCK_SEQPACKET;
- ii->sock_proto = IPPROTO_DCCP;
-#endif
- } else {
- ulogd_log(ULOGD_ERROR, "unknown protocol `%s'\n",
- proto_ce(pi->config_kset));
- return -EINVAL;
- }
-
- /* postpone address lookup to ->start() time, since we want to
- * re-lookup an address on SIGHUP */
-
- return ulogd_wildcard_inputkeys(pi);
-}
-
-static struct ulogd_plugin ipfix_plugin = {
- .name = "IPFIX",
- .input = {
- .type = ULOGD_DTYPE_PACKET | ULOGD_DTYPE_FLOW,
- },
- .output = {
- .type = ULOGD_DTYPE_SINK,
- },
- .config_kset = &ipfix_kset,
- .priv_size = sizeof(struct ipfix_instance),
-
- .configure = &configure_ipfix,
- .start = &start_ipfix,
- .stop = &stop_ipfix,
-
- .interp = &output_ipfix,
- .signal = &signal_handler_ipfix,
- .version = VERSION,
-};
-
-void __attribute__ ((constructor)) init(void);
-
-void init(void)
-{
- ulogd_register_plugin(&ipfix_plugin);
-}