/* ** 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@ */ /* * buildset * * Build an IP Set from textual data. */ #include "silk.h" RCSIDENT("$SiLK: rwsetbuild.c 6081 2007-01-22 19:25:22Z mthomas $"); #include "iptree.h" #include "skstream.h" #include "sksite.h" /* LOCAL DEFINES AND TYPEDEFS */ /* where to write output from --help */ #define USAGE_FH stdout /* LOCAL FUNCTIONS */ 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); /* LOCAL VARIABLES */ /* the IPset the application creates. */ static skIPTree_t *ipset = NULL; /* input and output streams */ static skstream_t *input_stream = NULL; static skstream_t *output_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 { ** } appOptionsEnum; */ static struct option appOptions[] = { {0,0,0,0} /* sentinel entry */ }; static const char *appHelp[] = { (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 \ (" \n" \ "\tReads IP addresses in dotted-quad or CIDR notation from input-file\n" \ "\tand writes a binary IPset file to output-file. Use \"stdin\" as\n" \ "\tthe input-file to read the IPs from the standard input, and use\n" \ "\t\"stdout\" as the output-file to write the IPset to the standard\n" \ "\toutput when the standard output is not a terminal.\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 (ipset) { skIPTreeDelete(&ipset); } skStreamDestroy(&input_stream); skStreamDestroy(&output_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; const char *input_fname; const char *output_fname; 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) || sksiteCompmethodOptionsRegister(&comp_method)) { skAppPrintErr("unable to register options"); exit(EXIT_FAILURE); } /* parse the options */ arg_index = optionsParse(argc, argv); if (arg_index < 0) { skAppUsage(); /* never returns */ } /* get name of input file */ if (arg_index == argc) { skAppPrintErr("missing input and output file names"); skAppUsage(); } input_fname = argv[arg_index]; ++arg_index; /* get name of output file */ if (arg_index == argc) { skAppPrintErr("missing output file name"); skAppUsage(); } output_fname = argv[arg_index]; ++arg_index; /* check for extra arguments */ if (arg_index != argc) { skAppPrintErr("too many arguments or unrecognized switch '%s'", argv[arg_index]); skAppUsage(); } /* create tree */ if (skIPTreeCreate(&ipset)) { skAppPrintErr("Error allocating memory for IPset."); exit(EXIT_FAILURE); } /* open input */ if ((rv = skStreamCreate(&input_stream, SK_IO_READ, SK_CONTENT_TEXT)) || (rv = skStreamBind(input_stream, input_fname)) || (rv = skStreamSetCommentStart(input_stream, "#")) || (rv = skStreamOpen(input_stream))) { skStreamPrintLastErr(input_stream, rv, &skAppPrintErr); skStreamDestroy(&input_stream); exit(EXIT_FAILURE); } /* open output */ if ((rv = skStreamCreate(&output_stream, SK_IO_WRITE, SK_CONTENT_SILK)) || (rv = skStreamBind(output_stream, output_fname)) || (rv = skStreamSetCompressionMethod(output_stream, comp_method)) || (rv = skStreamOpen(output_stream))) { skStreamPrintLastErr(output_stream, rv, &skAppPrintErr); skStreamDestroy(&output_stream); exit(EXIT_FAILURE); } if (atexit(appTeardown) < 0) { skAppPrintErr("unable to register appTeardown() with atexit()"); appTeardown(); exit(EXIT_FAILURE); } return; } /* * 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 UNUSED(opt_index), char UNUSED(*opt_arg)) { return 0; } /* * buildIPTreeFromStream(input_stream); * * Read IP addresses from the stream named by 'input_stream' and use * them to build the global IP Tree ipset. Return 0 on success or * -1 on failure. */ static int buildIPTreeFromStream(skstream_t *in_stream) { int lc = 0; char line_buf[256]; skOctetMapIterator_t iter; skOctetMap_t octetmap; uint32_t ip; int rv; /* read until end of file */ while ((rv = skStreamGetLine(in_stream, line_buf, sizeof(line_buf), &lc)) != SKSTREAM_ERR_EOF) { switch (rv) { case SKSTREAM_OK: /* good, we got our line */ break; case SKSTREAM_ERR_LONG_LINE: /* bad: line was longer than sizeof(line_buf) */ skAppPrintErr("input line %d too long. ignored", lc); continue; default: /* unexpected error */ skStreamPrintLastErr(in_stream, rv, &skAppPrintErr); goto END; } /* parse the line: fill in octet_bitmap */ rv = skStringParseWildcardIP(&octetmap, line_buf); if (rv < 0) { /* error */ skAppPrintErr("Error in line %d: %s\n", lc, line_buf); goto END; } skOctetMapIteratorInitialize(&iter, &octetmap); while (skOctetMapIteratorNext(&ip, &iter) == SK_ITERATOR_OK) { skIPTreeAddAddress(ip, ipset); } } /* success */ rv = 0; END: if (rv != 0) { return -1; } return 0; } int main(int argc, char **argv) { appSetup(argc, argv); /* read input file */ if (buildIPTreeFromStream(input_stream)) { return -1; } /* write output to stream */ if (skIPTreeWrite(output_stream, ipset)) { return -1; } skStreamDestroy(&input_stream); skStreamDestroy(&output_stream); /* done */ return 0; } /* ** Local variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */