fluffy

Network Archaeology tools for Unix
git clone https://git.woozle.org/neale/fluffy.git

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}