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
70static pcap_t *
71pcap_fopen_offline_internal(FILE *fp, u_int precision,
72			    char *errbuf, int isng);
73
74
75/*
76 * Setting O_BINARY on DOS/Windows is a bit tricky
77 */
78#if defined(WIN32)
79  #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
80#elif defined(MSDOS)
81  #if defined(__HIGHC__)
82  #define SET_BINMODE(f)  setmode(f, O_BINARY)
83  #else
84  #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
85  #endif
86#endif
87
88static int
89sf_getnonblock(pcap_t *p, char *errbuf)
90{
91	/*
92	 * This is a savefile, not a live capture file, so never say
93	 * it's in non-blocking mode.
94	 */
95	return (0);
96}
97
98static int
99sf_setnonblock(pcap_t *p, int nonblock, char *errbuf)
100{
101	/*
102	 * This is a savefile, not a live capture file, so reject
103	 * requests to put it in non-blocking mode.  (If it's a
104	 * pipe, it could be put in non-blocking mode, but that
105	 * would significantly complicate the code to read packets,
106	 * as it would have to handle reading partial packets and
107	 * keeping the state of the read.)
108	 */
109	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
110	    "Savefiles cannot be put into non-blocking mode");
111	return (-1);
112}
113
114static int
115sf_stats(pcap_t *p, struct pcap_stat *ps)
116{
117	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
118	    "Statistics aren't available from savefiles");
119	return (-1);
120}
121
122#ifdef WIN32
123static int
124sf_setbuff(pcap_t *p, int dim)
125{
126	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
127	    "The kernel buffer size cannot be set while reading from a file");
128	return (-1);
129}
130
131static int
132sf_setmode(pcap_t *p, int mode)
133{
134	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
135	    "impossible to set mode while reading from a file");
136	return (-1);
137}
138
139static int
140sf_setmintocopy(pcap_t *p, int size)
141{
142	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
143	    "The mintocopy parameter cannot be set while reading from a file");
144	return (-1);
145}
146#endif
147
148static int
149sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
150{
151	strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
152	    PCAP_ERRBUF_SIZE);
153	return (-1);
154}
155
156/*
157 * Set direction flag: Which packets do we accept on a forwarding
158 * single device? IN, OUT or both?
159 */
160static int
161sf_setdirection(pcap_t *p, pcap_direction_t d)
162{
163	snprintf(p->errbuf, sizeof(p->errbuf),
164	    "Setting direction is not supported on savefiles");
165	return (-1);
166}
167
168void
169sf_cleanup(pcap_t *p)
170{
171	if (p->rfile != stdin)
172		(void)fclose(p->rfile);
173	if (p->buffer != NULL)
174		free(p->buffer);
175	pcap_freecode(&p->fcode);
176}
177
178pcap_t *
179pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
180    char *errbuf)
181{
182	FILE *fp;
183	pcap_t *p;
184
185	if (fname[0] == '-' && fname[1] == '\0')
186	{
187		fp = stdin;
188#if defined(WIN32) || defined(MSDOS)
189		/*
190		 * We're reading from the standard input, so put it in binary
191		 * mode, as savefiles are binary files.
192		 */
193		SET_BINMODE(fp);
194#endif
195	}
196	else {
197#if !defined(WIN32) && !defined(MSDOS)
198		fp = fopen(fname, "r");
199#else
200		fp = fopen(fname, "rb");
201#endif
202		if (fp == NULL) {
203			snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname,
204			    pcap_strerror(errno));
205			return (NULL);
206		}
207	}
208	p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf);
209	if (p == NULL) {
210		if (fp != stdin)
211			fclose(fp);
212	}
213	return (p);
214}
215
216pcap_t *
217pcap_open_offline(const char *fname, char *errbuf)
218{
219	return (pcap_open_offline_with_tstamp_precision(fname,
220	    PCAP_TSTAMP_PRECISION_MICRO, errbuf));
221}
222
223#ifdef WIN32
224pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision,
225    char *errbuf)
226{
227	int fd;
228	FILE *file;
229
230	fd = _open_osfhandle(osfd, _O_RDONLY);
231	if ( fd < 0 )
232	{
233		snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
234		return NULL;
235	}
236
237	file = _fdopen(fd, "rb");
238	if ( file == NULL )
239	{
240		snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
241		return NULL;
242	}
243
244	return pcap_fopen_offline_with_tstamp_precision(file, precision,
245	    errbuf);
246}
247
248pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf)
249{
250	return pcap_hopen_offline_with_tstamp_precision(osfd,
251	    PCAP_TSTAMP_PRECISION_MICRO, errbuf);
252}
253#endif
254
255static pcap_t *(*check_headers[])(bpf_u_int32, FILE *, u_int, char *, int *, int) = {
256	pcap_check_header,
257	pcap_ng_check_header
258};
259
260#define	N_FILE_TYPES	(sizeof check_headers / sizeof check_headers[0])
261
262#ifdef WIN32
263static
264#endif
265pcap_t *
266pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
267    char *errbuf)
268{
269	return pcap_fopen_offline_internal(fp, precision, errbuf, 0);
270}
271
272#ifdef __APPLE__
273
274pcap_t *
275pcap_ng_open_offline(const char *fname, char *errbuf)
276{
277	FILE *fp;
278	pcap_t *p;
279
280	if (fname[0] == '-' && fname[1] == '\0')
281	{
282		fp = stdin;
283#if defined(WIN32) || defined(MSDOS)
284		/*
285		 * We're reading from the standard input, so put it in binary
286		 * mode, as savefiles are binary files.
287		 */
288		SET_BINMODE(fp);
289#endif
290	}
291	else {
292#if !defined(WIN32) && !defined(MSDOS)
293		fp = fopen(fname, "r");
294#else
295		fp = fopen(fname, "rb");
296#endif
297		if (fp == NULL) {
298			snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname,
299				 pcap_strerror(errno));
300			return (NULL);
301		}
302	}
303	p = pcap_fopen_offline_internal(fp,
304					  PCAP_TSTAMP_PRECISION_MICRO,
305					  errbuf, 1);
306	if (p == NULL) {
307		if (fp != stdin)
308			fclose(fp);
309	}
310	return (p);
311}
312
313pcap_t *
314pcap_ng_fopen_offline(FILE *fp, char *errbuf)
315{
316	return pcap_fopen_offline_internal(fp,
317					   PCAP_TSTAMP_PRECISION_MICRO,
318					   errbuf, 1);
319}
320
321#endif /* __APPLE__ */
322
323static pcap_t *
324pcap_fopen_offline_internal(FILE *fp, u_int precision,
325    char *errbuf, int isng)
326{
327	register pcap_t *p = NULL;
328	bpf_u_int32 magic;
329	size_t amt_read;
330	u_int i;
331	int err;
332	off_t offset = ftello(fp);
333
334	/*
335	 * Read the first 4 bytes of the file; the network analyzer dump
336	 * file formats we support (pcap and pcap-ng), and several other
337	 * formats we might support in the future (such as snoop, DOS and
338	 * Windows Sniffer, and Microsoft Network Monitor) all have magic
339	 * numbers that are unique in their first 4 bytes.
340	 */
341	amt_read = fread((char *)&magic, 1, sizeof(magic), fp);
342	if (amt_read != sizeof(magic)) {
343		if (ferror(fp)) {
344			snprintf(errbuf, PCAP_ERRBUF_SIZE,
345			    "error reading dump file: %s",
346			    pcap_strerror(errno));
347		} else {
348			snprintf(errbuf, PCAP_ERRBUF_SIZE,
349			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
350			    (unsigned long)sizeof(magic),
351			    (unsigned long)amt_read);
352		}
353		goto bad;
354	}
355
356	/*
357	 * When using the PCAP-NG extension APIs we are expected a PCAP-NG file
358	 */
359	if (isng) {
360		p = pcap_ng_check_header(magic, fp, precision, errbuf, &err, isng);
361		if (p != NULL) {
362				/*
363				 * Yup, that's a PCAP-NG file.
364				 */
365				goto found;
366		}
367		/*
368		 * That's not a PCAP-NG file
369		 */
370		snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
371		goto bad;
372	}
373	/*
374	 * Try all file types.
375	 */
376	for (i = 0; i < N_FILE_TYPES; i++) {
377		p = (*check_headers[i])(magic, fp, precision, errbuf, &err, isng);
378		if (p != NULL) {
379			/* Yup, that's it. */
380			goto found;
381		}
382		if (err) {
383			/*
384			 * Error trying to read the header.
385			 */
386			snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
387			goto bad;
388		}
389	}
390
391	/*
392	 * Well, who knows what this mess is....
393	 */
394	snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
395	goto bad;
396
397found:
398	p->rfile = fp;
399
400	/* Padding only needed for live capture fcode */
401	p->fddipad = 0;
402
403#if !defined(WIN32) && !defined(MSDOS)
404	/*
405	 * You can do "select()" and "poll()" on plain files on most
406	 * platforms, and should be able to do so on pipes.
407	 *
408	 * You can't do "select()" on anything other than sockets in
409	 * Windows, so, on Win32 systems, we don't have "selectable_fd".
410	 */
411	p->selectable_fd = fileno(fp);
412#endif
413
414	p->read_op = isng ? pcap_ng_offline_read : pcap_offline_read;
415	p->inject_op = sf_inject;
416	p->setfilter_op = install_bpf_program;
417	p->setdirection_op = sf_setdirection;
418	p->set_datalink_op = NULL;	/* we don't support munging link-layer headers */
419	p->getnonblock_op = sf_getnonblock;
420	p->setnonblock_op = sf_setnonblock;
421	p->stats_op = sf_stats;
422#ifdef WIN32
423	p->setbuff_op = sf_setbuff;
424	p->setmode_op = sf_setmode;
425	p->setmintocopy_op = sf_setmintocopy;
426#endif
427
428	/*
429	 * For offline captures, the standard one-shot callback can
430	 * be used for pcap_next()/pcap_next_ex().
431	 */
432	p->oneshot_callback = pcap_oneshot;
433
434	p->cleanup_op = sf_cleanup;
435	p->activated = 1;
436
437	return (p);
438 bad:
439	fseeko(fp, offset, SEEK_SET);
440	if (p != NULL)
441		free(p);
442	return (NULL);
443}
444
445#ifdef WIN32
446static
447#endif
448pcap_t *
449pcap_fopen_offline(FILE *fp, char *errbuf)
450{
451	return (pcap_fopen_offline_with_tstamp_precision(fp,
452	    PCAP_TSTAMP_PRECISION_MICRO, errbuf));
453}
454
455/*
456 * Read packets from a capture file, and call the callback for each
457 * packet.
458 * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
459 */
460int
461pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
462{
463	struct bpf_insn *fcode;
464	int status = 0;
465	int n = 0;
466	u_char *data;
467
468	while (status == 0) {
469		struct pcap_pkthdr h;
470
471		/*
472		 * Has "pcap_breakloop()" been called?
473		 * If so, return immediately - if we haven't read any
474		 * packets, clear the flag and return -2 to indicate
475		 * that we were told to break out of the loop, otherwise
476		 * leave the flag set, so that the *next* call will break
477		 * out of the loop without having read any packets, and
478		 * return the number of packets we've processed so far.
479		 */
480		if (p->break_loop) {
481			if (n == 0) {
482				p->break_loop = 0;
483				return (-2);
484			} else
485				return (n);
486		}
487
488		status = p->next_packet_op(p, &h, &data);
489		if (status) {
490			if (status == 1)
491				return (0);
492			return (status);
493		}
494
495		if ((fcode = p->fcode.bf_insns) == NULL ||
496		    bpf_filter(fcode, data, h.len, h.caplen)) {
497			(*callback)(user, &h, data);
498			if (++n >= cnt && cnt > 0)
499				break;
500		}
501	}
502	/*XXX this breaks semantics tcpslice expects */
503	return (n);
504}
505
506/*
507 * Read blocks from a capture file, and call the callback for each
508 * packet.
509 * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
510 */
511int
512pcap_ng_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
513{
514	struct bpf_insn *fcode;
515	int status = 0;
516	int n = 0;
517	u_char *data;
518
519	while (status == 0) {
520		struct pcap_pkthdr h;
521
522		/*
523		 * Has "pcap_breakloop()" been called?
524		 * If so, return immediately - if we haven't read any
525		 * packets, clear the flag and return -2 to indicate
526		 * that we were told to break out of the loop, otherwise
527		 * leave the flag set, so that the *next* call will break
528		 * out of the loop without having read any packets, and
529		 * return the number of packets we've processed so far.
530		 */
531		if (p->break_loop) {
532			if (n == 0) {
533				p->break_loop = 0;
534				return (-2);
535			} else
536				return (n);
537		}
538
539        /*
540         * The begining of the block is always returned into p->buffer
541         * even when data is NULL (because it's not a data block)
542         */
543		status = p->next_packet_op(p, &h, &data);
544		if (status) {
545			if (status == 1)
546				return (0);
547			return (status);
548		}
549
550		/*
551		 * TBD
552		 * Have one filter per link type
553		 */
554		if ((fcode = p->fcode.bf_insns) == NULL ||
555			data == NULL ||
556		    bpf_filter(fcode, data, h.len, h.caplen)) {
557			(*callback)(user, &h, p->buffer);
558			if (++n >= cnt && cnt > 0)
559				break;
560		}
561	}
562	/*XXX this breaks semantics tcpslice expects */
563	return (n);
564}
565
566