123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- /* $Id$ */
- /*
- * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- * Copyright (c) 2013-2018 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
- *
- * The Tcpreplay Suite of tools is free software: you can redistribute it
- * and/or modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or with the authors permission any later version.
- *
- * The Tcpreplay Suite is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "config.h"
- #include "defines.h"
- #include "common.h"
- #include <ctype.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <errno.h>
- #include <stdarg.h>
- #include "tcpprep_api.h"
- #include "tcpprep_opts.h"
- extern void print_comment(const char *);
- extern void print_info(const char *);
- extern void print_stats(const char *);
- /**
- * \brief Initialize a new tcpprep context
- *
- * Allocates memory and stuff like that. Always returns a buffer or completely
- * fails by calling exit() on malloc failure.
- */
- tcpprep_t *
- tcpprep_init()
- {
- tcpprep_t *ctx;
- int i;
- ctx = safe_malloc(sizeof(tcpprep_t));
- ctx->options = safe_malloc(sizeof(tcpprep_opt_t));
- ctx->options->bpf.optimize = BPF_OPTIMIZE;
- for (i = DEFAULT_LOW_SERVER_PORT; i <= DEFAULT_HIGH_SERVER_PORT; i++) {
- ctx->options->services.tcp[i] = 1;
- ctx->options->services.udp[i] = 1;
- }
- return ctx;
- }
- /**
- * Closes & free's all memory related to a tcpprep context
- */
- void
- tcpprep_close(tcpprep_t *ctx)
- {
- tcpr_cache_t *cache, *cache_nxt;
- tcpr_cidr_t *cidr, *cidr_nxt;
- tcpprep_opt_t *options;
- assert(ctx);
- options = ctx->options;
- if (options->pcap != NULL)
- pcap_close(options->pcap);
- #ifdef ENABLE_VERBOSE
- safe_free(options->tcpdump_args);
- #endif
- safe_free(options->comment);
- safe_free(options->maclist);
- cache = options->cachedata;
- while (cache != NULL) {
- cache_nxt = cache->next;
- safe_free(cache);
- cache = cache_nxt;
- }
- cidr = options->cidrdata;
- while (cidr != NULL) {
- cidr_nxt = cidr->next;
- safe_free(cidr);
- cidr = cidr_nxt;
- }
- safe_free(options);
- safe_free(ctx->outfile);
- safe_free(ctx->pcapfile);
- safe_free(ctx);
- }
- /**
- * Specify the pcap file to process
- */
- int
- tcpprep_set_pcap_file(tcpprep_t *ctx, char *value)
- {
- assert(ctx);
- assert(value);
- ctx->pcapfile = safe_strdup(value);
- return 0;
- }
- /**
- * Specify the tcpprep cache file to generate
- */
- int
- tcpprep_set_output_file(tcpprep_t *ctx, char *value)
- {
- assert(ctx);
- assert(value);
- ctx->outfile = safe_strdup(value);
- return 0;
- }
- /**
- * Specify a cache file comment
- */
- int
- tcpprep_set_comment(tcpprep_t *ctx, char *value)
- {
- assert(ctx);
- assert(value);
- ctx->options->comment = safe_strdup(value);
- return 0;
- }
- /**
- * \brief Disable comments in the tcpprep cachefile
- *
- * Indicate that there should not be any comment or option info
- * embedded in the generated tcpprep cache file
- */
- int
- tcpprep_set_nocomment(tcpprep_t *ctx, bool value)
- {
- assert(ctx);
- ctx->options->nocomment = value;
- return 0;
- }
- /**
- * Specify the tcpprep main mode
- */
- int
- tcpprep_set_mode(tcpprep_t *ctx, tcpprep_mode_t value)
- {
- assert(ctx);
- ctx->options->mode = value;
- return 0;
- }
- /**
- * Specify the submode for automode
- */
- int
- tcpprep_set_automode(tcpprep_t *ctx, tcpprep_mode_t value)
- {
- assert(ctx);
- ctx->options->automode = value;
- return 0;
- }
- /**
- * Set the minimum CIDR mask length for auto modes
- */
- int
- tcpprep_set_min_mask(tcpprep_t *ctx, int value)
- {
- assert(ctx);
- ctx->options->min_mask = value;
- return 0;
- }
- /**
- * Set the maximum CIDR mask length for auto modes
- */
- int
- tcpprep_set_max_mask(tcpprep_t *ctx, int value)
- {
- assert(ctx);
- ctx->options->max_mask = value;
- return 0;
- }
- /**
- * Set the client/server ratio for auto modes
- */
- int
- tcpprep_set_ratio(tcpprep_t *ctx, double value)
- {
- assert(ctx);
- ctx->options->ratio = value;
- return 0;
- }
- /**
- * Specify the regex for regex mode
- */
- int
- tcpprep_set_regex(tcpprep_t *ctx, char *value)
- {
- int regex_error;
- assert(ctx);
- if ((regex_error = regcomp(&ctx->options->preg, value,
- REG_EXTENDED|REG_NOSUB))) {
- char ebuf[EBUF_SIZE];
- regerror(regex_error, &ctx->options->preg, ebuf, EBUF_SIZE);
- tcpprep_seterr(ctx, "Unable to compile regex (%s): %s", value, regex_error);
- return -1;
- }
- return 0;
- }
- /**
- * Override default: Send all non-IP traffic out the secondary interface
- */
- int
- tcpprep_set_nonip_is_secondary(tcpprep_t *ctx, bool value)
- {
- assert(ctx);
- ctx->options->nonip = value;
- return 0;
- }
- #ifdef ENABLE_VERBOSE
- /**
- * Enable verbose (tcpdump)
- */
- int
- tcpprep_set_verbose(tcpprep_t *ctx, bool value)
- {
- assert(ctx);
- ctx->options->verbose = value;
- return 0;
- }
- /**
- * Specify tcpdump args for verbose = ON
- */
- int
- tcpprep_set_tcpdump_args(tcpprep_t *ctx, char *value)
- {
- assert(ctx);
- ctx->options->tcpdump_args = safe_strdup(value);
- return 0;
- }
- /**
- * Specify path to tcpdump binary
- */
- int
- tcpprep_set_tcpdump(tcpprep_t *ctx, tcpdump_t *value)
- {
- assert(ctx);
- memcpy(&ctx->tcpdump, value, sizeof(tcpdump_t));
- return 0;
- }
- #endif
- /**
- * \brief Returns a string describing the last error.
- *
- * Value when the last call does not result in an error is undefined
- * (may be NULL, may be garbage)
- */
- char *
- tcpprep_geterr(tcpprep_t *ctx)
- {
- assert(ctx);
- return(ctx->errstr);
- }
- /**
- * \brief Returns a string describing the last warning.
- *
- * Value when the last call does not result in an warning is undefined
- * (may be NULL, may be garbage)
- */
- char *
- tcpprep_getwarn(tcpprep_t *ctx)
- {
- assert(ctx);
- return(ctx->warnstr);
- }
- /**
- * \brief Internal function to set the tcpprep error string
- *
- * Used to set the error string when there is an error, result is retrieved
- * using tcpedit_geterr(). You shouldn't ever actually call this, but use
- * tcpreplay_seterr() which is a macro wrapping this instead.
- */
- void
- __tcpprep_seterr(tcpprep_t *ctx, const char *func, const int line,
- const char *file, const char *fmt, ...)
- {
- va_list ap;
- char errormsg[TCPREPLAY_ERRSTR_LEN];
- assert(ctx);
- va_start(ap, fmt);
- if (fmt != NULL) {
- (void)vsnprintf(errormsg,
- (TCPREPLAY_ERRSTR_LEN - 1), fmt, ap);
- }
- va_end(ap);
- snprintf(ctx->errstr, (TCPREPLAY_ERRSTR_LEN -1), "From %s:%s() line %d:\n%s",
- file, func, line, errormsg);
- }
- /**
- * \brief Internal function to set the tcpedit warning string
- *
- * Used to set the warning string when there is an non-fatal issue, result is
- * retrieved using tcpedit_getwarn().
- */
- void
- tcpprep_setwarn(tcpprep_t *ctx, const char *fmt, ...)
- {
- va_list ap;
- assert(ctx);
- va_start(ap, fmt);
- if (fmt != NULL)
- (void)vsnprintf(ctx->warnstr, (TCPREPLAY_ERRSTR_LEN - 1), fmt, ap);
- va_end(ap);
- }
- /**
- * \brief When using AutoOpts, call to do post argument processing
- * Used to process the autoopts arguments
- */
- int
- tcpprep_post_args(tcpprep_t *ctx, int argc, char *argv[])
- {
- char myargs[MYARGS_LEN];
- int bufsize;
- char *tempstr;
- memset(myargs, 0, MYARGS_LEN);
- /* print_comment and print_info don't return */
- if (HAVE_OPT(PRINT_COMMENT))
- print_comment(OPT_ARG(PRINT_COMMENT));
- if (HAVE_OPT(PRINT_INFO))
- print_info(OPT_ARG(PRINT_INFO));
- if (HAVE_OPT(PRINT_STATS))
- print_stats(OPT_ARG(PRINT_STATS));
- if (! HAVE_OPT(CACHEFILE) && ! HAVE_OPT(PCAP))
- err(-1, "Must specify an output cachefile (-o) and input pcap (-i)");
- if (! ctx->options->mode)
- err(-1, "Must specify a processing mode: -a, -c, -r, -p");
- #ifdef DEBUG
- if (HAVE_OPT(DBUG))
- debug = OPT_VALUE_DBUG;
- #endif
- #ifdef ENABLE_VERBOSE
- if (HAVE_OPT(VERBOSE)) {
- ctx->options->verbose = 1;
- }
- if (HAVE_OPT(DECODE))
- ctx->tcpdump.args = safe_strdup(OPT_ARG(DECODE));
- #endif
- /*
- * if we are to include the cli args, then prep it for the
- * cache file header
- */
- if (! ctx->options->nocomment) {
- int i;
- /* copy all of our args to myargs */
- for (i = 1; i < argc; i ++) {
- /* skip the -C <comment> */
- if (strcmp(argv[i], "-C") == 0) {
- i += 2;
- continue;
- }
- strlcat(myargs, argv[i], MYARGS_LEN);
- strlcat(myargs, " ", MYARGS_LEN);
- }
- /* remove trailing space */
- myargs[strlen(myargs) - 1] = 0;
- dbgx(1, "Comment args length: %zu", strlen(myargs));
- }
- /* setup or options.comment buffer so that that we get args\ncomment */
- if (ctx->options->comment != NULL) {
- strlcat(myargs, "\n", MYARGS_LEN);
- bufsize = strlen(ctx->options->comment) + strlen(myargs) + 1;
- ctx->options->comment = (char *)safe_realloc(ctx->options->comment,
- bufsize);
- tempstr = strdup(ctx->options->comment);
- strlcpy(ctx->options->comment, myargs, bufsize);
- strlcat(ctx->options->comment, tempstr, bufsize);
- safe_free(tempstr);
- } else {
- bufsize = strlen(myargs) + 1;
- ctx->options->comment = (char *)safe_malloc(bufsize);
- strlcpy(ctx->options->comment, myargs, bufsize);
- }
- dbgx(1, "Final comment length: %zu", strlen(ctx->options->comment));
- /* copy over our min/max mask */
- ctx->options->min_mask = OPT_VALUE_MINMASK;
- ctx->options->max_mask = OPT_VALUE_MAXMASK;
- if (!(ctx->options->min_mask > ctx->options->max_mask))
- errx(-1, "Min network mask len (%d) must be less then max network mask len (%d)",
- ctx->options->min_mask, ctx->options->max_mask);
- ctx->options->ratio = atof(OPT_ARG(RATIO));
- if (ctx->options->ratio < 0)
- err(-1, "Ratio must be a non-negative number.");
- return 0;
- }
|