/** * \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 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; }
void post_args(_U_ int argc, _U_ char *argv[]) { char ebuf[SENDPACKET_ERRBUF_SIZE]; struct tcpr_ether_addr *eth_buff; char *intname; sendpacket_t *sp; #ifdef ENABLE_PCAP_FINDALLDEVS interface_list_t *intlist = get_interface_list(); #else interface_list_t *intlist = NULL; #endif #ifdef DEBUG if (HAVE_OPT(DBUG)) debug = OPT_VALUE_DBUG; #else if (HAVE_OPT(DBUG)) warn("not configured with --enable-debug. Debugging disabled."); #endif #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(UNIDIR)) options.unidir = 1; if (HAVE_OPT(LIMIT)) options.limit_send = OPT_VALUE_LIMIT; /* default is -1 */ if ((intname = get_interface(intlist, OPT_ARG(INTF1))) == NULL) errx(-1, "Invalid interface name/alias: %s", OPT_ARG(INTF1)); options.intf1 = safe_strdup(intname); if (HAVE_OPT(INTF2)) { if ((intname = get_interface(intlist, OPT_ARG(INTF2))) == NULL) errx(-1, "Invalid interface name/alias: %s", OPT_ARG(INTF2)); options.intf2 = safe_strdup(intname); } if (HAVE_OPT(MAC)) { int ct = STACKCT_OPT(MAC); char **list = STACKLST_OPT(MAC); int first = 1; do { char *p = *list++; if (first) mac2hex(p, (u_char *)options.intf1_mac, ETHER_ADDR_LEN); else mac2hex(p, (u_char *)options.intf2_mac, ETHER_ADDR_LEN); first = 0; } while (--ct > 0); } /* * Figure out MAC addresses of sending interface(s) * if user doesn't specify MAC address on CLI, query for it */ if (memcmp(options.intf1_mac, "\00\00\00\00\00\00", ETHER_ADDR_LEN) == 0) { if ((sp = sendpacket_open(NULL, options.intf1, ebuf, TCPR_DIR_C2S)) == NULL) errx(-1, "Unable to open interface %s: %s", options.intf1, ebuf); if ((eth_buff = sendpacket_get_hwaddr(sp)) == NULL) { warnx("Unable to get MAC address: %s", sendpacket_geterr(sp)); err(-1, "Please consult the man page for using the -M option."); } sendpacket_close(sp); memcpy(options.intf1_mac, eth_buff, ETHER_ADDR_LEN); } if (memcmp(options.intf2_mac, "\00\00\00\00\00\00", ETHER_ADDR_LEN) == 0) { if ((sp = sendpacket_open(NULL, options.intf2, ebuf, TCPR_DIR_S2C)) == NULL) errx(-1, "Unable to open interface %s: %s", options.intf2, ebuf); if ((eth_buff = sendpacket_get_hwaddr(sp)) == NULL) { warnx("Unable to get MAC address: %s", sendpacket_geterr(sp)); err(-1, "Please consult the man page for using the -M option."); } sendpacket_close(sp); memcpy(options.intf2_mac, eth_buff, ETHER_ADDR_LEN); } /* * Open interfaces for sending & receiving */ if ((options.pcap1 = pcap_open_live(options.intf1, options.snaplen, options.promisc, options.to_ms, ebuf)) == NULL) errx(-1, "Unable to open interface %s: %s", options.intf1, ebuf); if (strcmp(options.intf1, options.intf2) == 0) errx(-1, "Whoa tiger! You don't want to use %s twice!", options.intf1); /* we always have to open the other pcap handle to send, but we may not listen */ if ((options.pcap2 = pcap_open_live(options.intf2, options.snaplen, options.promisc, options.to_ms, ebuf)) == NULL) errx(-1, "Unable to open interface %s: %s", options.intf2, ebuf); /* poll should be -1 to wait indefinitely */ options.poll_timeout = -1; }
/** * \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 */ }
/** * This is the main function of the program that handles calling other * functions to implemented the needed operations of the replay functionaily. */ int main(int argc, char **argv) { unsigned int k; unsigned int num_packets=0; char port_mode[10]; /* does user specify random port generation?*/ char random_strg[7] = "random"; char* iface = argv[1]; char* new_rmac_ptr; char* new_rip_ptr; in_addr new_remoteip; struct mac_addr new_remotemac; in_addr myip; struct mac_addr mymac; /*temporary packet buffers*/ unsigned int new_src_port = 0; unsigned int retransmissions = 0; pcap_t *local_handle; char errbuf[PCAP_ERRBUF_SIZE]; char ebuf[SENDPACKET_ERRBUF_SIZE]; optionProcess(&tcpliveplayOptions, argc, argv); /*Process AutoOpts for manpage options*/ if((argc < 5) || (argv[1]==NULL) || (argv[2]==NULL) || (argv[3]==NULL) || (argv[4]==NULL) || (argv[5]==NULL)) { printf("ERROR: Incorrect Usage!\n"); printf("Usage: tcpliveplay <eth0/eth1> <file.pcap> <Destinatin IP [1.2.3.4]> <Destination mac [0a:1b:2c:3d:4e:5f]> <specify 'random' or specific port#>\n"); printf("Example:\n yhsiam@yhsiam-VirtualBox:~$ sudo tcpliveplay eth0 test1.pcap 192.168.1.4 52:57:01:11:31:92 random\n\n"); exit(0); } iface_addrs(iface, &myip, &mymac); /* Extract MAC of interface replay is being request on */ /* open send function socket*/ if ((sp = sendpacket_open(iface, ebuf, TCPR_DIR_C2S, SP_TYPE_NONE)) == NULL) errx(-1, "Can't open %s: %s", argv[1], ebuf); /* random dport vs. specified dport operation*/ strcpy(port_mode, argv[5]); /*for(int i = 0; i<10; i++) tolower(port_mode[i]);*/ if(strcmp(port_mode, random_strg)==0) { new_src_port = random_port(); } else new_src_port = atoi(argv[5]); /*else { printf("Port specification error. Please specify 'random' for random source port generation between 49152 and 65535 OR specifiy a specific source port number.\n"); return; }*/ printf("new source port:: %d\n", new_src_port); /* Establish a handler for SIGALRM signals. */ /* This is used as timeout for unresponsive remote hosts */ signal (SIGALRM, catch_alarm); /* Extract new Remote MAC & IP inputted at command line */ new_rmac_ptr= argv[4]; new_rip_ptr = argv[3]; /* These function setup the MAC & IP addresses in the mac_addr & in_addr structs */ extmac(new_rmac_ptr, &new_remotemac); extip(new_rip_ptr, &new_remoteip); /* Rewrites the given "*.pcap" file with all the new parameters and returns the number of packets */ /* that need to be replayed */ num_packets = rewrite(&new_remoteip, &new_remotemac, &myip, &mymac, argv[2], new_src_port); /* create schedule & set it up */ sched = (struct tcp_sched*) malloc(num_packets*sizeof(struct tcp_sched)); pkts_scheduled = setup_sched(sched); /* Returns number of packets in schedule*/ /* Set up the schedule struct to be relative numbers rather than absolute*/ relative_sched(sched, sched[1].exp_rseq, num_packets); printf("Packets Scheduled %d\n", pkts_scheduled); /* Open socket for savedfile traffic to be sent*/ local_handle = pcap_open_offline("newfile.pcap", errbuf); /*call pcap library function*/ if (local_handle == NULL) { fprintf(stderr,"Couldn't open pcap file %s: %s\n", "newfile.pcap", errbuf); return(2); } /* Open socket for live traffic to be listed to*/ live_handle = set_live_filter(iface, &myip, new_src_port); /* returns a pcap_t that filters out traffic other than TCP*/ if (live_handle == NULL) { fprintf(stderr,"Error occured while listing on traffic: %s\n", errbuf); return(2); } /* Printout when no packets are scheduled */ if(pkts_scheduled==0) { printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); printf("+ ERROR:: There are no TCP packets to sent +\n"); printf("+ Closing replay... +\n"); printf("+ Thank you for Playing, Play again! +\n"); printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); return ERROR; } /* Start replay by sending the first packet, the SYN, from the schedule */ else if(sched[0].local) { /* Send first packet*/ sendpacket(sp, sched[sched_index].packet_ptr, sched[sched_index].pkthdr.len, &sched[sched_index].pkthdr); printf("Sending Local Packet............... [%d]\n",sched_index+1); sched_index++; /* Proceed in the schedule */ } /* Main while loop that handles the decision making and the replay oprations */ while(sched_index<pkts_scheduled) { if(!keep_going) { /*Check the timeout variable */ printf("\n======================================================================\n"); printf("= TIMEOUT:: Remote host is not responding. You may have crashed =\n"); printf("= the host you replayed these packets against OR the packet sequence =\n"); printf("= changed since the capture was taken resulting in differing =\n"); printf("= expectations. Closing replay... =\n"); printf("======================================================================\n\n"); break; } /* tcphdr_rprev carries the last remote tcp header */ if(tcphdr_rprev == NULL) { //printf("FIRST PASS!\n"); } /* Check if received RST or RST-ACK flagged packets*/ else if((tcphdr_rprev->th_flags==TH_RST) || (tcphdr_rprev->th_flags==(TH_RST|TH_ACK))) { printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); printf("+ ERROR:: Remote host has requested to RESET the connection. +\n"); printf("+ Closing replay... +\n"); printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); break; } /*Check if received earlier FIN-ACK than expected else if((sched_index-1 < finack_rindex) && (tcphdr_rprev->th_flags==(TH_FIN|TH_ACK))){ printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); printf("+ ERROR:: Remote host sent an earlier FIN-ACK than expected. +\n"); printf("+ Closing replay... +\n"); printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); return; } */ /* Do the following if we receive a packet that ACKs for the same ACKing of next packet */ else if((tcphdr_rprev->th_seq==htonl(sched[sched_index].exp_rseq)) && (tcphdr_rprev->th_ack==htonl(sched[sched_index].exp_rack)) && (size_payload_prev>0)) { printf("Received Remote Packet............... [%d]\n",sched_index+1); printf("Skipping Packet...................... [%d] to Packet [%d]\n",sched_index+1, sched_index+2); printf("Next Remote Packet Expectation met.\nProceeding in replay...\n"); sched_index++; } /* Do the following if payload does not meet expectation and re-attempt with the remote host for 3 tries*/ else if(different_payload) { printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); printf("+ WARNING: Remote host is not meeting packet size expectations. +\n"); printf("+ for packet %-d. Application layer data differs from capture being replayed. +\n", diff_payload_index+1); printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); printf("Requesting retransmission.\n Proceeding...\n"); different_payload = false; } /* Local Packets */ if(sched[sched_index].local) { /*Reset alarm timeout*/ alarm (ALARM_TIMEOUT); printf("Sending Local Packet............... [%d]\n",sched_index+1); /* edit each packet tcphdr before sending based on the schedule*/ if(sched_index>0) { sched[sched_index].tcphdr->th_ack = htonl(sched[sched_index].curr_lack); fix_all_checksum_liveplay(sched[sched_index].iphdr); } /* If 3 attempts of resending was made, then error out to the user */ if(sched[sched_index].sent_counter==3) { printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); printf("+ ERROR: Re-sent packet [%-d] 3 times, but remote host is not +\n", sched_index+1); printf("+ responding as expected. 3 resend attempts are a maximum. +\n"); printf("+ Closing replay... +\n"); printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); break; } /* If nothing goes wrong, then send the packet scheduled to be sent, then proceed in the schedule */ sendpacket(sp, sched[sched_index].packet_ptr, sched[sched_index].pkthdr.len, &sched[sched_index].pkthdr); sched[sched_index].sent_counter++; /* Keep track of how many times this specific packet was attempted */ sched_index++; /* proceed */ } /* Remote Packets */ else if(sched[sched_index].remote) { alarm (ALARM_TIMEOUT); printf("Receiving Packets from remote host...\n"); pcap_dispatch(live_handle, 1, got_packet, NULL); /* Listen in on NIC for tcp packets */ //printf("pcap_loop returned\n"); } } /* end of main while loop*/ pcap_breakloop(live_handle); pcap_close(live_handle); sendpacket_close(sp); /* Close Send socket*/ remove("newfile.pcap"); /* Remote the rewritten file that was created*/ for(k=0; k<pkts_scheduled; k++) { retransmissions+=sched[k].sent_counter; } /* User Debug Result Printouts*/ if(sched_index==pkts_scheduled) { printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); printf("~ CONGRATS!!! You have successfully Replayed your pcap file '%s' \n", argv[2]); printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"); } else { printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); printf("~ Unfortunately an error has occurred halting the replay of \n"); printf("~ the pcap file '%s'. Please see error above for details... \n", argv[2]); printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"); } printf("----------------TCP Live Play Summary----------------\n"); printf("- Packets Scheduled to be Sent & Received: %-d \n", pkts_scheduled); printf("- Actual Packets Sent & Received: %-d \n", sched_index); printf("- Total Local Packet Re-Transmissions due to packet \n"); printf("- loss and/or differing payload size than expected: %-d \n", retransmissions); printf("- Thank you for Playing, Play again! \n"); printf("----------------------------------------------------------\n\n"); return 0; }