/* ** 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@ */ #include "silk.h" RCSIDENT("$SiLK: rwipaexport.c 7494 2007-06-13 14:58:02Z mthomas $"); #include "rwipa.h" /* LOCAL DEFINES AND TYPEDEFS */ /* where to write output from --help */ #define USAGE_FH stdout /* 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 */ /* Name of the IPA catalog to export from */ static char *catalog_name = NULL; /* Date/time string specifying the time to search for in the catalog */ static char *export_time_str = NULL; struct timeval export_time; /* index of first option that is not handled by the options handler. */ static int arg_index = 0; /* OPTIONS SETUP */ typedef enum { OPT_CATALOG_NAME, OPT_EXPORT_TIME } appOptionsEnum; static struct option appOptions[] = { {"catalog", REQUIRED_ARG, 0, OPT_CATALOG_NAME}, {"time", REQUIRED_ARG, 0, OPT_EXPORT_TIME}, {0, 0, 0, 0} /* sentinel entry */ }; static const char *appHelp[] = { "Export data from the named IPA catalog", ("Export data that was active at the specified time;\n" "\tspecify the time in YYYY/MM/DD[:HH[:MM[:SS]]] format. Def. None"), (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 \ ("--catalog=CATALOG [SWITCHES] OUTPUT_FILE\n" \ "\tExport an existing IP Address Association (IPA) catalog to the\n" \ "\tspecified OUTPUT_FILE. The output will be in the same format\n" \ "\tthat was imported, that is, a SiLK IPSet, Bag, or Prefix Map.\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; if (teardownFlag) { return; } teardownFlag = 1; 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) { /* 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 options */ arg_index = optionsParse(argc, argv); assert(arg_index <= argc); if (arg_index < 0) { /* optionsParse() printed the error */ skAppUsage(); /* never returns */ } /* need name of target file */ if ((arg_index == argc)) { skAppPrintErr("No destination file name provided on command line."); skAppUsage(); } /* A catalog name must be specified */ if (catalog_name == NULL) { skAppPrintErr("You must specify a catalog name with the --%s option", appOptions[OPT_CATALOG_NAME].name); skAppUsage(); } /* A time is optional */ if (export_time_str != NULL) { if (skStringParseDatetime(&export_time, export_time_str, NULL)) { skAppPrintErr("Error parsing --%s argument '%s'", appOptions[OPT_EXPORT_TIME].name, export_time_str); 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) { switch ((appOptionsEnum) opt_index) { case OPT_CATALOG_NAME: catalog_name = opt_arg; break; case OPT_EXPORT_TIME: export_time_str = opt_arg; break; } return 0; /* OK */ } static int export_set(IPAContext *ipa, const char *filename) { skIPTree_t *set = NULL; skOctetMapIterator_t iter; skOctetMap_t octetmap; char *range = NULL; char *value = NULL; int rv; uint32_t ipaddr; /* create IPset */ if (skIPTreeCreate(&set)) { skAppPrintErr("Error allocating memory for IPset."); rv = -1; goto done; } /* Get IPs from IPA and add to the IPset */ while (!ipa_get_range(ipa, &range, &value)) { skOctetMapIteratorInitialize(&iter, &octetmap); rv = skStringParseWildcardIP(&octetmap, range); if (rv < 0) { /* error */ skAppPrintErr("Error parsing IP string %s\n", range); free(range); free(value); rv = -1; goto done; } while (skOctetMapIteratorNext(&ipaddr, &iter) == SK_ITERATOR_OK) { skIPTreeAddAddress(ipaddr, set); } free(range); free(value); } if ((rv = skIPTreeSave(filename, set)) != SKIP_OK) { skAppPrintErr("Error writing IPset to file '%s'", filename); rv = -1; goto done; } /* Success */ rv = 0; done: skIPTreeDelete(&set); return rv; } static int export_bag(IPAContext *ipa, const char *filename) { int rv = 0; char *range = NULL; char *value = NULL; skBag_header_t *bag = NULL; skOctetMapIterator_t iter; skOctetMap_t octetmap; skBag_key_t ipaddr; skBag_counter_t bagval; skstream_t *bag_stream = NULL; /* Create new bag */ if (skBag_create(&bag) != SKBAG_OK) { skAppPrintErr("Error allocating bag"); rv = -1; goto done; } /* Get IP-value pairs from IPA and add to the Bag */ while (!ipa_get_range(ipa, &range, &value)) { bagval = strtoull(value, NULL, 10); skOctetMapIteratorInitialize(&iter, &octetmap); rv = skStringParseWildcardIP(&octetmap, range); if (rv < 0) { /* error */ skAppPrintErr("Error parsing IP string %s\n", range); free(range); free(value); rv = -1; goto done; } while (skOctetMapIteratorNext(&ipaddr, &iter) == SK_ITERATOR_OK) { if ((rv = skBag_addToCounter(bag, &ipaddr, &bagval)) != SKBAG_OK) { skAppPrintErr("Error setting value on bag: %s", skBag_strerror(rv)); rv = -1; goto done; } } free(range); free(value); } /* write output */ if ((rv = skStreamCreate(&bag_stream, SK_IO_WRITE, SK_CONTENT_SILK)) || (rv = skStreamBind(bag_stream, filename)) || (rv = skStreamOpen(bag_stream))) { skStreamPrintLastErr(bag_stream, rv, &skAppPrintErr); rv = -1; goto done; } if (skBag_writeBinary(bag, bag_stream) != SKBAG_OK) { skAppPrintErr("Error writing Bag to %s", skStreamGetPathname(bag_stream)); rv = -1; goto done; } if (skStreamClose(bag_stream)) { skStreamPrintLastErr(bag_stream, rv, &skAppPrintErr); rv = -1; goto done; } /* Success */ rv = 0; done: if (bag_stream) { skStreamDestroy(&bag_stream); } if (bag) { skBag_free(bag); } return rv; } static int export_pmap(IPAContext *ipa, const char *filename) { char *range = NULL; char *value = NULL; int rv; skstream_t *pmap_text_stream = NULL; /* Create the output stream */ if ((rv = skStreamCreate(&pmap_text_stream, SK_IO_WRITE, SK_CONTENT_TEXT)) || (rv = skStreamBind(pmap_text_stream, filename)) || (rv = skStreamOpen(pmap_text_stream))) { skStreamPrintLastErr(pmap_text_stream, rv, &skAppPrintErr); exit(EXIT_FAILURE); } while (!ipa_get_range(ipa, &range, &value)) { skStreamPrint(pmap_text_stream, "%s%s %s\n", range, ( ( strchr(range, '/') || strchr(range, '-')) ? "" : "/32"), value); free(range); free(value); } if (skStreamClose(pmap_text_stream)) { skStreamPrintLastErr(pmap_text_stream, rv, &skAppPrintErr); } skStreamDestroy(&pmap_text_stream); return 0; } int main(int argc, char **argv) { const char *filename = NULL; int rv = 1; char *ipa_db_url = NULL; IPAContext *ipa; appSetup(argc, argv); /* never returns on error */ filename = argv[arg_index]; ipa_db_url = get_ipa_config(); if (ipa_db_url == NULL) { skAppPrintErr("Could not get IPA configuration"); rv = EXIT_FAILURE; goto done; } ipa_create_context(&ipa, ipa_db_url); if (ipa == NULL) { skAppPrintErr("Could not create IPA context"); rv = EXIT_FAILURE; goto done; } rv = ipa_get_dataset(ipa, catalog_name, export_time.tv_sec); switch (rv) { case IPA_OK: break; case IPA_ERR_NOTFOUND: skAppPrintErr("Dataset not found for given name and time"); goto done; default: skAppPrintErr("IPA error retrieving dataset"); goto done; } switch (ipa->cat_type) { case IPA_CAT_SET: rv = export_set(ipa, filename); break; case IPA_CAT_BAG: rv = export_bag(ipa, filename); break; case IPA_CAT_PMAP: rv = export_pmap(ipa, filename); break; default: skAppPrintErr("Unsupported catalog type (%d)", ipa->cat_type); rv = -1; goto done; } done: appTeardown(); return rv; } /* ** Local Variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */