tcpdump.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. /*
  20. * This code allows us to use tcpdump to print packet decodes.
  21. * Basically, we create a local AF_UNIX socketpair, fork a copy
  22. * of ourselves, link 1/2 of the pair to STDIN of the child and
  23. * replace the child with tcpdump. We then send a "pcap" file
  24. * over the socket so that tcpdump can print it's decode to STDOUT.
  25. *
  26. * Idea and a lot of code stolen from Christain Kreibich's
  27. * <christian@whoop.org> libnetdude 0.4 code. Any bugs are mine. :)
  28. *
  29. * This product includes software developed by the University of California,
  30. * Lawrence Berkeley Laboratory and its contributors
  31. */
  32. #include "config.h"
  33. #include "defines.h"
  34. #include "common.h"
  35. #include <stdlib.h>
  36. #include <sys/types.h>
  37. #include <unistd.h>
  38. #include <sys/socket.h>
  39. #include <sys/wait.h>
  40. #include <errno.h>
  41. #include <string.h>
  42. #ifdef HAVE_SIGNAL_H
  43. #include <signal.h>
  44. #endif
  45. #include "tcpdump.h"
  46. #ifndef HAVE_STRLCPY
  47. #include "lib/strlcpy.h"
  48. #endif
  49. #ifdef DEBUG
  50. extern int debug;
  51. #endif
  52. char *options_vec[OPTIONS_VEC_SIZE];
  53. static int tcpdump_fill_in_options(char *opt);
  54. static int can_exec(const char *filename);
  55. /**
  56. * given a packet, print a decode of via tcpdump
  57. */
  58. int
  59. tcpdump_print(tcpdump_t *tcpdump, struct pcap_pkthdr *pkthdr, const u_char *data)
  60. {
  61. struct pollfd poller[1];
  62. int result;
  63. char decode[TCPDUMP_DECODE_LEN];
  64. assert(tcpdump);
  65. assert(pkthdr);
  66. assert(data);
  67. poller[0].fd = tcpdump->infd;
  68. poller[0].events = POLLOUT;
  69. poller[0].revents = 0;
  70. /* wait until we can write to the tcpdump socket */
  71. result = poll(poller, 1, TCPDUMP_POLL_TIMEOUT);
  72. if (result < 0)
  73. errx(-1, "Error during poll() to write to tcpdump\n%s", strerror(errno));
  74. if (result == 0)
  75. err(-1, "poll() timeout... tcpdump seems to be having a problem keeping up\n"
  76. "Try increasing TCPDUMP_POLL_TIMEOUT");
  77. /* result > 0 if we get here */
  78. if (write(tcpdump->infd, (char *)pkthdr, sizeof(struct pcap_pkthdr))
  79. != sizeof(struct pcap_pkthdr))
  80. errx(-1, "Error writing pcap file header to tcpdump\n%s", strerror(errno));
  81. #ifdef DEBUG
  82. if (debug >= 5) {
  83. if (write(tcpdump->debugfd, (char *)pkthdr, sizeof(struct pcap_pkthdr))
  84. != sizeof(struct pcap_pkthdr))
  85. errx(-1, "Error writing pcap file header to tcpdump debug\n%s", strerror(errno));
  86. }
  87. #endif
  88. if (write(tcpdump->infd, data, pkthdr->caplen) != (ssize_t)pkthdr->caplen)
  89. errx(-1, "Error writing packet data to tcpdump\n%s", strerror(errno));
  90. #ifdef DEBUG
  91. if (debug >= 5) {
  92. if (write(tcpdump->debugfd, data, pkthdr->caplen) != (ssize_t)pkthdr->caplen)
  93. errx(-1, "Error writing packet data to tcpdump debug\n%s", strerror(errno));
  94. }
  95. #endif
  96. /* Wait for output from tcpdump */
  97. poller[0].fd = tcpdump->outfd;
  98. poller[0].events = POLLIN;
  99. poller[0].revents = 0;
  100. result = poll(poller, 1, TCPDUMP_POLL_TIMEOUT);
  101. if (result < 0)
  102. errx(-1, "Error during poll() to write to tcpdump\n%s", strerror(errno));
  103. if (result == 0)
  104. err(-1, "poll() timeout... tcpdump seems to be having a problem keeping up\n"
  105. "Try increasing TCPDUMP_POLL_TIMEOUT");
  106. result = read(tcpdump->outfd, &decode, TCPDUMP_DECODE_LEN);
  107. if (result < 0)
  108. errx(-1, "Error reading tcpdump decode: %s", strerror(errno));
  109. /* result > 0 if we get here */
  110. decode[min(result, TCPDUMP_DECODE_LEN)] = 0;
  111. printf("%s", decode);
  112. return TRUE;
  113. }
  114. /**
  115. * init our tcpdump handle using the given pcap handle
  116. * Basically, this starts up tcpdump as a child and communicates
  117. * to it via a pair of sockets (stdout/stdin)
  118. */
  119. int
  120. tcpdump_open(tcpdump_t *tcpdump, pcap_t *pcap)
  121. {
  122. int infd[2], outfd[2];
  123. FILE *writer;
  124. assert(tcpdump);
  125. assert(pcap);
  126. if (tcpdump->pid != 0) {
  127. warn("tcpdump process already running");
  128. return FALSE;
  129. }
  130. /* is tcpdump executable? */
  131. if (! can_exec(TCPDUMP_BINARY)) {
  132. errx(-1, "Unable to execute tcpdump binary: %s", TCPDUMP_BINARY);
  133. }
  134. #ifdef DEBUG
  135. strlcpy(tcpdump->debugfile, TCPDUMP_DEBUG, sizeof(tcpdump->debugfile));
  136. if (debug >= 5) {
  137. dbgx(5, "Opening tcpdump debug file: %s", tcpdump->debugfile);
  138. if ((tcpdump->debugfd = open(tcpdump->debugfile, O_WRONLY|O_CREAT|O_TRUNC,
  139. S_IREAD|S_IWRITE|S_IRGRP|S_IROTH)) == -1) {
  140. errx(-1, "Error opening tcpdump debug file: %s\n%s", tcpdump->debugfile, strerror(errno));
  141. }
  142. }
  143. #endif
  144. /* copy over the args */
  145. dbg(2, "Prepping tcpdump options...");
  146. tcpdump_fill_in_options(tcpdump->args);
  147. dbg(2, "Starting tcpdump...");
  148. /* create our socket pair to send packet data to tcpdump via */
  149. if (socketpair(AF_UNIX, SOCK_STREAM, 0, infd) < 0)
  150. errx(-1, "Unable to create stdin socket pair: %s", strerror(errno));
  151. /* create our socket pair to read packet decode from tcpdump */
  152. if (socketpair(AF_UNIX, SOCK_STREAM, 0, outfd) < 0)
  153. errx(-1, "Unable to create stdout socket pair: %s", strerror(errno));
  154. if ((tcpdump->pid = fork() ) < 0)
  155. errx(-1, "Fork failed: %s", strerror(errno));
  156. dbgx(2, "tcpdump pid: %d", tcpdump->pid);
  157. if (tcpdump->pid > 0) {
  158. /* we're still in tcpreplay */
  159. dbgx(2, "[parent] closing input fd %d", infd[1]);
  160. close(infd[1]); /* close the tcpdump side */
  161. dbgx(2, "[parent] closing output fd %d", outfd[1]);
  162. close(outfd[1]);
  163. tcpdump->infd = infd[0];
  164. tcpdump->outfd = outfd[0];
  165. /* send the pcap file header to tcpdump */
  166. writer = fdopen(tcpdump->infd, "w");
  167. if ((tcpdump->dumper = pcap_dump_fopen(pcap, writer)) == NULL) {
  168. warnx("[parent] pcap_dump_fopen(): %s", pcap_geterr(pcap));
  169. return FALSE;
  170. }
  171. pcap_dump_flush(tcpdump->dumper);
  172. if (fcntl(tcpdump->infd, F_SETFL, O_NONBLOCK) < 0)
  173. warnx("[parent] Unable to fcntl tcpreplay socket:\n%s", strerror(errno));
  174. if (fcntl(tcpdump->outfd, F_SETFL, O_NONBLOCK) < 0)
  175. warnx("[parent] Unable to fnctl stdout socket:\n%s", strerror(errno));
  176. }
  177. else {
  178. dbg(2, "[child] started the kid");
  179. /* we're in the child process */
  180. dbgx(2, "[child] closing in fd %d", infd[0]);
  181. dbgx(2, "[child] closing out fd %d", outfd[0]);
  182. close(infd[0]); /* close the tcpreplay side */
  183. close(outfd[0]);
  184. /* copy our side of the socketpair to our stdin */
  185. if (infd[1] != STDIN_FILENO) {
  186. if (dup2(infd[1], STDIN_FILENO) != STDIN_FILENO)
  187. errx(-1, "[child] Unable to copy socket to stdin: %s",
  188. strerror(errno));
  189. }
  190. /* copy our side of the socketpair to our stdout */
  191. if (outfd[1] != STDOUT_FILENO) {
  192. if (dup2(outfd[1], STDOUT_FILENO) != STDOUT_FILENO)
  193. errx(-1, "[child] Unable to copy socket to stdout: %s",
  194. strerror(errno));
  195. }
  196. /* exec tcpdump */
  197. dbg(2, "[child] Exec'ing tcpdump...");
  198. if (execv(TCPDUMP_BINARY, options_vec) < 0)
  199. errx(-1, "Unable to exec tcpdump: %s", strerror(errno));
  200. }
  201. return TRUE;
  202. }
  203. /**
  204. * shutdown tcpdump
  205. */
  206. void
  207. tcpdump_close(tcpdump_t *tcpdump)
  208. {
  209. if (! tcpdump)
  210. return;
  211. if (tcpdump->pid <= 0)
  212. return;
  213. dbgx(2, "[parent] killing tcpdump pid: %d", tcpdump->pid);
  214. kill(tcpdump->pid, SIGKILL);
  215. close(tcpdump->infd);
  216. close(tcpdump->outfd);
  217. if (waitpid(tcpdump->pid, NULL, 0) != tcpdump->pid)
  218. errx(-1, "[parent] Error in waitpid: %s", strerror(errno));
  219. tcpdump->pid = 0;
  220. tcpdump->infd = 0;
  221. tcpdump->outfd = 0;
  222. }
  223. /**
  224. * forcefully kill tcpdump
  225. */
  226. void
  227. tcpdump_kill(tcpdump_t *tcpdump)
  228. {
  229. if (tcpdump->pid) {
  230. if (kill(tcpdump->pid, SIGTERM) != 0) {
  231. kill(tcpdump->pid, SIGKILL);
  232. }
  233. }
  234. tcpdump->infd = 0;
  235. tcpdump->outfd = 0;
  236. tcpdump->pid = 0;
  237. }
  238. /**
  239. * copy the string of args (*opt) to the vector (**opt_vec)
  240. * for a max of opt_len. Returns the number of options
  241. * in the vector
  242. */
  243. static int
  244. tcpdump_fill_in_options(char *opt)
  245. {
  246. char options[256];
  247. char *arg, *newarg;
  248. int i = 1, arglen;
  249. char *token = NULL;
  250. /* zero out our options_vec for execv() */
  251. memset(options_vec, '\0', OPTIONS_VEC_SIZE);
  252. /* first arg should be the binary (by convention) */
  253. options_vec[0] = TCPDUMP_BINARY;
  254. /* prep args */
  255. memset(options, '\0', 256);
  256. if (opt != NULL) {
  257. strlcat(options, opt, sizeof(options));
  258. }
  259. strlcat(options, TCPDUMP_ARGS, sizeof(options));
  260. dbgx(2, "[child] Will execute: tcpdump %s", options);
  261. /* process args */
  262. /* process the first argument */
  263. arg = strtok_r(options, OPT_DELIM, &token);
  264. arglen = strlen(arg) + 2; /* -{arg}\0 */
  265. newarg = (char *)safe_malloc(arglen);
  266. strlcat(newarg, "-", arglen);
  267. strlcat(newarg, arg, arglen);
  268. options_vec[i++] = newarg;
  269. /* process the remaining args
  270. note that i < OPTIONS_VEC_SIZE - 1
  271. because: a) we need to add '-' as an option to the end
  272. b) because the array has to be null terminated
  273. */
  274. while (((arg = strtok_r(NULL, OPT_DELIM, &token)) != NULL) &&
  275. (i < OPTIONS_VEC_SIZE - 1)) {
  276. arglen = strlen(arg) + 2;
  277. newarg = (char *)safe_malloc(arglen);
  278. strlcat(newarg, "-", arglen);
  279. strlcat(newarg, arg, arglen);
  280. options_vec[i++] = newarg;
  281. }
  282. /* tell -r to read from stdin */
  283. options_vec[i] = "-";
  284. return(i);
  285. }
  286. /**
  287. * can we exec the given file?
  288. */
  289. static int
  290. can_exec(const char *filename)
  291. {
  292. struct stat st;
  293. if (!filename || filename[0] == '\0')
  294. return FALSE;
  295. /* Stat the file to see if it's executable and
  296. if the user may run it.
  297. */
  298. if (lstat(filename, &st) < 0)
  299. return FALSE;
  300. if ((st.st_mode & S_IXUSR) ||
  301. (st.st_mode & S_IXGRP) ||
  302. (st.st_mode & S_IXOTH))
  303. return TRUE;
  304. return FALSE;
  305. }