/* ** Copyright (C) 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@ */ /* ** ipfix2rw.c ** ** IPFIX to SiLK translation filter application ** ** Authors: Brian Trammell ** */ #include "silk.h" RCSIDENT("$SiLK: rwipfix2silk.c 6918 2007-04-16 18:37:21Z mthomas $"); #include "skipfix.h" /* LOCAL DEFINES AND TYPEDEFS */ /* where to write --help output */ #define USAGE_FH stdout /* where to write --print-stat output */ #define STATS_FH stderr /* LOCAL VARIABLE DEFINITIONS */ /* index into argv for looping over input */ static int arg_index; /* the SiLK flow file to write */ static rwIOStruct_t *silk_output = NULL; /* whether to print statistics */ static int print_statistics = 0; /* OPTIONS SETUP */ typedef enum { OPT_SILK_OUTPUT, OPT_PRINT_STATISTICS } appOptionsEnum; static struct option appOptions[] = { {"silk-output", REQUIRED_ARG, 0, OPT_SILK_OUTPUT}, {"print-statistics", NO_ARG, 0, OPT_PRINT_STATISTICS}, {0,0,0,0} /* sentinel entry */ }; static const char *appHelp[] = { ("Write the SiLK Flow records to the specified path.\n\tDef. stdout"), "Print the count of processed records. Def. No.", (char *)NULL }; /* LOCAL FUNCTION PROTOTYPES */ static void appUsageLong(void); static void appTeardown(void); static void appSetup(int argc, char **argv); static int appOptionsHandler(clientData cData, int opt_index, char *opt_arg); /* FUNCTION DEFINITIONS */ /* * appUsageLong(); * * Print complete usage information to USAGE_FH. Pass this * function to skOptionsSetUsageCallback(); optionsParse() will * call this funciton and then exit the program when the --help * option is given. */ static void appUsageLong(void) { #define USAGE_MSG \ ("[SWITCHES] [IPFIX_FILES]\n" \ "\tReads IPFIX records from files named on the command line or from\n" \ "\tthe standard input, converts them to the SiLK format, and writes\n" \ "\tthe SiLK records to the named file or to the standard output.\n") FILE *fh = USAGE_FH; skAppStandardUsage(fh, USAGE_MSG, appOptions, appHelp); } /* * appTeardown() * * Teardown all modules, close all files, and tidy up all * application state. * * This function is idempotent. */ static void appTeardown(void) { static int teardownFlag = 0; int rv; if (teardownFlag) { return; } teardownFlag = 1; /* close SiLK flow output file */ if (silk_output) { rv = rwioClose(silk_output); if (rv) { rwioPrintLastErr(silk_output, rv, &skAppPrintErr); } rwioDestroy(&silk_output); } skAppUnregister(); } /* * appSetup(argc, argv); * * Perform all the setup for this application include setting up * required modules, parsing options, etc. This function should be * passed the same arguments that were passed into main(). * * Returns to the caller if all setup succeeds. If anything fails, * this function will cause the application to exit with a FAILURE * exit status. */ static void appSetup(int argc, char **argv) { int rv; /* verify same number of options and help strings */ assert((sizeof(appHelp)/sizeof(char *)) == (sizeof(appOptions)/sizeof(struct option))); /* register the application */ skAppRegister(argv[0]); skOptionsSetUsageCallback(&appUsageLong); /* register the options */ if (optionsRegister(appOptions, (optHandler)appOptionsHandler, NULL)) { skAppPrintErr("unable to register options"); exit(EXIT_FAILURE); } /* parse the options */ arg_index = optionsParse(argc, argv); if (arg_index < 0) { /* options parsing should print error */ skAppUsage(); /* never returns */ } /* arg_index is looking at first file name to process */ if (arg_index == argc) { if (FILEIsATty(stdin)) { skAppPrintErr("No input files on command line and" " stdin is connected to a terminal"); skAppUsage(); /* never returns */ } } /* default output is "stdout" */ if (!silk_output) { rv = rwioCreate(&silk_output, "stdout", SK_RWIO_WRITE); if (rv) { rwioPrintLastErr(silk_output, rv, &skAppPrintErr); exit(EXIT_FAILURE); } } /* open the output */ rv = rwioOpen(silk_output); if (rv) { rwioPrintLastErr(silk_output, rv, &skAppPrintErr); exit(EXIT_FAILURE); } if (atexit(appTeardown) < 0) { skAppPrintErr("unable to register appTeardown() with atexit()"); appTeardown(); exit(EXIT_FAILURE); } return; /* OK */ } /* * status = appOptionsHandler(cData, opt_index, opt_arg); * * This function is passed to optionsRegister(); it will be called * by optionsParse() for each user-specified switch that the * application has registered; it should handle the switch as * required---typically by setting global variables---and return 1 * if the switch processing failed or 0 if it succeeded. Returning * a non-zero from from the handler causes optionsParse() to return * a negative value. * * The clientData in 'cData' is typically ignored; 'opt_index' is * the index number that was specified as the last value for each * struct option in appOptions[]; 'opt_arg' is the user's argument * to the switch for options that have a REQUIRED_ARG or an * OPTIONAL_ARG. */ static int appOptionsHandler( clientData UNUSED(cData), int opt_index, char *opt_arg) { int rv; switch ((appOptionsEnum)opt_index) { case OPT_SILK_OUTPUT: if (silk_output) { skAppPrintErr("--%s specified multiple times", appOptions[opt_index].name); return 1; } rv = rwioCreate(&silk_output, opt_arg, SK_RWIO_WRITE); if (rv) { rwioPrintLastErr(silk_output, rv, &skAppPrintErr); exit(EXIT_FAILURE); } break; case OPT_PRINT_STATISTICS: print_statistics = 1; break; } return 0; /* OK */ } /* * ok = appNextInput(argc, argv, &fpath, &fp); * * Open the next input file from the command line or the standard * input if no files were given on the command line. Return the * name of the file in 'fpath' and the opened file pointer in 'fp'. * * Return 0 on success, 1 if no more files, and -1 on error. */ static int appNextInput(int argc, char **argv, const char **fpath, FILE **fp) { static int initialized = 0; const char *fname = NULL; if (arg_index < argc) { /* get current file and prepare to get next */ fname = argv[arg_index]; ++arg_index; } else if (initialized) { /* no more input */ return 1; } else { /* input is from stdin */ *fpath = "stdin"; *fp = stdin; initialized = 1; return 0; } initialized = 1; /* open file */ *fp = fopen(fname, "rb"); if (*fp == NULL) { skAppPrintSyserror("unable to open file '%s'", fname); return -1; } *fpath = fname; return 0; } int main(int argc, char **argv) { fBuf_t *fbuf = NULL; GError *err = NULL; const char *ipfix_path; FILE *ipfix_in; rwRec rec, revRec; uint64_t fwd_count = 0; uint64_t rev_count = 0; int rv; appSetup(argc, argv); /* never returns on error */ /* initialize the rwrec */ memset(&rec, 0, sizeof(rwRec)); memset(&revRec, 0, sizeof(rwRec)); /* loop over all input */ while ((rv = appNextInput(argc, argv, &ipfix_path, &ipfix_in)) == 0) { /* Create IPFIX buffer for reading */ if (!(fbuf = skiCreateReadBufferForFP(ipfix_in, &err))) { skAppPrintErr("Couldn't open %s for IPFIX: %s", ipfix_path, err->message); exit(EXIT_FAILURE); } /* read IPFIX and write RW */ while (skiRwNextRecord(fbuf, &rec, &revRec, &err)) { rv = rwioWriteRecord(silk_output, &rec); if (rv) { rwioPrintLastErr(silk_output, rv, &skAppPrintErr); exit(EXIT_FAILURE); } ++fwd_count; if (revRec.bytes && revRec.pkts) { rv = rwioWriteRecord(silk_output, &revRec); if (rv) { rwioPrintLastErr(silk_output, rv, &skAppPrintErr); exit(EXIT_FAILURE); } ++rev_count; } } /* Handle EOF condition---a normal error */ if ( !g_error_matches(err, FB_ERROR_DOMAIN, FB_ERROR_EOF)) { skAppPrintErr("Couldn't read IPFIX record from %s: %s", ipfix_path, err->message); exit(EXIT_FAILURE); } } if (rv == -1) { exit(EXIT_FAILURE); } if (print_statistics) { fprintf(STATS_FH, ("%s: Wrote %" PRIu64 " records" " (%" PRIu64 " forward %" PRIu64 " reverse)" " to '%s'\n"), skAppName(), (fwd_count + rev_count), fwd_count, rev_count, rwGetFileName(silk_output)); } appTeardown(); return 0; } /* ** Local Variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */