replay.c 12 KB

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