replay.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /* $Id$ */
  2. /*
  3. * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
  4. * Copyright (c) 2013-2017 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  5. *
  6. * The Tcpreplay Suite of tools is free software: you can redistribute it
  7. * and/or modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or with the authors permission any later version.
  10. *
  11. * The Tcpreplay Suite is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <unistd.h>
  20. #include <string.h>
  21. #include "config.h"
  22. #include "defines.h"
  23. #include "common.h"
  24. #include "tcpreplay_api.h"
  25. #include "send_packets.h"
  26. static int replay_file(tcpreplay_t *ctx, int idx);
  27. static int replay_two_files(tcpreplay_t *ctx, int idx1, int idx2);
  28. static int replay_cache(tcpreplay_t *ctx, int idx);
  29. static int replay_two_caches(tcpreplay_t *ctx, int idx1, int idx2);
  30. static int replay_fd(tcpreplay_t *ctx, int idx);
  31. static int replay_two_fds(tcpreplay_t *ctx, int idx1, int idx2);
  32. /**
  33. * \brief Internal tcpreplay method to replay a given index
  34. *
  35. * This is used by tcpreplay_replay() to actually send the packets
  36. */
  37. int
  38. tcpr_replay_index(tcpreplay_t *ctx)
  39. {
  40. int rcode = 0;
  41. int idx;
  42. assert(ctx);
  43. init_timestamp(&ctx->stats.last_time);
  44. /* only process a single file */
  45. if (! ctx->options->dualfile) {
  46. /* process each pcap file in order */
  47. for (idx = 0; idx < ctx->options->source_cnt && !ctx->abort; idx++) {
  48. /* reset cache markers for each iteration */
  49. ctx->cache_byte = 0;
  50. ctx->cache_bit = 0;
  51. switch(ctx->options->sources[idx].type) {
  52. case source_filename:
  53. rcode = replay_file(ctx, idx);
  54. break;
  55. case source_fd:
  56. rcode = replay_fd(ctx, idx);
  57. break;
  58. case source_cache:
  59. rcode = replay_cache(ctx, idx);
  60. break;
  61. default:
  62. tcpreplay_seterr(ctx, "Invalid source type: %d", ctx->options->sources[idx].type);
  63. rcode = -1;
  64. }
  65. }
  66. }
  67. /* dual file mode: two files, two interfaces */
  68. else {
  69. /* process each pcap file in order */
  70. for (idx = 0; idx < ctx->options->source_cnt && !ctx->abort; idx += 2) {
  71. if (ctx->options->sources[idx].type != ctx->options->sources[(idx+1)].type) {
  72. tcpreplay_seterr(ctx, "Both source indexes (%d, %d) must be of the same type", idx, (idx+1));
  73. return -1;
  74. }
  75. switch(ctx->options->sources[idx].type) {
  76. case source_filename:
  77. rcode = replay_two_files(ctx, idx, (idx+1));
  78. break;
  79. case source_fd:
  80. rcode = replay_two_fds(ctx, idx, (idx+1));
  81. break;
  82. case source_cache:
  83. rcode = replay_two_caches(ctx, idx, (idx+1));
  84. break;
  85. default:
  86. tcpreplay_seterr(ctx, "Invalid source type: %d", ctx->options->sources[idx].type);
  87. rcode = -1;
  88. }
  89. }
  90. }
  91. if (rcode < 0) {
  92. ctx->running = false;
  93. return -1;
  94. }
  95. return rcode;
  96. }
  97. /**
  98. * \brief replay a pcap file out interface(s)
  99. *
  100. * Internal to tcpreplay. Does the heavy lifting.
  101. */
  102. static int
  103. replay_file(tcpreplay_t *ctx, int idx)
  104. {
  105. char *path;
  106. pcap_t *pcap = NULL;
  107. char ebuf[PCAP_ERRBUF_SIZE];
  108. assert(ctx);
  109. assert(ctx->options->sources[idx].type == source_filename);
  110. path = ctx->options->sources[idx].filename;
  111. /* close stdin if reading from it (needed for some OS's) */
  112. if (strncmp(path, "-", 1) == 0)
  113. close(1);
  114. /* read from pcap file if we haven't cached things yet */
  115. if (!ctx->options->preload_pcap) {
  116. if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
  117. tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
  118. return -1;
  119. }
  120. ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);
  121. #ifdef HAVE_PCAP_SNAPSHOT
  122. if (pcap_snapshot(pcap) < 65535)
  123. warnx("%s was captured using a snaplen of %d bytes. This may mean you have truncated packets.",
  124. path, pcap_snapshot(pcap));
  125. #endif
  126. } else {
  127. if (!ctx->options->file_cache[idx].cached) {
  128. if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
  129. tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
  130. return -1;
  131. }
  132. ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);
  133. }
  134. }
  135. #if 0
  136. /*
  137. * this API is broken right now. This needs to be handled via a pipe or
  138. * something else so we can pass the output up to the calling programm
  139. */
  140. #ifdef ENABLE_VERBOSE
  141. if (ctx->options->verbose) {
  142. /* in cache mode, we may not have opened the file */
  143. if (pcap == NULL)
  144. if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
  145. tcpreplay_seterr("Error opening pcap file: %s", ebuf);
  146. return -1;
  147. }
  148. ctx->options->file_cache[idx].dlt = pcap_datalink(pcap);
  149. /* init tcpdump */
  150. tcpdump_open(ctx->options->tcpdump, pcap);
  151. }
  152. #endif
  153. #endif
  154. if (pcap != NULL) {
  155. if (ctx->intf1dlt == -1)
  156. ctx->intf1dlt = sendpacket_get_dlt(ctx->intf1);
  157. #if 0
  158. if ((ctx->intf1dlt >= 0) && (ctx->intf1dlt != pcap_datalink(pcap)))
  159. warnx("%s DLT (%s) does not match that of the outbound interface: %s (%s)",
  160. path, pcap_datalink_val_to_name(pcap_datalink(pcap)),
  161. ctx->options->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt));
  162. #endif
  163. if (ctx->intf1dlt != ctx->options->file_cache[idx].dlt)
  164. tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)",
  165. path, pcap_datalink_val_to_name(pcap_datalink(pcap)),
  166. ctx->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt));
  167. }
  168. ctx->stats.active_pcap = ctx->options->sources[idx].filename;
  169. send_packets(ctx, pcap, idx);
  170. if (pcap != NULL)
  171. pcap_close(pcap);
  172. #if 0
  173. #ifdef ENABLE_VERBOSE
  174. tcpdump_close(ctx->options->tcpdump);
  175. #endif
  176. #endif
  177. return 0;
  178. }
  179. /**
  180. * \brief replay two pcap files out two interfaces
  181. *
  182. * Internal to tcpreplay, does the heavy lifting for --dualfile
  183. */
  184. static int
  185. replay_two_files(tcpreplay_t *ctx, int idx1, int idx2)
  186. {
  187. char *path1, *path2;
  188. pcap_t *pcap1 = NULL, *pcap2 = NULL;
  189. char ebuf[PCAP_ERRBUF_SIZE];
  190. int rcode = 0;
  191. assert(ctx);
  192. assert(ctx->options->sources[idx1].type == source_filename);
  193. assert(ctx->options->sources[idx2].type == source_filename);
  194. path1 = ctx->options->sources[idx1].filename;
  195. path2 = ctx->options->sources[idx2].filename;
  196. /* can't use stdin in dualfile mode */
  197. if ((strncmp(path1, "-", strlen(path1)) == 0) ||
  198. (strncmp(path2, "-", strlen(path2)) == 0)) {
  199. tcpreplay_seterr(ctx, "%s", "Invalid use of STDIN '-' in dual file mode");
  200. return -1;
  201. }
  202. /* read from first pcap file if we haven't cached things yet */
  203. if (!ctx->options->preload_pcap) {
  204. if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
  205. tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
  206. return -1;
  207. }
  208. ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1);
  209. if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) {
  210. tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
  211. return -1;
  212. }
  213. ctx->options->file_cache[idx2].dlt = pcap_datalink(pcap2);
  214. } else {
  215. if (!ctx->options->file_cache[idx1].cached) {
  216. if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
  217. tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
  218. return -1;
  219. }
  220. ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1);
  221. }
  222. if (!ctx->options->file_cache[idx2].cached) {
  223. if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) {
  224. tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
  225. return -1;
  226. }
  227. ctx->options->file_cache[idx2].dlt = pcap_datalink(pcap2);
  228. }
  229. }
  230. if (pcap1 != NULL) {
  231. #ifdef HAVE_PCAP_SNAPSHOT
  232. if (pcap_snapshot(pcap1) < 65535) {
  233. tcpreplay_setwarn(ctx, "%s was captured using a snaplen of %d bytes. This may mean you have truncated packets.",
  234. path1, pcap_snapshot(pcap1));
  235. rcode = -2;
  236. }
  237. if (pcap_snapshot(pcap2) < 65535) {
  238. tcpreplay_setwarn(ctx, "%s was captured using a snaplen of %d bytes. This may mean you have truncated packets.",
  239. path2, pcap_snapshot(pcap2));
  240. rcode = -2;
  241. }
  242. #endif
  243. if (ctx->intf1dlt == -1)
  244. ctx->intf1dlt = sendpacket_get_dlt(ctx->intf1);
  245. if ((ctx->intf1dlt >= 0) && (ctx->intf1dlt != pcap_datalink(pcap1))) {
  246. tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)",
  247. path1, pcap_datalink_val_to_name(pcap_datalink(pcap1)),
  248. ctx->intf1->device, pcap_datalink_val_to_name(ctx->intf1dlt));
  249. rcode = -2;
  250. }
  251. if (ctx->intf2dlt == -1)
  252. ctx->intf2dlt = sendpacket_get_dlt(ctx->intf2);
  253. if ((ctx->intf2dlt >= 0) && (ctx->intf2dlt != pcap_datalink(pcap2))) {
  254. tcpreplay_setwarn(ctx, "%s DLT (%s) does not match that of the outbound interface: %s (%s)",
  255. path2, pcap_datalink_val_to_name(pcap_datalink(pcap2)),
  256. ctx->intf2->device, pcap_datalink_val_to_name(ctx->intf2dlt));
  257. rcode = -2;
  258. }
  259. if (ctx->intf1dlt != ctx->intf2dlt) {
  260. tcpreplay_seterr(ctx, "DLT mismatch for %s (%d) and %s (%d)",
  261. path1, ctx->intf1dlt, path2, ctx->intf2dlt);
  262. return -1;
  263. }
  264. }
  265. #ifdef ENABLE_VERBOSE
  266. if (ctx->options->verbose) {
  267. /* in cache mode, we may not have opened the file */
  268. if (pcap1 == NULL) {
  269. if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
  270. tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
  271. return -1;
  272. }
  273. ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1);
  274. }
  275. /* init tcpdump */
  276. tcpdump_open(ctx->options->tcpdump, pcap1);
  277. }
  278. #endif
  279. send_dual_packets(ctx, pcap1, idx1, pcap2, idx2);
  280. if (pcap1 != NULL)
  281. pcap_close(pcap1);
  282. if (pcap2 != NULL)
  283. pcap_close(pcap2);
  284. #ifdef ENABLE_VERBOSE
  285. tcpdump_close(ctx->options->tcpdump);
  286. #endif
  287. return rcode;
  288. }
  289. /**
  290. * \brief Replay index using existing memory cache
  291. *
  292. * FIXME
  293. */
  294. static int
  295. replay_cache(tcpreplay_t *ctx, int idx)
  296. {
  297. assert(ctx);
  298. assert(ctx->options->sources[idx].type == source_cache);
  299. return 0;
  300. }
  301. /**
  302. * \brief Replay two indexes using existing memory cache
  303. *
  304. * FIXME
  305. */
  306. static int
  307. replay_two_caches(tcpreplay_t *ctx, int idx1, int idx2)
  308. {
  309. assert(ctx);
  310. assert(ctx->options->sources[idx1].type == source_cache);
  311. assert(ctx->options->sources[idx2].type == source_cache);
  312. return 0;
  313. }
  314. /**
  315. * \brief Replay index which is a file descriptor
  316. *
  317. * FIXME
  318. */
  319. static int
  320. replay_fd(tcpreplay_t *ctx, int idx)
  321. {
  322. assert(ctx);
  323. assert(ctx->options->sources[idx].type == source_fd);
  324. return 0;
  325. }
  326. /**
  327. * \brief Replay two indexes which are a file descriptor
  328. *
  329. * FIXME
  330. */
  331. static int
  332. replay_two_fds(tcpreplay_t *ctx, int idx1, int idx2)
  333. {
  334. assert(ctx);
  335. assert(ctx->options->sources[idx1].type == source_fd);
  336. assert(ctx->options->sources[idx2].type == source_fd);
  337. return 0;
  338. }