/** * \brief Specifies an interface to use for sending. * * You may call this up to two (2) times with different interfaces * when using a tcpprep cache file or dualfile mode. Note, both interfaces * must use the same DLT type */ int tcpreplay_set_interface(tcpreplay_t *ctx, tcpreplay_intf intf, char *value) { static int int1dlt = -1, int2dlt = -1; char *intname; char ebuf[SENDPACKET_ERRBUF_SIZE]; assert(ctx); assert(value); if (intf == intf1) { if ((intname = get_interface(ctx->intlist, value)) == NULL) { tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", value); return -1; } ctx->options->intf1_name = safe_strdup(intname); /* open interfaces for writing */ if ((ctx->intf1 = sendpacket_open(ctx->options->intf1_name, ebuf, TCPR_DIR_C2S)) == NULL) { tcpreplay_seterr(ctx, "Can't open %s: %s", ctx->options->intf1_name, ebuf); return -1; } int1dlt = sendpacket_get_dlt(ctx->intf1); } else if (intf == intf2) { if ((intname = get_interface(ctx->intlist, value)) == NULL) { tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", ctx->options->intf2_name); return -1; } ctx->options->intf2_name = safe_strdup(intname); /* open interface for writing */ if ((ctx->intf2 = sendpacket_open(ctx->options->intf2_name, ebuf, TCPR_DIR_S2C)) == NULL) { tcpreplay_seterr(ctx, "Can't open %s: %s", ctx->options->intf2_name, ebuf); return -1; } int2dlt = sendpacket_get_dlt(ctx->intf2); } /* * If both interfaces are selected, then make sure both interfaces use * the same DLT type */ if (int1dlt != -1 && int2dlt != -1) { if (int1dlt != int2dlt) { tcpreplay_seterr(ctx, "DLT type missmatch for %s (%s) and %s (%s)", ctx->options->intf1_name, pcap_datalink_val_to_name(int1dlt), ctx->options->intf2_name, pcap_datalink_val_to_name(int2dlt)); return -1; } } return 0; }
/** * \brief Add a pcap file to be sent via tcpreplay * * One or more pcap files can be added. Each file will be replayed * in order */ int tcpreplay_add_pcapfile(tcpreplay_t *ctx, char *pcap_file) { assert(ctx); assert(pcap_file); if (ctx->options->source_cnt < MAX_FILES) { ctx->options->sources[ctx->options->source_cnt].filename = safe_strdup(pcap_file); ctx->options->sources[ctx->options->source_cnt].type = source_filename; /* * prepare the cache info data struct. This doesn't actually enable * file caching for this pcap (that is controlled globally via * tcpreplay_set_file_cache()) */ ctx->options->file_cache[ctx->options->source_cnt].index = ctx->options->source_cnt; ctx->options->file_cache[ctx->options->source_cnt].cached = false; ctx->options->file_cache[ctx->options->source_cnt].packet_cache = NULL; ctx->options->source_cnt += 1; } else { tcpreplay_seterr(ctx, "Unable to add more then %u files", MAX_FILES); return -1; } return 0; }
/** * \brief sends the traffic out the interfaces * * Designed to be called in a separate thread if you need to. Blocks until * the replay is complete or you call tcpreplay_abort() in another thread. * Pass the index of the pcap you want to replay, or -1 for all pcaps. * * In dualfile mode, we will process idx and idx+1 */ int tcpreplay_replay(tcpreplay_t *ctx, int idx) { int rcode; assert(ctx); if (idx < 0 || idx > ctx->options->source_cnt) { tcpreplay_seterr(ctx, "invalid source index value: %d", idx); return -1; } if (ctx->options->dualfile && ((idx + 1) > ctx->options->source_cnt)) { tcpreplay_seterr(ctx, "invalid dualfile source index value: %d", (idx + 1)); return -1; } if (gettimeofday(&ctx->stats.start_time, NULL) < 0) { tcpreplay_seterr(ctx, "gettimeofday() failed: %s", strerror(errno)); return -1; } ctx->running = true; /* main loop, when not looping forever */ if (ctx->options->loop > 0) { while (ctx->options->loop--) { /* limited loop */ if ((rcode = tcpr_replay_index(ctx, idx)) < 0) return rcode; } } else { while (1) { /* loop forever */ if ((rcode = tcpr_replay_index(ctx, idx)) < 0) return rcode; } } ctx->running = false; return 0; }
/** * Enable verbose mode */ int tcpreplay_set_verbose(tcpreplay_t *ctx, bool value) { assert(ctx); #ifdef ENABLE_VERBOSE ctx->options->verbose = value; return 0; #else tcpreplay_seterr(ctx, "verbose mode not supported"); return -1; #endif }
/** * \brief Set the arguments to be passed to tcpdump * * Specify the additional argument to be passed to tcpdump when enabling * verbose mode. See TCPDUMP_ARGS in tcpdump.h for the default options */ int tcpreplay_set_tcpdump_args(tcpreplay_t *ctx, char *value) { assert(ctx); #ifdef ENABLE_VERBOSE assert(value); ctx->options->tcpdump_args = safe_strdup(value); return 0; #else tcpreplay_seterr(ctx, "verbose mode not supported"); return -1; #endif }
/** * \brief Set the path to the tcpdump binary * * In order to support the verbose feature, tcpreplay needs to know where * tcpdump lives */ int tcpreplay_set_tcpdump(tcpreplay_t *ctx, tcpdump_t *value) { assert(ctx); #ifdef ENABLE_VERBOSE assert(value); ctx->options->verbose = true; ctx->options->tcpdump = value; return 0; #else tcpreplay_seterr(ctx, "verbose mode not supported"); return -1; #endif }
/** * \brief Set the callback function for handing manual iteration * * Obviously for this to work, you need to first set speed_mode = speed_oneatatime * returns 0 on success, < 0 on error */ int tcpreplay_set_manual_callback(tcpreplay_t *ctx, tcpreplay_manual_callback callback) { assert(ctx); assert(callback); if (ctx->options->speed.mode != speed_oneatatime) { tcpreplay_seterr(ctx, "%s", "Unable to set manual callback because speed mode is not 'speed_oneatatime'"); return -1; } ctx->options->speed.manual_callback = callback; return 0; }
/** * \brief Specify the tcpprep cache file to use for replaying with two NICs * * Note: this only works if you have a single pcap file * returns -1 on error */ int tcpreplay_set_tcpprep_cache(tcpreplay_t *ctx, char *file) { assert(ctx); char *tcpprep_file; if (ctx->options->source_cnt > 1) { tcpreplay_seterr(ctx, "%s", "Unable to use tcpprep cache file with a single pcap file"); return -1; } tcpprep_file = safe_strdup(file); ctx->options->cache_packets = read_cache(&ctx->options->cachedata, tcpprep_file, &ctx->options->comment); free(tcpprep_file); return 0; }
/** * \brief Internal tcpreplay method to replay a given index * * This is used by tcpreplay_replay() to actually send the packets */ int tcpr_replay_index(tcpreplay_t *ctx) { int rcode = 0; int idx; assert(ctx); /* only process a single file */ if (! ctx->options->dualfile) { /* process each pcap file in order */ for (idx = 0; idx < ctx->options->source_cnt && !ctx->abort; idx++) { /* reset cache markers for each iteration */ ctx->cache_byte = 0; ctx->cache_bit = 0; switch(ctx->options->sources[idx].type) { case source_filename: rcode = replay_file(ctx, idx); break; case source_fd: rcode = replay_fd(ctx, idx); break; case source_cache: rcode = replay_cache(ctx, idx); break; default: tcpreplay_seterr(ctx, "Invalid source type: %d", ctx->options->sources[idx].type); rcode = -1; } } } /* dual file mode: two files, two interfaces */ else { /* process each pcap file in order */ for (idx = 0; idx < ctx->options->source_cnt && !ctx->abort; idx += 2) { if (ctx->options->sources[idx].type != ctx->options->sources[(idx+1)].type) { tcpreplay_seterr(ctx, "Both source indexes (%d, %d) must be of the same type", idx, (idx+1)); return -1; } switch(ctx->options->sources[idx].type) { case source_filename: rcode = replay_two_files(ctx, idx, (idx+1)); break; case source_fd: rcode = replay_two_fds(ctx, idx, (idx+1)); break; case source_cache: rcode = replay_two_caches(ctx, idx, (idx+1)); break; default: tcpreplay_seterr(ctx, "Invalid source type: %d", ctx->options->sources[idx].type); rcode = -1; } } } if (rcode < 0) { ctx->running = false; return -1; } return rcode; }
/** * \brief replay two pcap files out two interfaces * * Internal to tcpreplay, does the heavy lifting for --dualfile */ static int replay_two_files(tcpreplay_t *ctx, int idx1, int idx2) { char *path1, *path2; pcap_t *pcap1 = NULL, *pcap2 = NULL; char ebuf[PCAP_ERRBUF_SIZE]; int rcode = 0; assert(ctx); assert(ctx->options->sources[idx1].type = source_filename); assert(ctx->options->sources[idx2].type = source_filename); path1 = ctx->options->sources[idx1].filename; path2 = ctx->options->sources[idx2].filename; /* can't use stdin in dualfile mode */ if ((strncmp(path1, "-", strlen(path1)) == 0) || (strncmp(path2, "-", strlen(path2)) == 0)) { tcpreplay_seterr(ctx, "%s", "Invalid use of STDIN '-' in dual file mode"); return -1; } /* read from first pcap file if we haven't cached things yet */ if (!ctx->options->preload_pcap) { if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1); if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx2].dlt = pcap_datalink(pcap2); } else { if (!ctx->options->file_cache[idx1].cached) { if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1); } if (!ctx->options->file_cache[idx2].cached) { if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx2].dlt = pcap_datalink(pcap2); } } if (pcap1 != NULL) { #ifdef HAVE_PCAP_SNAPSHOT if (pcap_snapshot(pcap1) < 65535) { tcpreplay_setwarn(ctx, "%s was captured using a snaplen of %d bytes. This may mean you have truncated packets.", path1, pcap_snapshot(pcap1)); rcode = -2; } if (pcap_snapshot(pcap2) < 65535) { tcpreplay_setwarn(ctx, "%s was captured using a snaplen of %d bytes. This may mean you have truncated packets.", path2, pcap_snapshot(pcap2)); rcode = -2; } #endif if (ctx->intf1dlt == -1) ctx->intf1dlt = sendpacket_get_dlt(ctx->intf1); if ((ctx->intf1dlt >= 0) && (ctx->intf1dlt != pcap_datalink(pcap1))) { tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)", path1, pcap_datalink_val_to_name(pcap_datalink(pcap1)), ctx->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt)); rcode = -2; } if (ctx->intf2dlt == -1) ctx->intf2dlt = sendpacket_get_dlt(ctx->intf2); if ((ctx->intf2dlt >= 0) && (ctx->intf2dlt != pcap_datalink(pcap2))) { tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)", path2, pcap_datalink_val_to_name(pcap_datalink(pcap2)), ctx->intf2->device, pcap_datalink_val_to_name(ctx->intf2dlt)); rcode = -2; } if (ctx->intf1dlt != ctx->intf2dlt) { tcpreplay_seterr(ctx, "DLT mismatch for %s (%d) and %s (%d)", path1, ctx->intf1dlt, path2, ctx->intf2dlt); return -1; } } #ifdef ENABLE_VERBOSE if (ctx->options->verbose) { /* in cache mode, we may not have opened the file */ if (pcap1 == NULL) { if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1); } /* init tcpdump */ tcpdump_open(ctx->options->tcpdump, pcap1); } #endif send_dual_packets(ctx, pcap1, idx1, pcap2, idx2); if (pcap1 != NULL) pcap_close(pcap1); if (pcap2 != NULL) pcap_close(pcap2); #ifdef ENABLE_VERBOSE tcpdump_close(ctx->options->tcpdump); #endif return rcode; }
/** * \brief replay a pcap file out interface(s) * * Internal to tcpreplay. Does the heavy lifting. */ static int replay_file(tcpreplay_t *ctx, int idx) { char *path; pcap_t *pcap = NULL; char ebuf[PCAP_ERRBUF_SIZE]; assert(ctx); assert(ctx->options->sources[idx].type = source_filename); path = ctx->options->sources[idx].filename; /* close stdin if reading from it (needed for some OS's) */ if (strncmp(path, "-", 1) == 0) close(1); /* read from pcap file if we haven't cached things yet */ if (!ctx->options->preload_pcap) { if ((pcap = pcap_open_offline(path, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx].dlt = pcap_datalink(pcap); #ifdef HAVE_PCAP_SNAPSHOT if (pcap_snapshot(pcap) < 65535) warnx("%s was captured using a snaplen of %d bytes. This may mean you have truncated packets.", path, pcap_snapshot(pcap)); #endif } else { if (!ctx->options->file_cache[idx].cached) { if ((pcap = pcap_open_offline(path, ebuf)) == NULL) { tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx].dlt = pcap_datalink(pcap); } } #if 0 /* * this API is broken right now. This needs to be handled via a pipe or * something else so we can pass the output up to the calling programm */ #ifdef ENABLE_VERBOSE if (ctx->options->verbose) { /* in cache mode, we may not have opened the file */ if (pcap == NULL) if ((pcap = pcap_open_offline(path, ebuf)) == NULL) { tcpreplay_seterr("Error opening pcap file: %s", ebuf); return -1; } ctx->options->file_cache[idx].dlt = pcap_datalink(pcap); /* init tcpdump */ tcpdump_open(ctx->options->tcpdump, pcap); } #endif #endif if (pcap != NULL) { if (ctx->intf1dlt == -1) ctx->intf1dlt = sendpacket_get_dlt(ctx->intf1); #if 0 if ((ctx->intf1dlt >= 0) && (ctx->intf1dlt != pcap_datalink(pcap))) warnx("%s DLT (%s) does not match that of the outbound interface: %s (%s)", path, pcap_datalink_val_to_name(pcap_datalink(pcap)), ctx->options->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt)); #endif if (ctx->intf1dlt != ctx->options->file_cache[idx].dlt) tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)", path, pcap_datalink_val_to_name(pcap_datalink(pcap)), ctx->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt)); } ctx->stats.active_pcap = ctx->options->sources[idx].filename; send_packets(ctx, pcap, idx); if (pcap != NULL) pcap_close(pcap); #if 0 #ifdef ENABLE_VERBOSE tcpdump_close(ctx->options->tcpdump); #endif #endif return 0; }
/** * \brief Does all the prep work before calling tcpreplay_replay() * * Technically this validates our config options, preloads the tcpprep * cache file, loads the packet cache and anything else which might * cause a delay for starting to send packets with tcpreplay_replay() */ int tcpreplay_prepare(tcpreplay_t *ctx) { char *intname, ebuf[SENDPACKET_ERRBUF_SIZE]; int int1dlt, int2dlt, i; assert(ctx); /* * First, process the validations, basically the same we do in * tcpreplay_post_args() and AutoOpts */ if (ctx->options->intf1_name == NULL) { tcpreplay_seterr(ctx, "%s", "You must specify at least one network interface"); return -1; } if (ctx->options->source_cnt == 0) { tcpreplay_seterr(ctx, "%s", "You must specify at least one source pcap"); return -1; } if (ctx->options->dualfile) { if (! ctx->options->source_cnt >= 2) { tcpreplay_seterr(ctx, "%s", "Dual file mode requires 2 or more pcap files"); return -1; } if (ctx->options->source_cnt % 2 != 0) { tcpreplay_seterr(ctx, "%s", "Dual file mode requires an even number of pcap files"); return -1; } } if (ctx->options->dualfile && ctx->options->cachedata != NULL) { tcpreplay_seterr(ctx, "%s", "Can't use dual file mode and tcpprep cache file together"); return -1; } if ((ctx->options->dualfile || ctx->options->cachedata != NULL) && ctx->options->intf2_name == NULL) { tcpreplay_seterr(ctx, "%s", "dual file mode and tcpprep cache files require two interfaces"); } #ifndef HAVE_SELECT if (ctx->options->accurate == accurate_select) { tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with select support"); return -1; } #endif #ifndef HAVE_RDTSC if (ctx->options->accurate == accurate_rdtsc) { tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with rdtsc support"); return -1; } #else if (ctx->options->rdtsc_clicks > 0) rdtsc_calibrate(ctx->options->rdtsc_clicks); #endif #ifndef HAVE_IOPERM if (ctx->options->accurate == accurate_ioport) { tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with IO Port 0x80 support"); return -1; } #else if (ctx->options->accurate == accurate_ioport) { ioport_sleep_init(); } #endif #ifndef HAVE_ABSOLUTE_TIME if (ctx->options->accurate == accurate_abs_time) { tcpreplay_seterr(ctx, "%s", "tcpreplay_api only supports absolute time on Apple OS X"); return -1; } #endif if ((intname = get_interface(ctx->intlist, ctx->options->intf1_name)) == NULL) { tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF1)); return -1; } /* open interfaces for writing */ if ((ctx->intf1 = sendpacket_open(ctx->options->intf1_name, ebuf, TCPR_DIR_C2S)) == NULL) { tcpreplay_seterr(ctx, "Can't open %s: %s", ctx->options->intf1_name, ebuf); return -1; } int1dlt = sendpacket_get_dlt(ctx->intf1); if (ctx->options->intf2_name != NULL) { if ((intname = get_interface(ctx->intlist, ctx->options->intf2_name)) == NULL) { tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF2)); return -1; } /* open interfaces for writing */ if ((ctx->intf2 = sendpacket_open(ctx->options->intf2_name, ebuf, TCPR_DIR_C2S)) == NULL) { tcpreplay_seterr(ctx, "Can't open %s: %s", ctx->options->intf2_name, ebuf); return -1; } int2dlt = sendpacket_get_dlt(ctx->intf2); if (int2dlt != int1dlt) { tcpreplay_seterr(ctx, "DLT type missmatch for %s (%s) and %s (%s)", ctx->options->intf1_name, pcap_datalink_val_to_name(int1dlt), ctx->options->intf2_name, pcap_datalink_val_to_name(int2dlt)); return -1; } } /* * Setup up the file cache, if required */ if (ctx->options->enable_file_cache && ctx->options->file_cache == NULL) { /* Initialise each of the file cache structures */ for (i = 0; i < ctx->options->source_cnt; i++) { ctx->options->file_cache[i].index = i; ctx->options->file_cache[i].cached = FALSE; ctx->options->file_cache[i].packet_cache = NULL; } } return 0; }
/** * \brief Parses the GNU AutoOpts options for tcpreplay * * If you're using AutoOpts with tcpreplay_api, then just call this after * optionProcess() and it will parse all the options for you. As always, * returns 0 on success, and -1 on error & -2 on warning. */ int tcpreplay_post_args(tcpreplay_t *ctx, int argc) { char *temp, *intname; char ebuf[SENDPACKET_ERRBUF_SIZE]; int int1dlt, int2dlt; tcpreplay_opt_t *options; int warn = 0; #ifdef USE_AUTOOPTS options = ctx->options; #ifdef DEBUG if (HAVE_OPT(DBUG)) debug = OPT_VALUE_DBUG; #else if (HAVE_OPT(DBUG)) { warn ++; tcpreplay_setwarn(ctx, "%s", "not configured with --enable-debug. Debugging disabled."); } #endif options->loop = OPT_VALUE_LOOP; options->sleep_accel = OPT_VALUE_SLEEP_ACCEL; if (HAVE_OPT(LIMIT)) options->limit_send = OPT_VALUE_LIMIT; if (HAVE_OPT(TOPSPEED)) { options->speed.mode = speed_topspeed; options->speed.speed = 0.0; } else if (HAVE_OPT(PPS)) { options->speed.mode = speed_packetrate; options->speed.speed = (float)OPT_VALUE_PPS; options->speed.pps_multi = OPT_VALUE_PPS_MULTI; } else if (HAVE_OPT(ONEATATIME)) { options->speed.mode = speed_oneatatime; options->speed.speed = 0.0; } else if (HAVE_OPT(MBPS)) { options->speed.mode = speed_mbpsrate; options->speed.speed = atof(OPT_ARG(MBPS)); } else if (HAVE_OPT(MULTIPLIER)) { options->speed.mode = speed_multiplier; options->speed.speed = atof(OPT_ARG(MULTIPLIER)); } #ifdef ENABLE_VERBOSE if (HAVE_OPT(VERBOSE)) options->verbose = 1; if (HAVE_OPT(DECODE)) options->tcpdump->args = safe_strdup(OPT_ARG(DECODE)); #endif if (HAVE_OPT(STATS)) options->stats = OPT_VALUE_STATS; /* * Check if the file cache should be enabled - if we're looping more than * once and the command line option has been spec'd */ if (HAVE_OPT(ENABLE_FILE_CACHE) && (options->loop != 1)) { options->enable_file_cache = true; } /* * If we're preloading the pcap before the first run, then * we're forcing the file cache to be true */ if (HAVE_OPT(PRELOAD_PCAP)) { options->preload_pcap = true; options->enable_file_cache = true; } /* Dual file mode */ if (HAVE_OPT(DUALFILE)) { options->dualfile = true; if (argc < 2) { tcpreplay_seterr(ctx, "%s", "--dualfile mode requires at least two pcap files"); return -1; } if (argc % 2 != 0) { tcpreplay_seterr(ctx, "%s", "--dualfile mode requires an even number of pcap files"); return -1; } } if (HAVE_OPT(TIMER)) { if (strcmp(OPT_ARG(TIMER), "select") == 0) { #ifdef HAVE_SELECT options->accurate = accurate_select; #else tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with select support"); return -1; #endif } else if (strcmp(OPT_ARG(TIMER), "rdtsc") == 0) { #ifdef HAVE_RDTSC options->accurate = accurate_rdtsc; #else tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with rdtsc support"); return -1; #endif } else if (strcmp(OPT_ARG(TIMER), "ioport") == 0) { #if defined HAVE_IOPERM && defined(__i386__) options->accurate = accurate_ioport; ioport_sleep_init(); #else tcpreplay_seterr(ctx, "%s", "tcpreplay_api not compiled with IO Port 0x80 support"); return -1; #endif } else if (strcmp(OPT_ARG(TIMER), "gtod") == 0) { options->accurate = accurate_gtod; } else if (strcmp(OPT_ARG(TIMER), "nano") == 0) { options->accurate = accurate_nanosleep; } else if (strcmp(OPT_ARG(TIMER), "abstime") == 0) { #ifdef HAVE_ABSOLUTE_TIME options->accurate = accurate_abs_time; if (!MPLibraryIsLoaded()) { tcpreplay_seterr(ctx, "%s", "The MP library did not load.\n"); return -1; } #else tcpreplay_seterr(ctx, "%s", "tcpreplay_api only supports absolute time on Apple OS X"); return -1; #endif } else { tcpreplay_seterr(ctx, "Unsupported timer mode: %s", OPT_ARG(TIMER)); return -1; } } #ifdef HAVE_RDTSC if (HAVE_OPT(RDTSC_CLICKS)) { rdtsc_calibrate(OPT_VALUE_RDTSC_CLICKS); } #endif if (HAVE_OPT(PKTLEN)) { options->use_pkthdr_len = true; warn ++; tcpreplay_setwarn(ctx, "%s", "--pktlen may cause problems. Use with caution."); } if ((intname = get_interface(ctx->intlist, OPT_ARG(INTF1))) == NULL) { tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF1)); return -1; } options->intf1_name = safe_strdup(intname); /* open interfaces for writing */ if ((ctx->intf1 = sendpacket_open(options->intf1_name, ebuf, TCPR_DIR_C2S)) == NULL) { tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf1_name, ebuf); return -1; } int1dlt = sendpacket_get_dlt(ctx->intf1); if (HAVE_OPT(INTF2)) { if ((intname = get_interface(ctx->intlist, OPT_ARG(INTF2))) == NULL) { tcpreplay_seterr(ctx, "Invalid interface name/alias: %s", OPT_ARG(INTF2)); return -1; } options->intf2_name = safe_strdup(intname); /* open interface for writing */ if ((ctx->intf2 = sendpacket_open(options->intf2_name, ebuf, TCPR_DIR_S2C)) == NULL) { tcpreplay_seterr(ctx, "Can't open %s: %s", options->intf2_name, ebuf); } int2dlt = sendpacket_get_dlt(ctx->intf2); if (int2dlt != int1dlt) { tcpreplay_seterr(ctx, "DLT type missmatch for %s (%s) and %s (%s)", options->intf1_name, pcap_datalink_val_to_name(int1dlt), options->intf2_name, pcap_datalink_val_to_name(int2dlt)); return -1; } } if (HAVE_OPT(CACHEFILE)) { temp = safe_strdup(OPT_ARG(CACHEFILE)); options->cache_packets = read_cache(&options->cachedata, temp, &options->comment); safe_free(temp); } /* return -2 on warnings */ if (warn > 0) return -2; return 0; #else tcpreplay_seterr(ctx, "autopts support not compiled in. tcpreplay_post_args() not supported"); return -1; #endif /* USE_AUTOOPTS */ }