pcapmerge.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /* $Id: pcapmerge.c 767 2004-10-06 12:48:49Z aturner $ */
  2. /*
  3. * Copyright (c) 2001-2004 Aaron Turner, Matt Bing.
  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. /* The pcapmerge available at http://indev.insu.com/Fwctl/pcapmerge.html
  32. * is written in Perl and does not handle large pcaps very well. This
  33. * is meant to be small and efficient.
  34. *
  35. * gcc -o pcapmerge pcapmerge.c -lpcap
  36. *
  37. * usage: pcapmerge -o bigpcap pcap1 pcap2 pcap3 ..
  38. *
  39. * Tested on OpenBSD 3.1. Probably won't work on non BSD.
  40. */
  41. #include <pcap.h>
  42. #include <fcntl.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <unistd.h>
  47. #include <sys/time.h>
  48. #include <sys/types.h>
  49. #include "config.h"
  50. #include "tcpreplay.h"
  51. #include "err.h"
  52. #include "queue.h"
  53. /* we get this from libpcap */
  54. extern char pcap_version[];
  55. #ifdef DEBUG
  56. int debug = 0;
  57. #endif
  58. /* magic constants for various pcap file types */
  59. #define PCAP_MAGIC 0xa1b2c3d4
  60. #define PCAP_SWAPPED_MAGIC 0xd4c3b2a1
  61. #define PCAP_MODIFIED_MAGIC 0xa1b2cd34
  62. #define PCAP_SWAPPED_MODIFIED_MAGIC 0x34cdb2a1
  63. #define SWAPLONG(y) \
  64. ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
  65. #define SWAPSHORT(y) \
  66. ( (((y)&0xff)<<8) | ((u_short)((y)&0xff00)>>8) )
  67. /* data prefixing each packet in modified pcap */
  68. struct pcap_mod_pkthdr {
  69. struct pcap_pkthdr hdr; /* normal header */
  70. u_int32_t ifindex; /* receiving interface index */
  71. u_int16_t protocol; /* ethernet packet type */
  72. u_int8_t pkt_type; /* ethernet packet type */
  73. u_int8_t pad; /* padding */
  74. };
  75. /* info about each open file */
  76. struct pcap_file {
  77. int fd;
  78. int modified;
  79. int swapped;
  80. char *name;
  81. SLIST_ENTRY(pcap_file) next;
  82. };
  83. void init_files(int, char **);
  84. void write_packets(struct pcap_file *, int);
  85. void usage();
  86. SLIST_HEAD(, pcap_file) files;
  87. struct pcap_file_header hdr;
  88. int outfd;
  89. char *outfile;
  90. void
  91. version()
  92. {
  93. fprintf(stderr, "pcapmerge version: %s\n", VERSION);
  94. fprintf(stderr, "Compiled against libpcap: %s\n", pcap_version);
  95. exit(0);
  96. }
  97. int
  98. main(int argc, char *argv[])
  99. {
  100. struct pcap_file *p;
  101. int ch, fd;
  102. outfile = NULL;
  103. while ((ch = getopt(argc, argv, "o:h?V")) != -1) {
  104. switch (ch) {
  105. case 'o': /* output file */
  106. outfile = optarg;
  107. break;
  108. case 'V':
  109. version();
  110. break;
  111. default:
  112. usage();
  113. }
  114. }
  115. argc -= optind;
  116. argv += optind;
  117. if (outfile == NULL)
  118. errx(1, "must specify output file");
  119. SLIST_INIT(&files);
  120. init_files(argc, argv);
  121. if ((fd = open(outfile, O_WRONLY | O_CREAT, 0644)) < 0)
  122. err(1, "open %s", outfile);
  123. /* write file header */
  124. if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
  125. err(1, "write");
  126. SLIST_FOREACH(p, &files, next) {
  127. write_packets(p, fd);
  128. }
  129. return 0;
  130. }
  131. /* Read all the file headers and set the pcap_file_header for output file */
  132. void
  133. init_files(int len, char *filelist[])
  134. {
  135. struct pcap_file_header phdr;
  136. struct pcap_file *file;
  137. int i, fd, modified, swapped;
  138. u_int32_t snaplen, linktype;
  139. snaplen = linktype = 0;
  140. for (i = 0; i < len; i++) {
  141. if ((fd = open(filelist[i], O_RDONLY, 0)) < 0) {
  142. warn("skipping %s: could not open", filelist[i]);
  143. close(fd);
  144. continue;
  145. }
  146. if (read(fd, (void *)&phdr, sizeof(phdr)) != sizeof(phdr)) {
  147. warn("skipping %s: could not read header", filelist[i]);
  148. close(fd);
  149. continue;
  150. }
  151. switch (phdr.magic) {
  152. case PCAP_MAGIC:
  153. swapped = 0;
  154. modified = 0;
  155. break;
  156. case PCAP_SWAPPED_MAGIC:
  157. swapped = 1;
  158. modified = 0;
  159. break;
  160. case PCAP_MODIFIED_MAGIC:
  161. swapped = 0;
  162. modified = 1;
  163. break;
  164. case PCAP_SWAPPED_MODIFIED_MAGIC:
  165. swapped = 1;
  166. modified = 1;
  167. break;
  168. default:
  169. warn("skipping %s: invalid pcap", filelist[i]);
  170. close(fd);
  171. continue;
  172. }
  173. /* ensure everything is in host-byte order */
  174. if (swapped) {
  175. phdr.snaplen = SWAPLONG(phdr.snaplen);
  176. phdr.linktype = SWAPLONG(phdr.linktype);
  177. }
  178. if (linktype == 0) {
  179. linktype = phdr.linktype;
  180. }
  181. else if (linktype != phdr.linktype) {
  182. warn("skipping %s: inconsistent linktype", filelist[i]);
  183. close(fd);
  184. continue;
  185. }
  186. /* pick the largest snaplen */
  187. if (phdr.snaplen > snaplen)
  188. snaplen = phdr.snaplen;
  189. if ((file = (struct pcap_file *)malloc(sizeof(*file))) == NULL)
  190. errx(1, "out of memory");
  191. file->fd = fd;
  192. file->modified = modified;
  193. file->swapped = swapped;
  194. file->name = filelist[i];
  195. SLIST_INSERT_HEAD(&files, file, next);
  196. }
  197. /* set the header for the output file */
  198. hdr.magic = PCAP_MAGIC;
  199. hdr.version_major = 2;
  200. hdr.version_minor = 4;
  201. hdr.thiszone = 0;
  202. hdr.sigfigs = 0;
  203. hdr.snaplen = snaplen;
  204. hdr.linktype = linktype;
  205. }
  206. void
  207. write_packets(struct pcap_file *p, int out)
  208. {
  209. struct pcap_pkthdr p1, *phdr;
  210. struct pcap_mod_pkthdr p2;
  211. char pkt[MAXPACKET];
  212. int len, ret;
  213. for (;;) {
  214. if (p->modified) {
  215. ret = read(p->fd, &p2, sizeof(p2));
  216. if (ret == -1)
  217. err(1, "read");
  218. else if (ret == 0)
  219. break;
  220. phdr = &p2.hdr;
  221. }
  222. else {
  223. ret = read(p->fd, &p1, sizeof(p1));
  224. if (ret == -1)
  225. err(1, "read");
  226. else if (ret == 0)
  227. break;
  228. phdr = &p1;
  229. }
  230. if (p->swapped) {
  231. len = SWAPLONG(phdr->caplen);
  232. phdr->ts.tv_sec = SWAPLONG(phdr->ts.tv_sec);
  233. phdr->ts.tv_usec = SWAPLONG(phdr->ts.tv_usec);
  234. phdr->caplen = SWAPLONG(phdr->caplen);
  235. phdr->len = SWAPLONG(phdr->len);
  236. }
  237. else {
  238. len = phdr->caplen;
  239. }
  240. if (len > MAXPACKET) {
  241. warn("skipping %s: abnormally large packet (%d bytes)", p->name,
  242. len);
  243. break;
  244. }
  245. ret = read(p->fd, pkt, len);
  246. if (ret == -1)
  247. err(1, "read");
  248. else if (ret == 0) {
  249. warn("skipping %s: truncated packet3", p->name);
  250. break;
  251. }
  252. if (write(out, phdr, sizeof(*phdr)) != sizeof(*phdr))
  253. err(1, "write");
  254. if (write(out, pkt, len) != len)
  255. err(1, "write");
  256. }
  257. close(p->fd);
  258. }
  259. void
  260. usage()
  261. {
  262. fprintf(stderr, "usage: pcapmerge -o bigpcap pcap1 pcap2 pcap3 ..\n");
  263. exit(1);
  264. }