Browse Source

Import upstream version 1.0.1

Dug Song 25 years ago
commit
bd9528e255
16 changed files with 2676 additions and 0 deletions
  1. 14 0
      CHANGES
  2. 20 0
      CREDITS
  3. 15 0
      CVS/Entries
  4. 1 0
      CVS/Repository
  5. 1 0
      CVS/Root
  6. 45 0
      INSTALL
  7. 29 0
      LICENSE
  8. 59 0
      Makefile.in
  9. 54 0
      README
  10. 1 0
      VERSION
  11. 13 0
      config.h.in
  12. 1653 0
      configure
  13. 35 0
      configure.in
  14. 250 0
      install-sh
  15. 91 0
      tcpreplay.8
  16. 395 0
      tcpreplay.c

+ 14 - 0
CHANGES

@@ -0,0 +1,14 @@
+$Id: CHANGES,v 1.3 1999/05/19 20:05:01 dugsong Exp $
+
+v1.0.1 Wed May 19 16:03:38 EDT 1999
+
+- Added Solaris support.
+
+v1.0 Thu May 13 11:05:04 EDT 1999
+
+- Public release.
+
+v0.1b Wed May  5 10:06:07 EDT 1999
+
+- Initial release.
+

+ 20 - 0
CREDITS

@@ -0,0 +1,20 @@
+
+Tcpreplay author:
+
+   Matt Undy <mundy@anzen.com>
+
+Tcpreplay includes code from libnet and libpcap:
+
+   LBNL Network Research Group <libpcap@ee.lbl.gov>
+   ftp://ftp.ee.lbl.gov/libpcap.tar.Z
+
+   Mike D. Schiffman <mike@infonexus.com>
+   route|daemon9 <route@infonexus.com>
+   http://www.packetfactory.net/libnet
+
+Additional contributors:
+
+   None so far!
+
+---
+$Id: CREDITS,v 1.2 1999/05/13 15:02:10 dugsong Exp $

+ 15 - 0
CVS/Entries

@@ -0,0 +1,15 @@
+/CREDITS/1.2/Thu May 13 15:02:10 1999//
+/INSTALL/1.3/Thu May 13 15:02:10 1999//
+/LICENSE/1.2/Fri Apr 23 20:05:47 1999//
+/Makefile.in/1.5/Wed Apr 21 22:16:41 1999//
+/config.h.in/1.2/Wed Apr 21 22:16:41 1999//
+/install-sh/1.1/Tue Apr 20 19:41:49 1999//
+/tcpreplay.8/1.4/Wed May  5 13:16:55 1999//
+D/Libnet-0.99////
+D/libpcap-0.4////
+/CHANGES/1.3/Wed May 19 20:05:01 1999//
+/README/1.5/Wed May 19 20:05:01 1999//
+/VERSION/1.4/Wed May 19 20:00:42 1999//
+/configure/1.3/Wed May 19 19:55:31 1999//
+/configure.in/1.3/Wed May 19 19:55:28 1999//
+/tcpreplay.c/1.18/Wed May 19 20:00:35 1999//

+ 1 - 0
CVS/Repository

@@ -0,0 +1 @@
+/usr/anzen/src/nidsbench/nidsbench/tcpreplay

+ 1 - 0
CVS/Root

@@ -0,0 +1 @@
+/usr/anzen/src/nidsbench

+ 45 - 0
INSTALL

@@ -0,0 +1,45 @@
+
+Building tcpreplay
+-------------------
+
+To build tcpreplay on a supported platform:
+
+	% ./configure ; make
+
+If you get it to work on a platform not listed above, please let us
+know!
+
+Installing tcpreplay
+---------------------
+
+To install tcpreplay, as root:
+
+	# make install
+
+This will install the tcpreplay binary and man page (by default,
+/usr/local/sbin/tcpreplay and /usr/local/man/man8/tcpreplay.8).
+
+On BSD-based systems, kernel modifications are required to correctly
+forge outgoing Ethernet source MACs. See the libnet documentation for
+details on how to do this.
+
+Running tcpreplay
+------------------
+
+See the tcpreplay manpage for details.
+
+Known Problems
+--------------
+
+Tcpreplay can only replay traffic as fast as your hardware allows. If
+you find you can't hit that 80 Mbps traffic rate you want, build a
+faster machine (disk I/O seems to account for a lot of the overhead).
+
+Troubleshooting
+---------------
+
+Trouble? What trouble? :-)
+
+
+---
+$Id: INSTALL,v 1.3 1999/05/13 15:02:10 dugsong Exp $

+ 29 - 0
LICENSE

@@ -0,0 +1,29 @@
+Copyright (c) 1999 Anzen Computing. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+      This product includes software developed by Anzen Computing, Inc.
+4. Neither the name of Anzen Computing, Inc. nor the names of its
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 59 - 0
Makefile.in

@@ -0,0 +1,59 @@
+# Makefile for tcpreplay.
+#
+# dugsong@anzen.com
+
+PREFIX		= @prefix@
+SBINDIR		= $(PREFIX)/sbin
+MANDIR		= $(PREFIX)/man/man8
+
+CC		= @CC@
+CFLAGS		= @CFLAGS@
+LDFLAGS		= @LDFLAGS@
+DEFS		= @DEFS@
+INCS		= $(LNETINCS) $(PCAPINCS)
+LIBS		= @LIBS@ $(LNETLIBS) $(PCAPLIBS)
+
+INSTALL		= @INSTALL@
+INSTALL_PROGRAM	= @INSTALL_PROGRAM@
+
+PCAPDIR		= libpcap-0.4
+PCAPINCS	= -I$(PCAPDIR)
+PCAPLIBS	= -L$(PCAPDIR) -lpcap
+PCAPDEP		= $(PCAPDIR)/pcap.h $(PCAPDIR)/libpcap.a
+
+LNETDIR		= Libnet-0.99
+LNETINCS	= -I$(LNETDIR)/include
+LNETLIBS	= -L$(LNETDIR)/lib -lnet
+LNETDEP		= $(LNETDIR)/include/libnet.h $(LNETDIR)/libnet.a
+
+PROGRAMS	= tcpreplay
+
+all: $(PROGRAMS)
+
+tcpreplay: $(PCAPDEP) $(LNETDEP) tcpreplay.c
+	-rm -f tcpreplay
+	$(CC) $(CFLAGS) $(DEFS) $(INCS) -o $@ tcpreplay.c $(LDFLAGS) $(LIBS)
+
+$(PCAPDIR)/libpcap.a:
+	cd $(PCAPDIR) ; $(MAKE)
+
+$(LNETDIR)/libnet.a:
+	cd $(LNETDIR) ; $(MAKE)
+
+clean:
+	cd $(PCAPDIR) ; $(MAKE) clean
+	cd $(LNETDIR) ; $(MAKE) clean
+	rm -f *~ *.o *core $(PROGRAMS)
+
+distclean: clean
+	cd $(PCAPDIR) ; $(MAKE) distclean
+	cd $(LNETDIR) ; $(MAKE) distclean
+	rm -f Makefile config.h config.status config.cache config.log
+
+install: 
+	$(INSTALL_PROGRAM) -m 755 tcpreplay $(SBINDIR)
+	$(INSTALL) -m 644 tcpreplay.8 $(MANDIR)
+
+uninstall:
+	rm -f $(SBINDIR)/tcpreplay
+	rm -f $(MANDIR)/tcpreplay.8

+ 54 - 0
README

@@ -0,0 +1,54 @@
+
+			    ===============
+
+			    tcpreplay-1.0.1
+
+			    ===============
+
+What is tcpreplay?
+-------------------
+
+Tcpreplay is a tool to replay saved tcpdump files at arbitrary speeds.
+
+This program was written in the hopes that a more precise testing
+methodology might be applied to the area of network intrusion
+detection, which is still a black art at best. 
+
+Many NIDSs fare poorly when looking for attacks on heavily-loaded
+networks. Tcpreplay allows you to recreate real network traffic from a
+real network for use in testing.
+
+What systems does tcpreplay support?
+-------------------------------------
+
+Tcpreplay is fairly portable, relying on libpcap and libnet for
+packet capture and raw IP packet construction.
+
+Tcpreplay has been successfully tested on
+
+	- OpenBSD 2.x
+	- FreeBSD 3.x
+	- BSD/OS 3.x
+	- Redhat Linux 5.x
+	- Solaris 2.x
+
+Who can use tcpreplay?
+-----------------------
+
+Tcpreplay is licensed under a BSD-style license, as in the included
+LICENSE file. Please read the license to make sure it's okay to use it
+in your circumstances.
+
+Contact info?
+-------------
+
+The primary tcpreplay site is 
+
+	http://www.anzen.com/research/nidsbench/
+
+Please send bug reports, comments, or questions about this software to
+<nidsbench@anzen.com>.
+
+
+---
+$Id: README,v 1.5 1999/05/19 20:05:01 dugsong Exp $

+ 1 - 0
VERSION

@@ -0,0 +1 @@
+1.0.1

+ 13 - 0
config.h.in

@@ -0,0 +1,13 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if you have the gettimeofday function.  */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H

File diff suppressed because it is too large
+ 1653 - 0
configure


+ 35 - 0
configure.in

@@ -0,0 +1,35 @@
+dnl tcpreplay configure script.
+dnl dugsong@anzen.com
+
+AC_INIT(tcpreplay.c)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+dnl Use these compiler flags if we have gcc.
+dnl
+if test $ac_cv_prog_gcc = yes; then
+    CCOPTS='-O3 -pipe -Wall'
+    CFLAGS="$CCOPTS"
+fi
+
+dnl Checks for libraries.
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_LIB(nsl, gethostbyname)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(sys/time.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_TIME
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(gettimeofday)
+
+AC_CONFIG_SUBDIRS(Libnet-0.99 libpcap-0.4)
+
+AC_CONFIG_HEADER(config.h)
+AC_OUTPUT(Makefile)

+ 250 - 0
install-sh

@@ -0,0 +1,250 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0

+ 91 - 0
tcpreplay.8

@@ -0,0 +1,91 @@
+.\" yo there.
+.TH TCPREPLAY 8  "12 April 1999"
+.SH NAME
+tcpreplay \- replay traffic from a saved tcpdump file
+.SH SYNOPSIS
+.na
+.B tcpreplay
+[
+.B \-i
+.I intf
+] [
+.B \-l
+.I loop count
+] [
+.B \-r
+.I rate
+|
+.B \-m
+.I multiplier
+]
+.I file ...
+.br
+.ad
+.SH DESCRIPTION
+.LP
+.I Tcpreplay
+is a program for replaying network traffic saved in packet-trace files
+generated using 
+\fItcpdump(8)\fP's
+.B \-w
+flag.
+.LP
+The basic operation of
+.I tcpreplay
+is to resend all packets from its input file(s) at the speed at which
+they were recorded, at some specified data \fIrate\fP, or as fast as the hardware is 
+capable of.  If no
+\fIrate\fP or
+\fImultiplier\fP are given, 
+.I tcpreplay 
+will replay packets as fast as the hardware will allow.
+If no
+\fIfile\fP is given,
+.I tcpreplay
+will accept packet data from \fIstdin\fP.
+.SH OPTIONS
+.LP
+.TP
+.B \-i
+Specify the interface to send packets out on.
+.TP
+.B \-r
+Resend the packets at the \fIrate\fR specified (in Mbps).
+.TP
+.B \-m
+Resend the packets at a \fImultiple\fR of the speed at which they were
+recorded.
+.TP
+.B \-l
+Resend the pcap file(s) \fIloop count\fR times.
+.SH "SEE ALSO"
+tcpdump(8)
+.SH AUTHOR
+Matt Undy, Anzen Computing.
+.LP
+The current version is available via HTTP:
+.LP
+.RS
+.I http://www.anzen.com/research/nidsbench/
+.RE
+.SH BUGS
+.I tcpreplay
+can only send packets as fast as your machine's interface,
+processor, and disk will allow.
+.LP
+``\fIN\fR write attempts failed from full buffers and were repeated''
+does not indicate that these packets were not sent, but that the send
+was retried \fIN\fR times until it succeeded.
+.LP
+Looping captured traffic may simulate odd conditions on a network.
+For example, opening the same TCP connection multiple times may 
+exhaust resources on machines tracking the connection. The 
+.B \-l
+flag is provided to allow faster sending on machines with greater I/O
+constraints.
+.LP
+On BSD-based systems, kernel modifications are required to preserve
+outgoing link layer source addresses. Refer to the \fIlibnet(3)\fP
+documentation for more information on how to do this.
+.LP
+Please send bug reports to nidsbench@anzen.com.

+ 395 - 0
tcpreplay.c

@@ -0,0 +1,395 @@
+/*
+  tcpreplay.c
+
+  Matt Undy <mundy@anzen.com>
+  
+  Copyright (c) 1999 Anzen Computing. All rights reserved.
+  
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. All advertising materials mentioning features or use of this software
+     must display the following acknowledgement:
+        This product includes software developed by Anzen Computing, Inc.
+  4. Neither the name of Anzen Computing, Inc. nor the names of its
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  Notes:
+  The performance of paced modes could be increased somewhat by
+  estimating sleep time and only checking against the RTC ocasionally,
+  although this would also result in a less precise data rate,
+  especially on machines with an imprecise usleep().
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include <pcap.h>
+#include <libnet.h>
+
+#define TCPREPLAY_VERSION	"1.0.1"
+
+#define PACE 1            /*0b01*/
+#define RATE 2            /*0b10*/
+#define TIME_GT(x,y) (x tv_sec>y tv_sec||(x tv_sec==y tv_sec&&x tv_usec>y tv_usec))
+#define TIME_LT(x,y) (x tv_sec<y tv_sec||(x tv_sec==y tv_sec&&x tv_usec<y tv_usec))
+#define TIME_ASSIGN(x,y)  x tv_sec=y tv_sec; x tv_usec=y tv_usec;
+#define PRINT_TIMEVAL(x) fprintf(stderr, " tv_sec=%li tv_usec=%li\n",x tv_sec, x tv_usec);
+
+typedef struct timeval time_struct;
+extern int errno;
+int failed_writes, first_pkt,older_pkts;
+int pkts_sent;
+long long bytes_sent;
+int iterrations;
+int mode;
+int rate;
+int debug;
+float multiplier;
+struct timeval lasttime, lastpkt, behind_time, starttime_struc,
+  startpkt_struct, last_dpkt, starttime, pkttime_struct;
+int caplen;
+int iterations;
+char * interface;
+
+void usage(){
+  fprintf(stderr, "Version: " TCPREPLAY_VERSION "\nUsage: tcpreplay "
+	  "[-i interface] [-l loops] [-m multiplier] [-r rate] <file>\n");
+  exit (1);
+}
+
+/* we aren't checking for overflow here.  if it happens we have run
+   into the 2038 problem and the whole time handling is broken (or a bug). */
+
+void addtime(time_struct * op1,time_struct *  op2,time_struct * result)
+{
+  result->tv_usec = op1->tv_usec+op2->tv_usec;
+  if (result->tv_usec > 999999) {
+    result->tv_usec -= 1000000;
+    op1->tv_sec++;
+  }
+  result->tv_sec = op1->tv_sec+op2->tv_sec;
+}
+
+/*
+  if op1>op2, return op1-op2 and 0
+  if op1<op2, return |op1-op2| and 1
+              (return a negative # with the sign bit in the return int)
+  if op2>op1, subtract op2 from op1 and set return int
+*/
+
+int subtime(time_struct * op1, time_struct * op2, time_struct * result)
+{
+  int borrow=0;     
+  int sign=0;
+  time_struct * temp_time;
+  
+  if (TIME_LT(op1->, op2->)) {
+    sign = 1;
+    temp_time = op1;
+    op1 = op2;
+    op2 = temp_time;
+  }
+  if (op1->tv_usec >= op2->tv_usec) {
+    result->tv_usec = op1->tv_usec-op2->tv_usec;
+  }
+  else {
+    result->tv_usec = (op1->tv_usec+1000000)-op2->tv_usec;
+    borrow = 1;
+  }
+  result->tv_sec = (op1->tv_sec-op2->tv_sec)-borrow;
+  
+  return sign;
+}
+
+void divtime(time_struct * num, float denom) {
+  num->tv_sec = num->tv_sec/denom;
+  num->tv_usec = num->tv_usec/denom;
+}
+
+void write_packet(u_char * user,struct pcap_pkthdr* pcap_hdr, u_char * data)
+{
+  int write_status = -1;
+  float sec;
+  struct timeval now, dtime, dpkt, sleeptime; 
+
+ 
+  if (mode) {
+#if HAVE_GETTIMEOFDAY 
+    gettimeofday(&now,NULL);
+#endif
+    iterations++;
+#ifdef DEBUG
+    if ((!(iterations %99))&&debug>0) {
+      fprintf(stderr, "\nELAPSED TIME %lu sec %li usec\n\n",
+	     now.tv_sec-starttime_struc.tv_sec,
+	     now.tv_usec - starttime_struc.tv_usec);
+      fprintf(stderr, "\nELAPSED PACKET TIME %lu sec %li usec\n\n",
+	     pcap_hdr->ts.tv_sec - startpkt_struct.tv_sec,
+	     pcap_hdr->ts.tv_usec - startpkt_struct.tv_usec); 
+    }
+#endif
+    if (first_pkt) {
+      first_pkt = 0;
+      TIME_ASSIGN(starttime_struc., now.);
+      TIME_ASSIGN(lastpkt., pcap_hdr->ts.);
+      TIME_ASSIGN(startpkt_struct., pcap_hdr->ts.);
+
+    }
+    if (subtime(&now, &starttime_struc, &dtime)) {
+      fprintf(stderr, "The RTC has decreased since last read (or someone multithreaded this wrong)\n");
+      /*if it is earlier than the last time we executed this loop,
+        something is very wrong*/
+      abort();
+    }
+    if (mode & PACE) {
+      if (subtime(&pcap_hdr->ts, &lastpkt, &dpkt)) {
+        /*Uncomment this if you want to stop on out of order packets
+          in the dump file*/
+        /*fprintf(stderr, "packets in pcap file not in increasing time of arrival\n");
+          abort();*/
+        older_pkts++;
+      }
+      else {
+        divtime(&dpkt, multiplier);
+        addtime(&dpkt, &pkttime_struct, &pkttime_struct);
+      }
+#ifdef DEBUG
+      if (debug > 2) {
+        fprintf(stderr, "dtime: ");
+        PRINT_TIMEVAL(dtime.);
+        fprintf(stderr, "pkttime_struct: ");
+        PRINT_TIMEVAL(pkttime_struct.);
+      }
+#endif
+    }
+    if (mode & RATE) {
+      /*calculate time packet should take, add to total packet time. */
+      sec = (float)pcap_hdr->caplen / (float)rate;
+      dpkt.tv_sec = sec;
+      dpkt.tv_usec = (sec - dpkt.tv_sec) * 1000000;
+#ifdef DEBUG
+      if (debug > 2) {
+        fprintf(stderr, "dpkt:");
+        PRINT_TIMEVAL(dpkt.);
+      }
+#endif
+      addtime(&dpkt, &pkttime_struct, &pkttime_struct);
+#ifdef DEBUG
+      if (debug > 2) {
+        fprintf(stderr, "pkttime_struct: ");
+        PRINT_TIMEVAL(pkttime_struct.);
+      }
+#endif
+    }
+    if (subtime(&dtime, &pkttime_struct, &sleeptime)) {
+      /*we are ahead by pkttime if true*/
+#ifdef DEBUG
+      if (debug > 2) {
+        fprintf(stderr, "sleeptime: ");
+        PRINT_TIMEVAL(sleeptime.);
+      }
+#endif
+      sleep(sleeptime.tv_sec);
+      usleep(sleeptime.tv_usec);
+    }
+    TIME_ASSIGN(lastpkt., pcap_hdr->ts.); 
+  }
+
+  while (write_status < 0) {
+    write_status = write_link_layer((struct link_int *)user, interface,
+				    data,pcap_hdr->caplen);
+#ifdef DEBUG
+    if (debug > 1) {
+      fprintf(stderr, "write_status = %i\n", write_status);
+    }
+#endif
+    if (write_status < 0) {
+      /*if errno =  = 55(ENOBUFS) loop, otherwise break*/
+
+      if (errno != ENOBUFS) {
+	fprintf(stderr, "errno = %i\n", errno);
+	perror("pcap_inject");
+	exit(1);
+      }
+      else {
+	failed_writes++;
+      }
+    }
+  }
+  bytes_sent += write_status;
+  pkts_sent++;
+}
+int main(int argc, char * argv[])
+{
+  pcap_t * in_file;
+  struct link_int * write_if;
+  float Mrate = 0;
+  double starttime_local, startusec;
+  char ebuf[256];
+  struct timeval tp;
+  extern char *optarg;
+  extern int optind;
+  int ch, iterrated,files = 0;
+  char * name = NULL;
+  int stdinput  = 0;
+  debug = 0;
+  iterrations = 1;
+  mode = 0;
+  interface = NULL;
+
+  while ((ch = getopt(argc, argv, "i:l:r:m:h")) != -1)
+    switch(ch) {
+    case 'd':
+      debug++;
+      break;
+    case 'm':
+      multiplier = atof(optarg);
+      mode = mode | PACE;
+      break;
+    case 'r':
+      mode = mode | RATE;
+      Mrate = atof(optarg);
+      rate = (Mrate * (1024 * 1024)) / 8;
+      break;
+    case 'l':
+      iterrations = atoi(optarg);
+      break;
+    case 'i':
+      interface = optarg;
+      break;
+    case 'h':
+      usage();
+      break;
+    default:
+      usage();
+    }
+  
+  if ((mode & PACE) && (mode & RATE)) {
+    usage();
+  }
+  if ((mode & PACE) && multiplier == 0) {
+    fprintf(stderr, "invalid pace multiplier - use a nonzero multiplier\n");
+    usage();
+  }
+  if ((mode & RATE) && (Mrate == 0)) {
+    fprintf(stderr, "invalid sending rate - use a nonzero rate\n");
+    usage();
+  }
+  if (interface == NULL) {
+    if (!(interface = pcap_lookupdev(ebuf))) {
+      fprintf(stderr, "can't determine default interface: %s\n", ebuf);
+      exit(1);
+    }
+  }
+  
+  iterations = 0;
+  older_pkts = 0;
+#if HAVE_GETTIMEOFDAY
+  gettimeofday(&tp,NULL);
+#endif
+  /*if you don't have gettimeofday, you will have to add the appropriate 
+    syscall for your system*/
+  starttime_local = tp.tv_sec;
+  startusec = tp.tv_usec;
+  failed_writes  = 0;
+  pkts_sent = 0;
+  bytes_sent = 0;
+  write_if = open_link_interface(interface,ebuf);
+  if (write_if <= 0) {
+    fprintf(stderr, "output i/f: %s\n",ebuf);
+    exit(1);
+  }
+  /*need to account for no args*/
+
+  if (argc == optind) {
+    stdinput = 1;
+  }
+  for (files=0;files < argc-optind || stdinput;files++) {
+    if (stdinput) {
+      name = malloc(4);
+      strcpy(name,"-");
+    }
+    else {
+      name = argv[files+optind];
+    }
+    for (iterrated = 0; iterrated < iterrations; iterrated++){
+      first_pkt = 1;
+#if HAVE_GETTIMEOFDAY
+      gettimeofday(&tp,NULL);
+#endif
+      pkttime_struct.tv_sec = 0;
+      pkttime_struct.tv_usec = 0;
+      lasttime.tv_sec = tp.tv_sec;
+      lasttime.tv_usec = tp.tv_usec;
+      in_file = pcap_open_offline(name, ebuf);
+      if (!in_file) {
+        fprintf(stderr, "Error opening %s for reading\n",argv[1]);
+        fprintf(stderr, "in_file: %s\n",ebuf);
+        exit (1);
+      }
+      if (pcap_dispatch(in_file, 0,(void *)&write_packet,
+			(u_char *) write_if) == -1) {
+	pcap_perror(in_file, argv[1]);
+      }
+      pcap_close(in_file);
+    }
+    stdinput = 0;
+  }
+  if (failed_writes) {
+    fprintf(stderr, "%i write attempts failed from full buffers and were repeated\n", failed_writes);
+  }
+  if (older_pkts) {
+    fprintf(stderr, "%i packet delays removed because they were out of order\n", older_pkts);
+  }
+  fprintf(stderr, "%i packets sucessfully sent", pkts_sent);
+#if HAVE_GETTIMEOFDAY
+  gettimeofday(&tp, NULL);
+#endif
+  fprintf(stderr, " in %f seconds(%f packets per second)\n",
+         (tp.tv_sec - starttime_local + ((tp.tv_usec - startusec) / 1000000)),
+         (pkts_sent / ((tp.tv_sec - starttime_local) * 1000000 +
+		       ((tp.tv_usec - startusec)))) * 1000000);
+  fprintf(stderr, "%lld bytes sucessfully sent", bytes_sent);
+  
+  fprintf(stderr, "(%f bytes per second\n",
+         (bytes_sent / ((tp.tv_sec - starttime_local) * 1000000 +
+			((tp.tv_usec - startusec)))) * 1000000);
+  fprintf(stderr, "%f megabits per second)\n",
+	  (((bytes_sent / ((tp.tv_sec - starttime_local) * 1000000 +
+			   ((tp.tv_usec-startusec)))) * 1000000) * 8) /
+	  (1024 * 1024));  
+  exit(0);
+}