/* ** Copyright (C) 2001-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@ */ /* ** rwtotalutils.c ** ** */ #include "silk.h" RCSIDENT("$SiLK: rwtotalutils.c 8269 2007-08-03 18:54:48Z mthomas $"); #include "rwtotal.h" /* LOCAL DEFINES AND TYPEDEFS */ /* where to write --help output */ #define USAGE_FH stdout /* Values to use for appOptions and option_to_count_mode[]. * option_to_count_mode[] depends on the order of IDs here; keep them * in sync!! */ typedef enum { OPT_SIP_8=0, OPT_SIP_16, OPT_SIP_24, OPT_SIP_L8, OPT_SIP_L16, OPT_DIP_8, OPT_DIP_16, OPT_DIP_24, OPT_DIP_L8, OPT_DIP_L16, OPT_SPORT, OPT_DPORT, OPT_PROTO, OPT_PACKETS, OPT_BYTES, OPT_DURATION, OPT_ICMPCODE, /* above map to count-modes; below control output */ OPT_SKIP_ZEROES, OPT_NO_TITLES, OPT_NO_COLUMNS, OPT_COLUMN_SEPARATOR, OPT_DELIMITED, OPT_PRINT_FILENAMES, OPT_COPY_INPUT, OPT_OUTPUT_PATH, OPT_PAGER } appOptionsEnum; /* a mapping from appOptionsEnum to the countMode, totalRecs, & * destFlag. */ typedef struct { int count_mode; uint32_t total_recs; int dest_flag; } option_mode_t; /* LOCAL FUNCTIONS */ static void appUsageLong(void); static int appOptionsHandler(clientData cData, int opt_index, char *opt_arg); /* LOCAL VARIABLES */ /* a mapping from appOptionsEnum to the countMode, totalRecs, & * destFlag. This depends on ordering in appOptionsEnum!! */ static option_mode_t option_to_count_mode[] = { /* OPT_SIP_8 */ {RWTO_COPT_ADD8, (1 << 8), 0}, /* OPT_SIP_16 */ {RWTO_COPT_ADD16, (1 << 16), 0}, /* OPT_SIP_24 */ {RWTO_COPT_ADD24, (1 << 24), 0}, /* OPT_SIP_L8 */ {RWTO_COPT_LADD8, (1 << 8), 0}, /* OPT_SIP_L16 */ {RWTO_COPT_LADD16, (1 << 16), 0}, /* OPT_DIP_8 */ {RWTO_COPT_ADD8, (1 << 8), 1}, /* OPT_DIP_16 */ {RWTO_COPT_ADD16, (1 << 16), 1}, /* OPT_DIP_24 */ {RWTO_COPT_ADD24, (1 << 24), 1}, /* OPT_DIP_L8 */ {RWTO_COPT_LADD8, (1 << 8), 1}, /* OPT_DIP_L16 */ {RWTO_COPT_LADD16, (1 << 16), 1}, /* OPT_SPORT */ {RWTO_COPT_PORT, (1 << 16), 0}, /* OPT_DPORT */ {RWTO_COPT_PORT, (1 << 16), 1}, /* OPT_PROTO */ {RWTO_COPT_PROTO, (1 << 8), 0}, /* OPT_PACKETS */ {RWTO_COPT_PACKETS, (1 << 24), 0}, /* OPT_BYTES */ {RWTO_COPT_BYTES, (1 << 24), 0}, /* OPT_DURATION */ {RWTO_COPT_DURATION, 4096, 0}, /* OPT_ICMPCODE */ {RWTO_COPT_ICMP, (1 << 16), 0}, }; /* OPTIONS SETUP */ static struct option appOptions[] = { {"sip-first-8", NO_ARG, 0, OPT_SIP_8}, {"sip-first-16", NO_ARG, 0, OPT_SIP_16}, {"sip-first-24", NO_ARG, 0, OPT_SIP_24}, {"sip-last-8", NO_ARG, 0, OPT_SIP_L8}, {"sip-last-16", NO_ARG, 0, OPT_SIP_L16}, {"dip-first-8", NO_ARG, 0, OPT_DIP_8}, {"dip-first-16", NO_ARG, 0, OPT_DIP_16}, {"dip-first-24", NO_ARG, 0, OPT_DIP_24}, {"dip-last-8", NO_ARG, 0, OPT_DIP_L8}, {"dip-last-16", NO_ARG, 0, OPT_DIP_L16}, {"sport", NO_ARG, 0, OPT_SPORT}, {"dport", NO_ARG, 0, OPT_DPORT}, {"proto", NO_ARG, 0, OPT_PROTO}, {"packets", NO_ARG, 0, OPT_PACKETS}, {"bytes", NO_ARG, 0, OPT_BYTES}, {"duration", NO_ARG, 0, OPT_DURATION}, {"icmp-code", NO_ARG, 0, OPT_ICMPCODE}, {"skip-zeroes", NO_ARG, 0, OPT_SKIP_ZEROES}, {"no-titles", NO_ARG, 0, OPT_NO_TITLES}, {"no-columns", NO_ARG, 0, OPT_NO_COLUMNS}, {"column-separator", REQUIRED_ARG, 0, OPT_COLUMN_SEPARATOR}, {"delimited", OPTIONAL_ARG, 0, OPT_DELIMITED}, {"print-filenames", NO_ARG, 0, OPT_PRINT_FILENAMES}, {"copy-input", REQUIRED_ARG, 0, OPT_COPY_INPUT}, {"output-path", REQUIRED_ARG, 0, OPT_OUTPUT_PATH}, {"pager", REQUIRED_ARG, 0, OPT_PAGER}, {0,0,0,0} /* sentinel entry */ }; static char *appHelp[] = { "Key on the first 8 bits of the source IP address", "Key on the first 16 bits of the source IP address", "Key on the first 24 bits of the source IP address", "Key on the last 8 bits of the source IP address", "Key on the last 16 bits of the source IP address", "Key on the first 8 bits of the destination IP address", "Key on the first 16 bits of the destination IP address", "Key on the first 24 bits of the destination IP address", "Key on the last 8 bits of the destination IP address", "Key on the last 16 bits of the destination IP address", "Key on the source port", "Key on the destination port", "Key on the protocol", "Key on the number of packets", "Key on the number of bytes", "Key on duration", ("Key on icmp type and code (DOES NOT check to see\n" "\t if the record is ICMP)\n" "\nSWITCHES:"), "Do not print bins that have zero flows. Def. Print all", "Do not print column titles. Def. Print titles", "Disable fixed-width columnar output. Def. Columnar", "Use specified character between columns. Def. '|'", "Shortcut for --no-columns --column-sep=CHAR", "Print names of input files as they are opened. Def. No", "Copy all input SiLK Flows to given pipe or file. Def. No", "Send output to given file path. Def. stdout", "Program to invoke to page output. Def. $SILK_PAGER or $PAGER", (char *)NULL }; /* * DO NOT PRINT THE FOLLOWING * * These let --delimeted replace --delimiter, without forcing the use * to fulling type the switch name; and therefore will not breaking * any existing scripts. */ static struct option legacyOptions[] = { {"de", OPTIONAL_ARG, 0, OPT_DELIMITED}, {"del", OPTIONAL_ARG, 0, OPT_DELIMITED}, {"deli", OPTIONAL_ARG, 0, OPT_DELIMITED}, {"delim", OPTIONAL_ARG, 0, OPT_DELIMITED}, {"delimi", OPTIONAL_ARG, 0, OPT_DELIMITED}, {"delimit", OPTIONAL_ARG, 0, OPT_DELIMITED}, {"delimite", OPTIONAL_ARG, 0, OPT_DELIMITED}, {"delimiter", REQUIRED_ARG, 0, OPT_COLUMN_SEPARATOR}, {0,0,0,0} /* sentinel entry */ }; /* 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] [FILES]\n" \ "\tSummarize SiLK Flow records by a specified key and print the byte,\n" \ "\tpacket, and flow counts for flows matching the key. When no files\n" \ "\tare given on the command line, flows are read from STDIN.\n") FILE *fh = USAGE_FH; int i; fprintf(fh, "%s %s", skAppName(), USAGE_MSG); fprintf(fh, "\nKEY:\n"); for (i = 0; appOptions[i].name; ++i) { if (appOptions[i].val == OPT_SKIP_ZEROES) { /* insert standard options after the "key" and before the * other "switches" */ skOptionsDefaultUsage(fh); sksiteOptionsUsage(fh); } fprintf(fh, "--%s %s. %s\n", appOptions[i].name, SK_OPTION_HAS_ARG(appOptions[i]), appHelp[i]); } } /* * appTeardown() * * Teardown all modules, close all files, and tidy up all * application state. * * This function is idempotent. */ void appTeardown(void) { static uint8_t teardownFlag = 0; if (teardownFlag) { return; } teardownFlag = 1; /* free our RAM */ if (countRecs) { free(countRecs); } /* close the output-path */ if (ioISP->passCount && ioISP->passFD[0] && ioISP->passFD[0] != stdout) { if (ioISP->passIsPipe[0]) { if (-1 == pclose(ioISP->passFD[0])) { skAppPrintErr("Error closing output pipe %s", ioISP->passFPath[0]); } } else { if (EOF == fclose(ioISP->passFD[0])) { skAppPrintSyserror("Error closing output file %s", ioISP->passFPath[0]); } } ioISP->passFD[0] = NULL; } iochecksTeardown(ioISP); 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. */ void appSetup(int argc, char **argv) { /* 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); /* initialize variables */ countMode = RWTO_NONE; skip_zeroes = 0; /* Create input/output checker */ ioISP = iochecksSetup(1, 0, argc, argv); /* register the options */ if (optionsRegister(appOptions, (optHandler)appOptionsHandler, NULL) || optionsRegister(legacyOptions, (optHandler)appOptionsHandler, NULL) || sksiteOptionsRegister(SK_SITE_FLAG_CONFIG_FILE)) { skAppPrintErr("unable to register options"); exit(EXIT_FAILURE); } /* parse options */ ioISP->firstFile = optionsParse(argc, argv); if (ioISP->firstFile < 0) { skAppUsage(); /* never returns */ } /* try to load site config file; if it fails, we will not be able * to resolve flowtype and sensor from input file names */ sksiteConfigure(0); /* make certain we have something to count */ if(countMode == RWTO_NONE) { skAppPrintErr("No key specified,\n" "\t Please choose a summarization key.\n"); skAppUsage(); } /* Use STDIN as an input stream if it is not a TTY; make certain * we have some input and we are either reading from STDIN or * using files listed the command line, but not both. */ if (iochecksAcceptFromStdin(ioISP) || iochecksInputs(ioISP, 0)) { skAppUsage(); } /* if no destination was specified, use stdout */ if ((0 == ioISP->passCount) && iochecksPassDestinations(ioISP, "stdout", 1)) { exit(EXIT_FAILURE); } /* looks good, open the --copy-input destination */ if (iochecksOpenCopyDest(ioISP)) { 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); * * Called by optionsParse(), this handles a user-specified switch * that the application has registered, typically by setting global * variables. Returns 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) { /* handle the switches that set the key/count-mode */ if (opt_index < (int)(sizeof(option_to_count_mode)/sizeof(option_mode_t))){ if (countMode != RWTO_NONE) { skAppPrintErr("Only one summarization key may be specified"); return 1; } countMode = option_to_count_mode[opt_index].count_mode; totalRecs = option_to_count_mode[opt_index].total_recs; destFlag = option_to_count_mode[opt_index].dest_flag; return 0; } switch (opt_index) { case OPT_SKIP_ZEROES: skip_zeroes = 1; break; case OPT_NO_TITLES: no_titles = 1; break; case OPT_NO_COLUMNS: no_columns = 1; break; case OPT_COLUMN_SEPARATOR: delimiter = opt_arg[0]; break; case OPT_DELIMITED: no_columns = 1; if (opt_arg) { delimiter = opt_arg[0]; } break; case OPT_PRINT_FILENAMES: print_filenames = 1; break; case OPT_COPY_INPUT: if (iochecksAllDestinations(ioISP, opt_arg)) { return 1; } break; case OPT_OUTPUT_PATH: if (iochecksPassDestinations(ioISP, opt_arg, 1)) { return 1; } break; case OPT_PAGER: pager = opt_arg; break; default: skAppPrintErr("Unhandled option %d in options handler at %s:%d", opt_index, __FILE__, __LINE__); exit(EXIT_FAILURE); } /* switch */ return 0; /* OK */ } /* ** Local Variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */