replay.c 12 KB

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