123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- /* $Id$ */
- /*
- * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- * Copyright (c) 2013-2024 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 "defines.h"
- #include "config.h"
- #include "common.h"
- #include "send_packets.h"
- #include "tcpreplay_api.h"
- #include <string.h>
- static int replay_file(tcpreplay_t *ctx, int idx);
- static int replay_two_files(tcpreplay_t *ctx, int idx1, int idx2);
- static int replay_cache(tcpreplay_t *ctx, int idx);
- static int replay_two_caches(tcpreplay_t *ctx, int idx1, int idx2);
- static int replay_fd(tcpreplay_t *ctx, int idx);
- static int replay_two_fds(tcpreplay_t *ctx, int idx1, int idx2);
- /**
- * \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 */
- 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 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;
- /* read from pcap file if we haven't cached things yet */
- if (!ctx->options->preload_pcap) {
- if ((pcap = tcpr_pcap_open(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 = tcpr_pcap_open(path, ebuf)) == NULL) {
- tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
- return -1;
- }
- ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);
- }
- }
- #ifdef ENABLE_VERBOSE
- if (ctx->options->verbose) {
- /* in cache mode, we may not have opened the file */
- if (pcap == NULL)
- if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL) {
- tcpreplay_seterr(ctx, "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
- 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);
- #ifdef ENABLE_VERBOSE
- tcpdump_close(ctx->options->tcpdump);
- #endif
- return 0;
- }
- /**
- * \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 = tcpr_pcap_open(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 = tcpr_pcap_open(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 = tcpr_pcap_open(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 = tcpr_pcap_open(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 = tcpr_pcap_open(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 index using existing memory cache
- *
- * FIXME
- */
- static int
- replay_cache(tcpreplay_t *ctx, int idx)
- {
- assert(ctx);
- assert(ctx->options->sources[idx].type == source_cache);
- return 0;
- }
- /**
- * \brief Replay two indexes using existing memory cache
- *
- * FIXME
- */
- static int
- replay_two_caches(tcpreplay_t *ctx, int idx1, int idx2)
- {
- assert(ctx);
- assert(ctx->options->sources[idx1].type == source_cache);
- assert(ctx->options->sources[idx2].type == source_cache);
- return 0;
- }
- /**
- * \brief Replay index which is a file descriptor
- *
- * FIXME
- */
- static int
- replay_fd(tcpreplay_t *ctx, int idx)
- {
- assert(ctx);
- assert(ctx->options->sources[idx].type == source_fd);
- return 0;
- }
- /**
- * \brief Replay two indexes which are a file descriptor
- *
- * FIXME
- */
- static int
- replay_two_fds(tcpreplay_t *ctx, int idx1, int idx2)
- {
- assert(ctx);
- assert(ctx->options->sources[idx1].type == source_fd);
- assert(ctx->options->sources[idx2].type == source_fd);
- return 0;
- }
|