tcpreplay.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /* $Id: tcpreplay.c 1462 2006-04-13 05:10:27Z aturner $ */
  2. /*
  3. * Copyright (c) 2001-2005 Aaron Turner <aturner@pobox.com>.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the names of the copyright owners nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  20. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  23. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  25. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  27. * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  28. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  29. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. #include "config.h"
  32. #include "defines.h"
  33. #include "common.h"
  34. #include <ctype.h>
  35. #include <fcntl.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <sys/types.h>
  40. #include <unistd.h>
  41. #include "tcpreplay.h"
  42. #include "tcpreplay_opts.h"
  43. #include "send_packets.h"
  44. #include "signal_handler.h"
  45. tcpreplay_opt_t options;
  46. struct timeval begin, end;
  47. COUNTER bytes_sent, failed, pkts_sent;
  48. int cache_bit, cache_byte;
  49. volatile int didsig;
  50. #ifdef HAVE_TCPDUMP
  51. /* tcpdump handle */
  52. tcpdump_t tcpdump;
  53. #endif
  54. #ifdef DEBUG
  55. int debug = 0;
  56. #endif
  57. void replay_file(char *path);
  58. void usage(void);
  59. void init(void);
  60. void post_args(void);
  61. int
  62. main(int argc, char *argv[])
  63. {
  64. char ebuf[256];
  65. int i, optct = 0;
  66. init(); /* init our globals */
  67. optct = optionProcess(&tcpreplayOptions, argc, argv);
  68. argc -= optct;
  69. argv += optct;
  70. post_args();
  71. for (i = 0; i < argc; i++)
  72. options.files[i] = safe_strdup(argv[i]);
  73. /* open interfaces for writing */
  74. if ((options.intf1 = libnet_init(LIBNET_LINK_ADV, options.intf1_name, ebuf)) == NULL)
  75. errx(1, "Libnet can't open %s: %s", options.intf1_name, ebuf);
  76. if (options.intf2_name != NULL) {
  77. if ((options.intf2 = libnet_init(LIBNET_LINK_ADV, options.intf2_name, ebuf)) == NULL)
  78. errx(1, "Libnet can't open %s: %s", options.intf2_name, ebuf);
  79. }
  80. notice("sending out %s %s", options.intf1_name,
  81. options.intf2_name == NULL ? "" : options.intf2_name);
  82. /* init the signal handlers */
  83. init_signal_handlers();
  84. if (gettimeofday(&begin, NULL) < 0)
  85. err(1, "gettimeofday() failed");
  86. /* main loop for non-bridge mode */
  87. if (options.loop > 0) {
  88. while (options.loop--) { /* limited loop */
  89. /* process each pcap file in order */
  90. for (i = 0; i < argc; i++) {
  91. /* reset cache markers for each iteration */
  92. cache_byte = 0;
  93. cache_bit = 0;
  94. replay_file(argv[i]);
  95. }
  96. }
  97. }
  98. else {
  99. /* loop forever */
  100. while (1) {
  101. for (i = 0; i < argc; i++) {
  102. /* reset cache markers for each iteration */
  103. cache_byte = 0;
  104. cache_bit = 0;
  105. replay_file(argv[i]);
  106. }
  107. }
  108. }
  109. if (bytes_sent > 0)
  110. packet_stats(&begin, &end, bytes_sent, pkts_sent, failed);
  111. return 0;
  112. } /* main() */
  113. /*
  114. * replay a pcap file out an interface
  115. */
  116. void
  117. replay_file(char *path)
  118. {
  119. pcap_t *pcap = NULL;
  120. char ebuf[PCAP_ERRBUF_SIZE];
  121. #ifdef HAVE_TCPDUMP
  122. if (options.verbose) {
  123. tcpdump.filename = path;
  124. tcpdump_open(&tcpdump);
  125. }
  126. #endif
  127. notice("processing file: %s", path);
  128. /* close stdin if reading from it (needed for some OS's) */
  129. if (strncmp(path, "-", 1) == 0)
  130. if (close(1) == -1)
  131. warnx("unable to close stdin: %s", strerror(errno));
  132. if ((pcap = pcap_open_offline(path, ebuf)) == NULL)
  133. errx(1, "Error opening pcap file: %s", ebuf);
  134. send_packets(pcap);
  135. pcap_close(pcap);
  136. #ifdef HAVE_TCPDUMP
  137. tcpdump_close(&tcpdump);
  138. #endif
  139. }
  140. /*
  141. * Initialize globals
  142. */
  143. void
  144. init(void)
  145. {
  146. bytes_sent = failed = pkts_sent = 0;
  147. memset(&options, 0, sizeof(options));
  148. /* replay packets only once */
  149. options.loop = 1;
  150. /* Default mode is to replay pcap once in real-time */
  151. options.speed.mode = SPEED_MULTIPLIER;
  152. options.speed.speed = 1.0;
  153. /* set the default MTU size */
  154. options.mtu = DEFAULT_MTU;
  155. /* disable limit send */
  156. options.limit_send = -1;
  157. #ifdef HAVE_TCPDUMP
  158. /* clear out tcpdump struct */
  159. memset(&tcpdump, '\0', sizeof(tcpdump_t));
  160. #endif
  161. cache_bit = cache_byte = 0;
  162. if (fcntl(STDERR_FILENO, F_SETFL, O_NONBLOCK) < 0)
  163. warnx("Unable to set STDERR to non-blocking: %s", strerror(errno));
  164. }
  165. /*
  166. * post processes the args and puts them into our options
  167. */
  168. void
  169. post_args(void)
  170. {
  171. char *temp;
  172. #ifdef DEBUG
  173. if (HAVE_OPT(DBUG))
  174. debug = OPT_VALUE_DBUG;
  175. #else
  176. if (HAVE_OPT(DBUG))
  177. warn("not configured with --enable-debug. Debugging disabled.");
  178. #endif
  179. options.loop = OPT_VALUE_LOOP;
  180. /* Currently disabled
  181. if (HAVE_OPT(LIMIT))
  182. options.limit_send = OPT_VALUE_LIMIT;
  183. */
  184. if (HAVE_OPT(TOPSPEED)) {
  185. options.speed.mode = SPEED_TOPSPEED;
  186. options.speed.speed = 0.0;
  187. } else if (HAVE_OPT(PPS)) {
  188. options.speed.mode = SPEED_PACKETRATE;
  189. options.speed.speed = (float)OPT_VALUE_PPS;
  190. } else if (HAVE_OPT(ONEATATIME)) {
  191. options.speed.mode = SPEED_ONEATATIME;
  192. options.speed.speed = 0.0;
  193. } else if (HAVE_OPT(MBPS)) {
  194. options.speed.mode = SPEED_MBPSRATE;
  195. options.speed.speed = atof(OPT_ARG(MBPS));
  196. } else if (HAVE_OPT(MULTIPLIER)) {
  197. options.speed.mode = SPEED_MULTIPLIER;
  198. options.speed.speed = atof(OPT_ARG(MULTIPLIER));
  199. }
  200. #ifdef HAVE_TCPDUMP
  201. if (HAVE_OPT(VERBOSE))
  202. options.verbose = 1;
  203. if (HAVE_OPT(DECODE))
  204. tcpdump.args = safe_strdup(OPT_ARG(DECODE));
  205. #endif
  206. if (HAVE_OPT(PKTLEN))
  207. warn("--pktlen may cause problems. Use with caution.");
  208. options.intf1_name = (char *)safe_malloc(strlen(OPT_ARG(INTF1)) + 1);
  209. strncpy(options.intf1_name, OPT_ARG(INTF1), strlen(OPT_ARG(INTF1)));
  210. if (HAVE_OPT(INTF2)) {
  211. options.intf2_name = (char *)safe_malloc(strlen(OPT_ARG(INTF2)) + 1);
  212. strncpy(options.intf2_name, OPT_ARG(INTF2), strlen(OPT_ARG(INTF2)));
  213. }
  214. if (HAVE_OPT(CACHEFILE)) {
  215. temp = safe_strdup(OPT_ARG(CACHEFILE));
  216. options.cache_packets = read_cache(&options.cachedata, temp,
  217. &options.comment);
  218. free(temp);
  219. }
  220. }
  221. /*
  222. Local Variables:
  223. mode:c
  224. indent-tabs-mode:nil
  225. c-basic-offset:4
  226. End:
  227. */