/* ** Copyright (C) 2006, 2007 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** A "plug-in" (currently compile-time only) for rwflowpack to ** process IPFIX records from the network. ** */ #include "silk.h" RCSIDENT("$SiLK: ipfixreader.c 6836 2007-04-09 19:31:31Z mwd $"); #include "utils.h" #include "rwpack.h" #include "sklog.h" #include "ipfixsource.h" #include "rwflowpack.h" #include "probeconf.h" /* MACROS and DATA TYPES */ #define READER_TYPE_NAME "IPFIX Reader" /* Number of IPFIX records, used to create buffer for reading */ /* Should handle over 30 seconds of data */ #define IPFIX_BUFFER_SIZE 60000 /* PRIVATE FUNCTIONS */ static int readerSetup( fp_daemon_mode_t *is_daemon, const sk_vector_t *probe_vec, reader_options_t *options); static void readerTeardown(void); static int readerStart(flow_proc_t *fproc); static int readerStop(flow_proc_t *fproc); static fp_get_record_result_t readerGetRecord( rwRec *out_rec, const probe_def_t **out_probe, flow_proc_t *fproc); static int readerWantProbe(probe_def_t *probe); /* FUNCTION DEFINITIONS */ /* * readerTeardown(); * * Destroy the IPFIX reader. * * Invoked by reader_type->teardown_fn(); */ static void readerTeardown(void) { /* nothing to do */ } /* * readerStart() * * Create a flowsource object that will read IPFIX records from a * TCP connection. * * Invoked by reader_type->start_fn(); */ static int readerStart(flow_proc_t *fproc) { ipfixSource_t ipfix_src; in_addr_t addr; uint16_t port; probe_proto_t protocol; int rv; char buf[SK_NUM2DOT_STRLEN]; /* if a ipfix_src already exists, just return. */ if (fproc->flow_src != NULL) { return 0; } rv = skProbeGetListenAsHost(&addr, &port, fproc->probe); if (rv != 0) { skAppPrintErr("Could not determine IP address and port for IPFIX."); logMsg("Could not determine IP address and port for IPFIX."); return -1; } protocol = skProbeGetProtocol(fproc->probe); if (protocol == PROBE_PROTO_UNSET) { skAppPrintErr("Unknown protocol for IPFIX listener on %s:%d", buf, port); logMsg("Unknown protocol for IPFIX listener on %s:%d", buf, port); return -1; } ipfix_src = ipfixSourceCreate(port, addr, protocol, IPFIX_BUFFER_SIZE, &logMsg); if (ipfix_src) { /* success. return */ fproc->flow_src = ipfix_src; return 0; } /* failed. print error */ num2dot_r(addr, buf); skAppPrintErr("Could not create IPFIX listener on %s:%d", buf, port); logMsg("Could not create IPFIX listener on %s:%d", buf, port); return -1; } /* * readerStop(); * * Stop reading records. * * Invoked by reader_type->stop_fn(); */ static int readerStop(flow_proc_t *fproc) { ipfixSource_t ipfix_src = (ipfixSource_t)fproc->flow_src; if (ipfix_src) { ipfixSourceDestroy(ipfix_src); fproc->flow_src = NULL; } return 0; } /* * readerGetRecord(&out_rwrec, &out_probe); * * Fill 'out_rwrec' with an rw generic record from the underlying * flowsource object connected to a socket. Fill 'out_probe' with * the probe where the flow was collected. * * Invoked by reader_type->get_record_fn(); */ static fp_get_record_result_t readerGetRecord( rwRec *out_rwrec, const probe_def_t **out_probe, flow_proc_t *fproc) { ipfixSource_t ipfix_src = (ipfixSource_t)fproc->flow_src; if (-1 == ipfixSourceGetGeneric(ipfix_src, out_rwrec)) { return FP_GET_ERROR; } *out_probe = fproc->probe; /* When reading from a socket, any point is a valid stopping * point */ return FP_BREAK_POINT; } /* * ipfixReaderInitialize: * * Set initial state of this flow reader. Register its options. * * Invoked by reader_type->initialize_fn(); */ int ipfixReaderInitialize(reader_type_t *reader_type) { /* Set my name */ reader_type->reader_name = READER_TYPE_NAME; /* Set function pointers */ reader_type->setup_fn = &readerSetup; reader_type->teardown_fn = &readerTeardown; reader_type->start_fn = &readerStart; reader_type->stop_fn = &readerStop; reader_type->get_record_fn = &readerGetRecord; reader_type->want_probe_fn = &readerWantProbe; return 0; } /* * yes_or_no = readerWantProbe(probe); * * Return a TRUE value this reader_type is able to process the data * from the 'probe'; return a FALSE value otherwise. */ static int readerWantProbe(probe_def_t *probe) { in_addr_t addr; uint16_t port; /* This is what we expect: a socket based IPFIX listener */ if ((-1 != skProbeGetListenAsHost(&addr, &port, probe)) && (PROBE_ENUM_IPFIX == skProbeGetType(probe))) { return 1; } return 0; } /* * status = readerSetup(&out_daemon_mode, probe_vector, options); * * The reader_type should do any setup it requires prior to * starting its flow_processor instances: Validate and/or store the * reader_type's 'options'. 'probe_vector' is the list of probes * that this reader_type said it would process * (readerWantProbe). 'out_daemon_mode' should be set according * to how this reader_type expects to run. * * Invoked by reader_type->setup_fn(); */ static int readerSetup( fp_daemon_mode_t *is_daemon, const sk_vector_t *probe_vec, reader_options_t UNUSED(*options)) { /* this function should only be called if we actually have probes * to process */ if (0 == skVectorGetCount(probe_vec)) { return 1; } /* We are a daemon */ *is_daemon = FP_DAEMON_ON; return 0; }