/* ** 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@ */ /* * * setintersect.c * * This is an application that takes multiple set files and intersects them, * generating a set of addresses that are in all sets. Sets are * specified as 'removes' or adds, where a 'remove' file is one that * should have all of its addresses present removed, and an add file * will keep addresses that are in it. * */ #include "silk.h" RCSIDENT("$SiLK: rwsetintersect.c 6843 2007-04-10 15:19:34Z mthomas $"); #include "iptree.h" #include "utils.h" #include "sksite.h" /* LOCAL DEFINES AND TYPEDEFS */ /* where to write output from --help */ #define USAGE_FH stdout /* maximum number of add and remove files */ #define ADD_SET_LIMIT 4 #define ADD_SET_STRING "4" #define REMOVE_SET_LIMIT 4 #define REMOVE_SET_STRING "4" /* LOCAL FUNCTIONS */ static void appUsageLong(void); /* never returns */ static void appTeardown(void); static void appSetup(int argc, char **argv); /* never returns */ static int appOptionsHandler(clientData cData, int opt_index, char *opt_arg); /* LOCAL VARIABLES */ /* whether to print IPs */ static uint8_t print_ips = 0; /* how to print IPs */ static uint8_t ipFormat = SKIP_IPF_DOT; /* counts of --add and --remove sets, and the arrays to hold them */ static uint8_t add_set_count, remove_set_count; static char *add_sets[ADD_SET_LIMIT]; static char *remove_sets[REMOVE_SET_LIMIT]; /* where to write the resulting set */ static skstream_t *set_stream = NULL; /* the compression method to use when writing the file. * sksiteCompmethodOptionsRegister() will set this to the default or * to the value the user specifies. */ static sk_compmethod_t comp_method; /* OPTIONS SETUP */ typedef enum { OPT_PRINT_IPS, OPT_INTEGER_IPS, OPT_ADD_SET, OPT_REMOVE_SET, OPT_SET_FILE } appOptionsEnum; static struct option appOptions[] = { {"print-ips", NO_ARG, 0, OPT_PRINT_IPS}, {"integer-ips", NO_ARG, 0, OPT_INTEGER_IPS}, {"add-set", REQUIRED_ARG, 0, OPT_ADD_SET}, {"remove-set", REQUIRED_ARG, 0, OPT_REMOVE_SET}, {"set-file", REQUIRED_ARG, 0, OPT_SET_FILE}, {0,0,0,0} /* sentinel entry */ }; static const char *appHelp[] = { "Print IP's as dotted quad to stdout", "Print IP's as 32 bit integers to stdout", "Specify a set of IPs to use", "Specify a set of IPs to remove", "File to write resulting set to", (char *)NULL }; /* 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 \ ("--add= [options] {--print-ips | --set-file=}\n" \ "\tGenerates a new IP-set by intersecting all --add-set binary\n" \ "\tIP-set files, then removing all --remove-set binary IP-set\n" \ "\tfiles from the new IP-set. Prints the resulting IP-set to\n" \ "\tstdout and/or writes it to the specified file.\n" \ "\tSupports 1-" ADD_SET_STRING " add sets and " \ "0-" REMOVE_SET_STRING " remove sets.\n") FILE *fh = USAGE_FH; skAppStandardUsage(fh, USAGE_MSG, appOptions, appHelp); sksiteCompmethodOptionsUsage(fh); } /* * 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; if (teardownFlag) { return; } teardownFlag = 1; if (set_stream) { skStreamDestroy(&set_stream); } 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 arg_index; /* 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 */ set_stream = NULL; add_set_count = 0; remove_set_count = 0; /* register the options */ if (optionsRegister(appOptions, (optHandler)appOptionsHandler, NULL) || sksiteCompmethodOptionsRegister(&comp_method)) { skAppPrintErr("unable to register options"); exit(EXIT_FAILURE); } /* parse options */ arg_index = optionsParse(argc, argv); assert(arg_index <= argc); if (arg_index < 0) { /* optionsParse() printed the error */ skAppUsage(); /* never returns */ } /* optionsParse() handles all arguments; if any are left over, it * is an error */ if (arg_index != argc) { skAppPrintErr("Unrecognized argument '%s'", argv[arg_index]); skAppUsage(); /* never returns */ } /* verify at least one add file */ if (add_set_count == 0) { skAppPrintErr("Please specify at least one %s", appOptions[OPT_ADD_SET].name); skAppUsage(); /* never returns */ } /* verify that there is some output to produce */ if (!set_stream && !print_ips) { skAppPrintErr("Please specify the --%s or --%s switch", appOptions[OPT_PRINT_IPS].name, appOptions[OPT_SET_FILE].name); skAppUsage(); } 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_INTEGER_IPS: ipFormat = SKIP_IPF_DEC; /* FALLTHROUGH */ case OPT_PRINT_IPS: print_ips = 1; break; case OPT_SET_FILE: if (set_stream) { skAppPrintErr("The --%s switch was specified multiple times", appOptions[OPT_SET_FILE].name); return 1; } if ((rv = skStreamCreate(&set_stream, SK_IO_WRITE, SK_CONTENT_SILK)) || (rv = skStreamBind(set_stream, opt_arg))) { skStreamPrintLastErr(set_stream, rv, &skAppPrintErr); skStreamDestroy(&set_stream); } break; case OPT_ADD_SET: if (add_set_count == ADD_SET_LIMIT) { skAppPrintErr("File limit exceeded. Only %d %s allowed", ADD_SET_LIMIT, appOptions[OPT_ADD_SET].name); return -1; } add_sets[add_set_count] = opt_arg; add_set_count++; break; case OPT_REMOVE_SET: if (remove_set_count == REMOVE_SET_LIMIT) { skAppPrintErr("File limit exceeded. Only %d %s allowed", REMOVE_SET_LIMIT, appOptions[OPT_REMOVE_SET].name); return -1; } remove_sets[remove_set_count] = opt_arg; remove_set_count++; break; } return 0; /* OK */ } int main(int argc, char **argv) { int i; skIPTree_t *new_set = NULL; skIPTree_t *tmp_set = NULL; int rv; appSetup(argc, argv); /* never returns on error */ /* Read in initial --add file; appSetup should guarantee one add file */ assert(add_set_count > 0); if (skIPTreeLoad(add_sets[0], &new_set)) { return 1; } /* Process remaining --add files */ for (i = 1; i < add_set_count; i++) { skIPTreeDelete(&tmp_set); if (0 != skIPTreeLoad(add_sets[i], &tmp_set)) { return 1; } skIPTreeIntersect(new_set, tmp_set); } /* Process --remove files */ for (i = 0; i < remove_set_count; i++) { skIPTreeDelete(&tmp_set); if (0 != skIPTreeLoad(remove_sets[i], &tmp_set)) { return 1; } skIPTreeSubtract(new_set, tmp_set); } /* Do textual output */ if (print_ips) { skstream_t *s; skStreamCreate(&s, SK_IO_WRITE, SK_CONTENT_TEXT); skStreamBind(s, "stdout"); skStreamOpen(s); skIPTreePrint(s, new_set, ipFormat); skStreamDestroy(&s); } /* Do setfile output */ if (set_stream != NULL) { if ((rv = skStreamSetCompressionMethod(set_stream, comp_method)) || (rv = skStreamOpen(set_stream))) { skStreamPrintLastErr(set_stream, rv, &skAppPrintErr); return 1; } if (skIPTreeWrite(set_stream, new_set)) { skAppPrintErr("Error writing IPset to file '%s'", skStreamGetPathname(set_stream)); return 1; } if ((rv = skStreamClose(set_stream)) || (rv = skStreamDestroy(&set_stream))) { skStreamPrintLastErr(set_stream, rv, &skAppPrintErr); return 1; } } /* done */ appTeardown(); return (0); } /* ** Local Variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */