117683Spst/*
239291Sfenner * Copyright (c) 1993, 1994, 1995, 1996, 1997
317683Spst *	The Regents of the University of California.  All rights reserved.
417683Spst *
517683Spst * Redistribution and use in source and binary forms, with or without
617683Spst * modification, are permitted provided that: (1) source code distributions
717683Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817683Spst * distributions including binary code include the above copyright notice and
917683Spst * this paragraph in its entirety in the documentation or other materials
1017683Spst * provided with the distribution, and (3) all advertising materials mentioning
1117683Spst * features or use of this software display the following acknowledgement:
1217683Spst * ``This product includes software developed by the University of California,
1317683Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417683Spst * the University nor the names of its contributors may be used to endorse
1517683Spst * or promote products derived from this software without specific prior
1617683Spst * written permission.
1717683Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817683Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917683Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2026175Sfenner *
2117683Spst * savefile.c - supports offline use of tcpdump
2217683Spst *	Extraction/creation by Jeffrey Mogul, DECWRL
2317683Spst *	Modified by Steve McCanne, LBL.
2417683Spst *
2517683Spst * Used to save the received packet headers, after filtering, to
2617683Spst * a file, and then read them later.
2717683Spst * The first record in the file contains saved values for the machine
2817683Spst * dependent values so we can print the dump file on any architecture.
2917683Spst */
3017683Spst
3126175Sfenner#ifndef lint
32127664Sbmsstatic const char rcsid[] _U_ =
33214518Srpaulo    "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.183 2008-12-23 20:13:29 guy Exp $ (LBL)";
3426175Sfenner#endif
3526175Sfenner
3675107Sfenner#ifdef HAVE_CONFIG_H
3775107Sfenner#include "config.h"
3875107Sfenner#endif
3975107Sfenner
40214518Srpaulo#ifdef WIN32
41214518Srpaulo#include <pcap-stdinc.h>
42214518Srpaulo#else /* WIN32 */
43214518Srpaulo#if HAVE_INTTYPES_H
44214518Srpaulo#include <inttypes.h>
45214518Srpaulo#elif HAVE_STDINT_H
46214518Srpaulo#include <stdint.h>
47214518Srpaulo#endif
48214518Srpaulo#ifdef HAVE_SYS_BITYPES_H
49214518Srpaulo#include <sys/bitypes.h>
50214518Srpaulo#endif
51214518Srpaulo#include <sys/types.h>
52214518Srpaulo#endif /* WIN32 */
53214518Srpaulo
5417683Spst#include <errno.h>
5517683Spst#include <memory.h>
5617683Spst#include <stdio.h>
5717683Spst#include <stdlib.h>
5875107Sfenner#include <string.h>
5917683Spst
6017683Spst#include "pcap-int.h"
61190225Srpaulo#include "pcap/usb.h"
6217683Spst
6317683Spst#ifdef HAVE_OS_PROTO_H
6417683Spst#include "os-proto.h"
6517683Spst#endif
6617683Spst
67214518Srpaulo#include "sf-pcap.h"
68214518Srpaulo#include "sf-pcap-ng.h"
6917683Spst
7017683Spst/*
71146768Ssam * Setting O_BINARY on DOS/Windows is a bit tricky
72146768Ssam */
73146768Ssam#if defined(WIN32)
74147894Ssam  #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
75146768Ssam#elif defined(MSDOS)
76146768Ssam  #if defined(__HIGHC__)
77146768Ssam  #define SET_BINMODE(f)  setmode(f, O_BINARY)
78146768Ssam  #else
79146768Ssam  #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
80146768Ssam  #endif
81146768Ssam#endif
82146768Ssam
8317683Spststatic int
84127664Sbmssf_getnonblock(pcap_t *p, char *errbuf)
85127664Sbms{
86127664Sbms	/*
87127664Sbms	 * This is a savefile, not a live capture file, so never say
88127664Sbms	 * it's in non-blocking mode.
89127664Sbms	 */
90127664Sbms	return (0);
91127664Sbms}
92127664Sbms
93127664Sbmsstatic int
94127664Sbmssf_setnonblock(pcap_t *p, int nonblock, char *errbuf)
95127664Sbms{
96127664Sbms	/*
97235426Sdelphij	 * This is a savefile, not a live capture file, so reject
98235426Sdelphij	 * requests to put it in non-blocking mode.  (If it's a
99235426Sdelphij	 * pipe, it could be put in non-blocking mode, but that
100235426Sdelphij	 * would significantly complicate the code to read packets,
101235426Sdelphij	 * as it would have to handle reading partial packets and
102235426Sdelphij	 * keeping the state of the read.)
103127664Sbms	 */
104235426Sdelphij	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
105235426Sdelphij	    "Savefiles cannot be put into non-blocking mode");
106235426Sdelphij	return (-1);
107127664Sbms}
108127664Sbms
109127664Sbmsstatic int
110127664Sbmssf_stats(pcap_t *p, struct pcap_stat *ps)
111127664Sbms{
112127664Sbms	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
113127664Sbms	    "Statistics aren't available from savefiles");
114127664Sbms	return (-1);
115127664Sbms}
116127664Sbms
117190225Srpaulo#ifdef WIN32
118146768Ssamstatic int
119190225Srpaulosf_setbuff(pcap_t *p, int dim)
120190225Srpaulo{
121190225Srpaulo	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
122190225Srpaulo	    "The kernel buffer size cannot be set while reading from a file");
123190225Srpaulo	return (-1);
124190225Srpaulo}
125190225Srpaulo
126190225Srpaulostatic int
127190225Srpaulosf_setmode(pcap_t *p, int mode)
128190225Srpaulo{
129190225Srpaulo	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
130190225Srpaulo	    "impossible to set mode while reading from a file");
131190225Srpaulo	return (-1);
132190225Srpaulo}
133190225Srpaulo
134190225Srpaulostatic int
135190225Srpaulosf_setmintocopy(pcap_t *p, int size)
136190225Srpaulo{
137190225Srpaulo	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
138190225Srpaulo	    "The mintocopy parameter cannot be set while reading from a file");
139190225Srpaulo	return (-1);
140190225Srpaulo}
141190225Srpaulo#endif
142190225Srpaulo
143190225Srpaulostatic int
144146768Ssamsf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
145146768Ssam{
146146768Ssam	strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
147146768Ssam	    PCAP_ERRBUF_SIZE);
148146768Ssam	return (-1);
149146768Ssam}
150146768Ssam
151147894Ssam/*
152147894Ssam * Set direction flag: Which packets do we accept on a forwarding
153147894Ssam * single device? IN, OUT or both?
154147894Ssam */
155147894Ssamstatic int
156162012Ssamsf_setdirection(pcap_t *p, pcap_direction_t d)
157147894Ssam{
158147894Ssam	snprintf(p->errbuf, sizeof(p->errbuf),
159147894Ssam	    "Setting direction is not supported on savefiles");
160147894Ssam	return (-1);
161147894Ssam}
162147894Ssam
163127664Sbmsstatic void
164190225Srpaulosf_cleanup(pcap_t *p)
165127664Sbms{
166127664Sbms	if (p->sf.rfile != stdin)
167127664Sbms		(void)fclose(p->sf.rfile);
168214518Srpaulo	if (p->buffer != NULL)
169214518Srpaulo		free(p->buffer);
170235426Sdelphij	pcap_freecode(&p->fcode);
171127664Sbms}
172127664Sbms
17317683Spstpcap_t *
17439291Sfennerpcap_open_offline(const char *fname, char *errbuf)
17517683Spst{
176146768Ssam	FILE *fp;
177146768Ssam	pcap_t *p;
178146768Ssam
179146768Ssam	if (fname[0] == '-' && fname[1] == '\0')
180147894Ssam	{
181146768Ssam		fp = stdin;
182147894Ssam#if defined(WIN32) || defined(MSDOS)
183147894Ssam		/*
184147894Ssam		 * We're reading from the standard input, so put it in binary
185147894Ssam		 * mode, as savefiles are binary files.
186147894Ssam		 */
187147894Ssam		SET_BINMODE(fp);
188147894Ssam#endif
189147894Ssam	}
190146768Ssam	else {
191146768Ssam#if !defined(WIN32) && !defined(MSDOS)
192146768Ssam		fp = fopen(fname, "r");
193146768Ssam#else
194146768Ssam		fp = fopen(fname, "rb");
195146768Ssam#endif
196146768Ssam		if (fp == NULL) {
197146768Ssam			snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname,
198146768Ssam			    pcap_strerror(errno));
199146768Ssam			return (NULL);
200146768Ssam		}
201146768Ssam	}
202146768Ssam	p = pcap_fopen_offline(fp, errbuf);
203146768Ssam	if (p == NULL) {
204146768Ssam		if (fp != stdin)
205146768Ssam			fclose(fp);
206146768Ssam	}
207146768Ssam	return (p);
208146768Ssam}
209146768Ssam
210190225Srpaulo#ifdef WIN32
211190225Srpaulopcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf)
212190225Srpaulo{
213190225Srpaulo	int fd;
214190225Srpaulo	FILE *file;
215190225Srpaulo
216190225Srpaulo	fd = _open_osfhandle(osfd, _O_RDONLY);
217190225Srpaulo	if ( fd < 0 )
218190225Srpaulo	{
219190225Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
220190225Srpaulo		return NULL;
221190225Srpaulo	}
222190225Srpaulo
223190225Srpaulo	file = _fdopen(fd, "rb");
224190225Srpaulo	if ( file == NULL )
225190225Srpaulo	{
226190225Srpaulo		snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
227190225Srpaulo		return NULL;
228190225Srpaulo	}
229190225Srpaulo
230190225Srpaulo	return pcap_fopen_offline(file, errbuf);
231190225Srpaulo}
232190225Srpaulo#endif
233190225Srpaulo
234214518Srpaulostatic int (*check_headers[])(pcap_t *, bpf_u_int32, FILE *, char *) = {
235214518Srpaulo	pcap_check_header,
236214518Srpaulo	pcap_ng_check_header
237214518Srpaulo};
238214518Srpaulo
239214518Srpaulo#define	N_FILE_TYPES	(sizeof check_headers / sizeof check_headers[0])
240214518Srpaulo
241190225Srpaulo#ifdef WIN32
242190225Srpaulostatic
243190225Srpaulo#endif
244146768Ssampcap_t *
245146768Ssampcap_fopen_offline(FILE *fp, char *errbuf)
246146768Ssam{
24717683Spst	register pcap_t *p;
248214518Srpaulo	bpf_u_int32 magic;
249146768Ssam	size_t amt_read;
250214518Srpaulo	u_int i;
25117683Spst
252214518Srpaulo	p = pcap_create_common("(savefile)", errbuf);
253214518Srpaulo	if (p == NULL)
25417683Spst		return (NULL);
25517683Spst
256214518Srpaulo	/*
257214518Srpaulo	 * Read the first 4 bytes of the file; the network analyzer dump
258214518Srpaulo	 * file formats we support (pcap and pcap-ng), and several other
259214518Srpaulo	 * formats we might support in the future (such as snoop, DOS and
260214518Srpaulo	 * Windows Sniffer, and Microsoft Network Monitor) all have magic
261214518Srpaulo	 * numbers that are unique in their first 4 bytes.
262214518Srpaulo	 */
263214518Srpaulo	amt_read = fread((char *)&magic, 1, sizeof(magic), fp);
264214518Srpaulo	if (amt_read != sizeof(magic)) {
265146768Ssam		if (ferror(fp)) {
266146768Ssam			snprintf(errbuf, PCAP_ERRBUF_SIZE,
267146768Ssam			    "error reading dump file: %s",
26875107Sfenner			    pcap_strerror(errno));
269146768Ssam		} else {
270146768Ssam			snprintf(errbuf, PCAP_ERRBUF_SIZE,
271146768Ssam			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
272214518Srpaulo			    (unsigned long)sizeof(magic),
273146768Ssam			    (unsigned long)amt_read);
27417683Spst		}
27517683Spst		goto bad;
27617683Spst	}
277214518Srpaulo
278214518Srpaulo	/*
279214518Srpaulo	 * Try all file types.
280214518Srpaulo	 */
281214518Srpaulo	for (i = 0; i < N_FILE_TYPES; i++) {
282214518Srpaulo		switch ((*check_headers[i])(p, magic, fp, errbuf)) {
283214518Srpaulo
284214518Srpaulo		case -1:
285214518Srpaulo			/*
286214518Srpaulo			 * Error trying to read the header.
287214518Srpaulo			 */
28817683Spst			goto bad;
289214518Srpaulo
290214518Srpaulo		case 1:
291214518Srpaulo			/*
292214518Srpaulo			 * Yup, that's it.
293214518Srpaulo			 */
294214518Srpaulo			goto found;
29517683Spst		}
29617683Spst	}
29717683Spst
298214518Srpaulo	/*
299214518Srpaulo	 * Well, who knows what this mess is....
300214518Srpaulo	 */
301214518Srpaulo	snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
302214518Srpaulo	goto bad;
30317683Spst
304214518Srpaulofound:
305214518Srpaulo	p->sf.rfile = fp;
30617683Spst
30717683Spst#ifdef PCAP_FDDIPAD
308146768Ssam	/* Padding only needed for live capture fcode */
309146768Ssam	p->fddipad = 0;
31017683Spst#endif
31117683Spst
312146768Ssam#if !defined(WIN32) && !defined(MSDOS)
313127664Sbms	/*
314127664Sbms	 * You can do "select()" and "poll()" on plain files on most
315127664Sbms	 * platforms, and should be able to do so on pipes.
316127664Sbms	 *
317127664Sbms	 * You can't do "select()" on anything other than sockets in
318127664Sbms	 * Windows, so, on Win32 systems, we don't have "selectable_fd".
319127664Sbms	 */
320127664Sbms	p->selectable_fd = fileno(fp);
321127664Sbms#endif
322127664Sbms
323127664Sbms	p->read_op = pcap_offline_read;
324146768Ssam	p->inject_op = sf_inject;
325127664Sbms	p->setfilter_op = install_bpf_program;
326147894Ssam	p->setdirection_op = sf_setdirection;
327127664Sbms	p->set_datalink_op = NULL;	/* we don't support munging link-layer headers */
328127664Sbms	p->getnonblock_op = sf_getnonblock;
329127664Sbms	p->setnonblock_op = sf_setnonblock;
330127664Sbms	p->stats_op = sf_stats;
331190225Srpaulo#ifdef WIN32
332190225Srpaulo	p->setbuff_op = sf_setbuff;
333190225Srpaulo	p->setmode_op = sf_setmode;
334190225Srpaulo	p->setmintocopy_op = sf_setmintocopy;
335190225Srpaulo#endif
336190225Srpaulo	p->cleanup_op = sf_cleanup;
337190225Srpaulo	p->activated = 1;
338127664Sbms
33917683Spst	return (p);
34017683Spst bad:
34117683Spst	free(p);
34217683Spst	return (NULL);
34317683Spst}
34417683Spst
34517683Spst/*
346214518Srpaulo * Read packets from a capture file, and call the callback for each
347214518Srpaulo * packet.
34817683Spst * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
34917683Spst */
35017683Spstint
35117683Spstpcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
35217683Spst{
353146768Ssam	struct bpf_insn *fcode;
35417683Spst	int status = 0;
35517683Spst	int n = 0;
356214518Srpaulo	u_char *data;
35717683Spst
35817683Spst	while (status == 0) {
35917683Spst		struct pcap_pkthdr h;
36017683Spst
361127664Sbms		/*
362127664Sbms		 * Has "pcap_breakloop()" been called?
363127664Sbms		 * If so, return immediately - if we haven't read any
364127664Sbms		 * packets, clear the flag and return -2 to indicate
365127664Sbms		 * that we were told to break out of the loop, otherwise
366127664Sbms		 * leave the flag set, so that the *next* call will break
367127664Sbms		 * out of the loop without having read any packets, and
368127664Sbms		 * return the number of packets we've processed so far.
369127664Sbms		 */
370127664Sbms		if (p->break_loop) {
371127664Sbms			if (n == 0) {
372127664Sbms				p->break_loop = 0;
373127664Sbms				return (-2);
374127664Sbms			} else
375127664Sbms				return (n);
376127664Sbms		}
377127664Sbms
378214518Srpaulo		status = p->sf.next_packet_op(p, &h, &data);
37917683Spst		if (status) {
38017683Spst			if (status == 1)
38117683Spst				return (0);
38217683Spst			return (status);
38317683Spst		}
38417683Spst
385146768Ssam		if ((fcode = p->fcode.bf_insns) == NULL ||
386235426Sdelphij		    bpf_filter(fcode, data, h.len, h.caplen)) {
387214518Srpaulo			(*callback)(user, &h, data);
38817683Spst			if (++n >= cnt && cnt > 0)
38917683Spst				break;
39017683Spst		}
39117683Spst	}
39217683Spst	/*XXX this breaks semantics tcpslice expects */
39317683Spst	return (n);
39417683Spst}
395