1/*
2 * Copyright (c) 1993, 1994, 1995, 1996, 1997
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * savefile.c - supports offline use of tcpdump
22 *	Extraction/creation by Jeffrey Mogul, DECWRL
23 *	Modified by Steve McCanne, LBL.
24 *
25 * Used to save the received packet headers, after filtering, to
26 * a file, and then read them later.
27 * The first record in the file contains saved values for the machine
28 * dependent values so we can print the dump file on any architecture.
29 */
30
31#ifndef lint
32static const char rcsid[] _U_ =
33    "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.183 2008-12-23 20:13:29 guy Exp $ (LBL)";
34#endif
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40#ifdef WIN32
41#include <pcap-stdinc.h>
42#else /* WIN32 */
43#if HAVE_INTTYPES_H
44#include <inttypes.h>
45#elif HAVE_STDINT_H
46#include <stdint.h>
47#endif
48#ifdef HAVE_SYS_BITYPES_H
49#include <sys/bitypes.h>
50#endif
51#include <sys/types.h>
52#endif /* WIN32 */
53
54#include <errno.h>
55#include <memory.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59
60#include "pcap-int.h"
61#include "pcap/usb.h"
62
63#ifdef HAVE_OS_PROTO_H
64#include "os-proto.h"
65#endif
66
67#include "sf-pcap.h"
68#include "sf-pcap-ng.h"
69
70/*
71 * Setting O_BINARY on DOS/Windows is a bit tricky
72 */
73#if defined(WIN32)
74  #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
75#elif defined(MSDOS)
76  #if defined(__HIGHC__)
77  #define SET_BINMODE(f)  setmode(f, O_BINARY)
78  #else
79  #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
80  #endif
81#endif
82
83static int
84sf_getnonblock(pcap_t *p, char *errbuf)
85{
86	/*
87	 * This is a savefile, not a live capture file, so never say
88	 * it's in non-blocking mode.
89	 */
90	return (0);
91}
92
93static int
94sf_setnonblock(pcap_t *p, int nonblock, char *errbuf)
95{
96	/*
97	 * This is a savefile, not a live capture file, so reject
98	 * requests to put it in non-blocking mode.  (If it's a
99	 * pipe, it could be put in non-blocking mode, but that
100	 * would significantly complicate the code to read packets,
101	 * as it would have to handle reading partial packets and
102	 * keeping the state of the read.)
103	 */
104	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
105	    "Savefiles cannot be put into non-blocking mode");
106	return (-1);
107}
108
109static int
110sf_stats(pcap_t *p, struct pcap_stat *ps)
111{
112	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
113	    "Statistics aren't available from savefiles");
114	return (-1);
115}
116
117#ifdef WIN32
118static int
119sf_setbuff(pcap_t *p, int dim)
120{
121	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
122	    "The kernel buffer size cannot be set while reading from a file");
123	return (-1);
124}
125
126static int
127sf_setmode(pcap_t *p, int mode)
128{
129	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
130	    "impossible to set mode while reading from a file");
131	return (-1);
132}
133
134static int
135sf_setmintocopy(pcap_t *p, int size)
136{
137	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
138	    "The mintocopy parameter cannot be set while reading from a file");
139	return (-1);
140}
141#endif
142
143static int
144sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
145{
146	strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
147	    PCAP_ERRBUF_SIZE);
148	return (-1);
149}
150
151/*
152 * Set direction flag: Which packets do we accept on a forwarding
153 * single device? IN, OUT or both?
154 */
155static int
156sf_setdirection(pcap_t *p, pcap_direction_t d)
157{
158	snprintf(p->errbuf, sizeof(p->errbuf),
159	    "Setting direction is not supported on savefiles");
160	return (-1);
161}
162
163static void
164sf_cleanup(pcap_t *p)
165{
166	if (p->sf.rfile != stdin)
167		(void)fclose(p->sf.rfile);
168	if (p->buffer != NULL)
169		free(p->buffer);
170	pcap_freecode(&p->fcode);
171}
172
173pcap_t *
174pcap_open_offline(const char *fname, char *errbuf)
175{
176	FILE *fp;
177	pcap_t *p;
178
179	if (fname[0] == '-' && fname[1] == '\0')
180	{
181		fp = stdin;
182#if defined(WIN32) || defined(MSDOS)
183		/*
184		 * We're reading from the standard input, so put it in binary
185		 * mode, as savefiles are binary files.
186		 */
187		SET_BINMODE(fp);
188#endif
189	}
190	else {
191#if !defined(WIN32) && !defined(MSDOS)
192		fp = fopen(fname, "r");
193#else
194		fp = fopen(fname, "rb");
195#endif
196		if (fp == NULL) {
197			snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname,
198			    pcap_strerror(errno));
199			return (NULL);
200		}
201	}
202	p = pcap_fopen_offline(fp, errbuf);
203	if (p == NULL) {
204		if (fp != stdin)
205			fclose(fp);
206	}
207	return (p);
208}
209
210#ifdef WIN32
211pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf)
212{
213	int fd;
214	FILE *file;
215
216	fd = _open_osfhandle(osfd, _O_RDONLY);
217	if ( fd < 0 )
218	{
219		snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
220		return NULL;
221	}
222
223	file = _fdopen(fd, "rb");
224	if ( file == NULL )
225	{
226		snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
227		return NULL;
228	}
229
230	return pcap_fopen_offline(file, errbuf);
231}
232#endif
233
234static int (*check_headers[])(pcap_t *, bpf_u_int32, FILE *, char *) = {
235	pcap_check_header,
236	pcap_ng_check_header
237};
238
239#define	N_FILE_TYPES	(sizeof check_headers / sizeof check_headers[0])
240
241#ifdef WIN32
242static
243#endif
244pcap_t *
245pcap_fopen_offline(FILE *fp, char *errbuf)
246{
247	register pcap_t *p;
248	bpf_u_int32 magic;
249	size_t amt_read;
250	u_int i;
251
252	p = pcap_create_common("(savefile)", errbuf);
253	if (p == NULL)
254		return (NULL);
255
256	/*
257	 * Read the first 4 bytes of the file; the network analyzer dump
258	 * file formats we support (pcap and pcap-ng), and several other
259	 * formats we might support in the future (such as snoop, DOS and
260	 * Windows Sniffer, and Microsoft Network Monitor) all have magic
261	 * numbers that are unique in their first 4 bytes.
262	 */
263	amt_read = fread((char *)&magic, 1, sizeof(magic), fp);
264	if (amt_read != sizeof(magic)) {
265		if (ferror(fp)) {
266			snprintf(errbuf, PCAP_ERRBUF_SIZE,
267			    "error reading dump file: %s",
268			    pcap_strerror(errno));
269		} else {
270			snprintf(errbuf, PCAP_ERRBUF_SIZE,
271			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
272			    (unsigned long)sizeof(magic),
273			    (unsigned long)amt_read);
274		}
275		goto bad;
276	}
277
278	/*
279	 * Try all file types.
280	 */
281	for (i = 0; i < N_FILE_TYPES; i++) {
282		switch ((*check_headers[i])(p, magic, fp, errbuf)) {
283
284		case -1:
285			/*
286			 * Error trying to read the header.
287			 */
288			goto bad;
289
290		case 1:
291			/*
292			 * Yup, that's it.
293			 */
294			goto found;
295		}
296	}
297
298	/*
299	 * Well, who knows what this mess is....
300	 */
301	snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
302	goto bad;
303
304found:
305	p->sf.rfile = fp;
306
307#ifdef PCAP_FDDIPAD
308	/* Padding only needed for live capture fcode */
309	p->fddipad = 0;
310#endif
311
312#if !defined(WIN32) && !defined(MSDOS)
313	/*
314	 * You can do "select()" and "poll()" on plain files on most
315	 * platforms, and should be able to do so on pipes.
316	 *
317	 * You can't do "select()" on anything other than sockets in
318	 * Windows, so, on Win32 systems, we don't have "selectable_fd".
319	 */
320	p->selectable_fd = fileno(fp);
321#endif
322
323	p->read_op = pcap_offline_read;
324	p->inject_op = sf_inject;
325	p->setfilter_op = install_bpf_program;
326	p->setdirection_op = sf_setdirection;
327	p->set_datalink_op = NULL;	/* we don't support munging link-layer headers */
328	p->getnonblock_op = sf_getnonblock;
329	p->setnonblock_op = sf_setnonblock;
330	p->stats_op = sf_stats;
331#ifdef WIN32
332	p->setbuff_op = sf_setbuff;
333	p->setmode_op = sf_setmode;
334	p->setmintocopy_op = sf_setmintocopy;
335#endif
336	p->cleanup_op = sf_cleanup;
337	p->activated = 1;
338
339	return (p);
340 bad:
341	free(p);
342	return (NULL);
343}
344
345/*
346 * Read packets from a capture file, and call the callback for each
347 * packet.
348 * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
349 */
350int
351pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
352{
353	struct bpf_insn *fcode;
354	int status = 0;
355	int n = 0;
356	u_char *data;
357
358	while (status == 0) {
359		struct pcap_pkthdr h;
360
361		/*
362		 * Has "pcap_breakloop()" been called?
363		 * If so, return immediately - if we haven't read any
364		 * packets, clear the flag and return -2 to indicate
365		 * that we were told to break out of the loop, otherwise
366		 * leave the flag set, so that the *next* call will break
367		 * out of the loop without having read any packets, and
368		 * return the number of packets we've processed so far.
369		 */
370		if (p->break_loop) {
371			if (n == 0) {
372				p->break_loop = 0;
373				return (-2);
374			} else
375				return (n);
376		}
377
378		status = p->sf.next_packet_op(p, &h, &data);
379		if (status) {
380			if (status == 1)
381				return (0);
382			return (status);
383		}
384
385		if ((fcode = p->fcode.bf_insns) == NULL ||
386		    bpf_filter(fcode, data, h.len, h.caplen)) {
387			(*callback)(user, &h, data);
388			if (++n >= cnt && cnt > 0)
389				break;
390		}
391	}
392	/*XXX this breaks semantics tcpslice expects */
393	return (n);
394}
395