Neale Pickett
·
2020-09-21
pmerge.c
1#include <stdio.h>
2#include <stdint.h>
3#include <sysexits.h>
4#include "pcap.h"
5
6struct input_file {
7 int active;
8 struct pcap_file p;
9 struct pcap_pkthdr next;
10};
11
12int
13usage(int ret)
14{
15 fprintf(stderr, "Usage: pmerge FILE ...\n");
16 fprintf(stderr, "\n");
17 fprintf(stderr, "Merges pcap files, outputting time-ordered pcap stream\n");
18 return ret;
19}
20
21int
22read_next(struct input_file *file)
23{
24 if (!file->active)
25 return -1;
26
27 if (-1 == pcap_read_pkthdr(&file->p, &file->next)) {
28 pcap_close(&file->p);
29 file->active = 0;
30 file->next.ts.tv_sec = 0xffffffff;
31 file->next.ts.tv_usec = 0xffffffff;
32 return -1;
33 }
34
35 return 0;
36}
37
38int
39main(int argc, char *argv[])
40{
41 struct input_file files[argc - 1];
42 int nfiles = 0;
43 int nopen;
44 int i;
45 struct pcap_file out;
46
47 if (1 == argc)
48 return usage(0);
49
50 /*
51 * Open input files
52 */
53 int32_t linktype = 0;
54 for (i = 0; i < argc - 1; i += 1) {
55 char *fn = argv[i + 1];
56 struct input_file *cur = &files[nfiles];
57 FILE *f;
58
59 if ('-' == fn[0])
60 return usage(0);
61
62 f = fopen(fn, "rb");
63 if (NULL == f) {
64 perror(fn);
65 return EX_NOINPUT;
66 }
67
68 if (-1 == pcap_open_in(&cur->p, f)) {
69 fprintf(stderr, "%s: unable to process\n", fn);
70 return EX_IOERR;
71 }
72 if (i == 0) {
73 linktype = cur->p.linktype;
74 } else if (linktype != cur->p.linktype) {
75 fprintf(stderr, "%s: incompatible linktype with first file\n", fn);
76 return EX_IOERR;
77 }
78 cur->active = 1;
79
80 if (0 == read_next(cur)) {
81 nfiles += 1;
82 }
83 }
84
85 if (-1 == pcap_open_out_linktype(&out, stdout, linktype)) {
86 perror("writing header");
87 return EX_IOERR;
88 }
89
90 nopen = nfiles;
91 while (nopen) {
92 struct input_file *cur = &files[0];
93 char frame[MAXFRAME];
94 size_t len;
95
96 /*
97 * Find next oldest frame
98 */
99 for (i = 0; i < nfiles; i += 1) {
100 if (files[i].active &&
101 ((files[i].next.ts.tv_sec < cur->next.ts.tv_sec) ||
102 ((files[i].next.ts.tv_sec == cur->next.ts.tv_sec) &&
103 (files[i].next.ts.tv_usec < cur->next.ts.tv_usec)))) {
104 cur = &files[i];
105 }
106 }
107
108 /*
109 * Make sure it'll fit
110 */
111 if (cur->next.caplen > sizeof(frame)) {
112 fprintf(stderr, "error: huge frame (size %u)\n", (unsigned int) cur->next.caplen);
113 return EX_SOFTWARE;
114 }
115
116 /*
117 * Read it
118 */
119 len = fread(frame, 1, cur->next.caplen, cur->p.f);
120 if (len < cur->next.caplen) {
121 /*
122 * Short read
123 */
124 cur->next.caplen = len;
125 pcap_close(&cur->p);
126 cur->active = 0;
127 }
128
129 /*
130 * Write header + frame
131 */
132 if (len) {
133 if (1 != fwrite(&cur->next, sizeof(cur->next), 1, stdout)) {
134 perror("error");
135 return EX_IOERR;
136 }
137 if (len != fwrite(frame, 1, len, stdout)) {
138 perror("error");
139 return EX_IOERR;
140 }
141 }
142
143 if (-1 == read_next(cur)) {
144 nopen -= 1;
145 }
146 }
147
148 return 0;
149}