sf-pcap.c revision 214455
1184610Salfred/*
2184610Salfred * Copyright (c) 1993, 1994, 1995, 1996, 1997
3184610Salfred *	The Regents of the University of California.  All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that: (1) source code distributions
7184610Salfred * retain the above copyright notice and this paragraph in its entirety, (2)
8184610Salfred * distributions including binary code include the above copyright notice and
9184610Salfred * this paragraph in its entirety in the documentation or other materials
10184610Salfred * provided with the distribution, and (3) all advertising materials mentioning
11184610Salfred * features or use of this software display the following acknowledgement:
12184610Salfred * ``This product includes software developed by the University of California,
13184610Salfred * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14184610Salfred * the University nor the names of its contributors may be used to endorse
15184610Salfred * or promote products derived from this software without specific prior
16184610Salfred * written permission.
17184610Salfred * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18184610Salfred * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19184610Salfred * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20184610Salfred *
21184610Salfred * sf-pcap.c - libpcap-file-format-specific code from savefile.c
22184610Salfred *	Extraction/creation by Jeffrey Mogul, DECWRL
23184610Salfred *	Modified by Steve McCanne, LBL.
24184610Salfred *
25184610Salfred * Used to save the received packet headers, after filtering, to
26184610Salfred * a file, and then read them later.
27190754Sthompsa * The first record in the file contains saved values for the machine
28184610Salfred * dependent values so we can print the dump file on any architecture.
29194677Sthompsa */
30194677Sthompsa
31194677Sthompsa#ifndef lint
32194677Sthompsastatic const char rcsid[] _U_ =
33194677Sthompsa    "@(#) $Header$ (LBL)";
34194677Sthompsa#endif
35194677Sthompsa
36194677Sthompsa#ifdef HAVE_CONFIG_H
37194677Sthompsa#include "config.h"
38194677Sthompsa#endif
39194677Sthompsa
40194677Sthompsa#ifdef WIN32
41194677Sthompsa#include <pcap-stdinc.h>
42194677Sthompsa#else /* WIN32 */
43194677Sthompsa#if HAVE_INTTYPES_H
44194677Sthompsa#include <inttypes.h>
45194677Sthompsa#elif HAVE_STDINT_H
46194677Sthompsa#include <stdint.h>
47194677Sthompsa#endif
48188942Sthompsa#ifdef HAVE_SYS_BITYPES_H
49194677Sthompsa#include <sys/bitypes.h>
50194677Sthompsa#endif
51188942Sthompsa#include <sys/types.h>
52188942Sthompsa#endif /* WIN32 */
53184610Salfred
54194228Sthompsa#include <errno.h>
55184610Salfred#include <memory.h>
56188942Sthompsa#include <stdio.h>
57188942Sthompsa#include <stdlib.h>
58188942Sthompsa#include <string.h>
59188942Sthompsa
60188942Sthompsa#include "pcap-int.h"
61188942Sthompsa
62188942Sthompsa#include "pcap-common.h"
63188942Sthompsa
64188942Sthompsa#ifdef HAVE_OS_PROTO_H
65184610Salfred#include "os-proto.h"
66188942Sthompsa#endif
67188942Sthompsa
68184610Salfred#include "sf-pcap.h"
69184610Salfred
70225000Shselasky/*
71225000Shselasky * Setting O_BINARY on DOS/Windows is a bit tricky
72225000Shselasky */
73225000Shselasky#if defined(WIN32)
74225000Shselasky  #define SET_BINMODE(f)  _setmode(_fileno(f), _O_BINARY)
75207077Sthompsa#elif defined(MSDOS)
76194228Sthompsa  #if defined(__HIGHC__)
77194228Sthompsa  #define SET_BINMODE(f)  setmode(f, O_BINARY)
78184610Salfred  #else
79192502Sthompsa  #define SET_BINMODE(f)  setmode(fileno(f), O_BINARY)
80194228Sthompsa  #endif
81192502Sthompsa#endif
82194228Sthompsa
83184610Salfred/*
84208018Sthompsa * Standard libpcap format.
85208018Sthompsa */
86208018Sthompsa#define TCPDUMP_MAGIC		0xa1b2c3d4
87208018Sthompsa
88208018Sthompsa/*
89208018Sthompsa * Alexey Kuznetzov's modified libpcap format.
90208018Sthompsa */
91208018Sthompsa#define KUZNETZOV_TCPDUMP_MAGIC	0xa1b2cd34
92208018Sthompsa
93208018Sthompsa/*
94208018Sthompsa * Reserved for Francisco Mesquita <francisco.mesquita@radiomovel.pt>
95208018Sthompsa * for another modified format.
96208018Sthompsa */
97208018Sthompsa#define FMESQUITA_TCPDUMP_MAGIC	0xa1b234cd
98208018Sthompsa
99208018Sthompsa/*
100208018Sthompsa * Navtel Communcations' format, with nanosecond timestamps,
101208018Sthompsa * as per a request from Dumas Hwang <dumas.hwang@navtelcom.com>.
102208018Sthompsa */
103208018Sthompsa#define NAVTEL_TCPDUMP_MAGIC	0xa12b3c4d
104208018Sthompsa
105208018Sthompsa/*
106208018Sthompsa * Normal libpcap format, except for seconds/nanoseconds timestamps,
107208018Sthompsa * as per a request by Ulf Lamping <ulf.lamping@web.de>
108208018Sthompsa */
109208018Sthompsa#define NSEC_TCPDUMP_MAGIC	0xa1b23c4d
110208018Sthompsa
111208018Sthompsa/*
112208018Sthompsa * Mechanism for storing information about a capture in the upper
113208018Sthompsa * 6 bits of a linktype value in a capture file.
114208018Sthompsa *
115208018Sthompsa * LT_LINKTYPE_EXT(x) extracts the additional information.
116208018Sthompsa *
117208018Sthompsa * The rest of the bits are for a value describing the link-layer
118208018Sthompsa * value.  LT_LINKTYPE(x) extracts that value.
119208018Sthompsa */
120208018Sthompsa#define LT_LINKTYPE(x)		((x) & 0x03FFFFFF)
121208018Sthompsa#define LT_LINKTYPE_EXT(x)	((x) & 0xFC000000)
122208018Sthompsa
123208018Sthompsastatic int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap);
124208018Sthompsa
125208018Sthompsa/*
126208018Sthompsa * Check whether this is a pcap savefile and, if it is, extract the
127208018Sthompsa * relevant information from the header.
128208018Sthompsa */
129208018Sthompsaint
130208018Sthompsapcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
131184610Salfred{
132208018Sthompsa	struct pcap_file_header hdr;
133208018Sthompsa	size_t amt_read;
134208018Sthompsa
135208018Sthompsa	/*
136208018Sthompsa	 * Check whether the first 4 bytes of the file are the magic
137208018Sthompsa	 * number for a pcap savefile, or for a byte-swapped pcap
138208018Sthompsa	 * savefile.
139208018Sthompsa	 */
140208018Sthompsa	if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) {
141208018Sthompsa		magic = SWAPLONG(magic);
142208018Sthompsa		if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC)
143208018Sthompsa			return (0);	/* nope */
144208018Sthompsa		p->sf.swapped = 1;
145208018Sthompsa	}
146208018Sthompsa
147208018Sthompsa	/*
148208018Sthompsa	 * They are.  Put the magic number in the header, and read
149208018Sthompsa	 * the rest of the header.
150208018Sthompsa	 */
151208018Sthompsa	hdr.magic = magic;
152208018Sthompsa	amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1,
153208018Sthompsa	    sizeof(hdr) - sizeof(hdr.magic), fp);
154208018Sthompsa	if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) {
155208018Sthompsa		if (ferror(fp)) {
156208018Sthompsa			snprintf(errbuf, PCAP_ERRBUF_SIZE,
157208018Sthompsa			    "error reading dump file: %s",
158208018Sthompsa			    pcap_strerror(errno));
159208018Sthompsa		} else {
160208018Sthompsa			snprintf(errbuf, PCAP_ERRBUF_SIZE,
161208018Sthompsa			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
162208018Sthompsa			    (unsigned long)sizeof(hdr),
163208018Sthompsa			    (unsigned long)amt_read);
164208018Sthompsa		}
165208018Sthompsa		return (-1);
166208018Sthompsa	}
167208018Sthompsa
168208018Sthompsa	/*
169208018Sthompsa	 * If it's a byte-swapped capture file, byte-swap the header.
170208018Sthompsa	 */
171208018Sthompsa	if (p->sf.swapped) {
172208018Sthompsa		hdr.version_major = SWAPSHORT(hdr.version_major);
173208018Sthompsa		hdr.version_minor = SWAPSHORT(hdr.version_minor);
174208018Sthompsa		hdr.thiszone = SWAPLONG(hdr.thiszone);
175208018Sthompsa		hdr.sigfigs = SWAPLONG(hdr.sigfigs);
176208018Sthompsa		hdr.snaplen = SWAPLONG(hdr.snaplen);
177208018Sthompsa		hdr.linktype = SWAPLONG(hdr.linktype);
178208018Sthompsa	}
179208018Sthompsa
180208018Sthompsa	if (hdr.version_major < PCAP_VERSION_MAJOR) {
181208018Sthompsa		snprintf(errbuf, PCAP_ERRBUF_SIZE,
182208018Sthompsa		    "archaic pcap savefile format");
183208018Sthompsa		return (-1);
184208018Sthompsa	}
185208018Sthompsa	p->sf.version_major = hdr.version_major;
186208018Sthompsa	p->sf.version_minor = hdr.version_minor;
187208018Sthompsa	p->tzoff = hdr.thiszone;
188208018Sthompsa	p->snapshot = hdr.snaplen;
189208018Sthompsa	p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype));
190208018Sthompsa	p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype);
191208018Sthompsa
192208018Sthompsa	p->sf.next_packet_op = pcap_next_packet;
193208018Sthompsa
194208018Sthompsa	/*
195208018Sthompsa	 * We interchanged the caplen and len fields at version 2.3,
196194228Sthompsa	 * in order to match the bpf header layout.  But unfortunately
197184610Salfred	 * some files were written with version 2.3 in their headers
198184610Salfred	 * but without the interchanged fields.
199184610Salfred	 *
200184610Salfred	 * In addition, DG/UX tcpdump writes out files with a version
201184610Salfred	 * number of 543.0, and with the caplen and len fields in the
202194677Sthompsa	 * pre-2.3 order.
203184610Salfred	 */
204184610Salfred	switch (hdr.version_major) {
205184610Salfred
206184610Salfred	case 2:
207184610Salfred		if (hdr.version_minor < 3)
208184610Salfred			p->sf.lengths_swapped = SWAPPED;
209184610Salfred		else if (hdr.version_minor == 3)
210194228Sthompsa			p->sf.lengths_swapped = MAYBE_SWAPPED;
211184610Salfred		else
212184610Salfred			p->sf.lengths_swapped = NOT_SWAPPED;
213207079Sthompsa		break;
214184610Salfred
215184610Salfred	case 543:
216184610Salfred		p->sf.lengths_swapped = SWAPPED;
217184610Salfred		break;
218184610Salfred
219194228Sthompsa	default:
220184610Salfred		p->sf.lengths_swapped = NOT_SWAPPED;
221184610Salfred		break;
222184610Salfred	}
223184610Salfred
224194677Sthompsa	if (magic == KUZNETZOV_TCPDUMP_MAGIC) {
225184610Salfred		/*
226192984Sthompsa		 * XXX - the patch that's in some versions of libpcap
227192984Sthompsa		 * changes the packet header but not the magic number,
228193644Sthompsa		 * and some other versions with this magic number have
229193644Sthompsa		 * some extra debugging information in the packet header;
230193644Sthompsa		 * we'd have to use some hacks^H^H^H^H^Hheuristics to
231190731Sthompsa		 * detect those variants.
232184610Salfred		 *
233187173Sthompsa		 * Ethereal does that, but it does so by trying to read
234184610Salfred		 * the first two packets of the file with each of the
235187173Sthompsa		 * record header formats.  That currently means it seeks
236187173Sthompsa		 * backwards and retries the reads, which doesn't work
237193644Sthompsa		 * on pipes.  We want to be able to read from a pipe, so
238184610Salfred		 * that strategy won't work; we'd have to buffer some
239193644Sthompsa		 * data ourselves and read from that buffer in order to
240193644Sthompsa		 * make that work.
241193644Sthompsa		 */
242193644Sthompsa		p->sf.hdrsize = sizeof(struct pcap_sf_patched_pkthdr);
243193318Sthompsa
244184610Salfred		if (p->linktype == DLT_EN10MB) {
245184610Salfred			/*
246225000Shselasky			 * This capture might have been done in raw mode
247222786Shselasky			 * or cooked mode.
248222786Shselasky			 *
249222786Shselasky			 * If it was done in cooked mode, p->snapshot was
250193644Sthompsa			 * passed to recvfrom() as the buffer size, meaning
251193318Sthompsa			 * that the most packet data that would be copied
252193644Sthompsa			 * would be p->snapshot.  However, a faked Ethernet
253193644Sthompsa			 * header would then have been added to it, so the
254193644Sthompsa			 * most data that would be in a packet in the file
255193644Sthompsa			 * would be p->snapshot + 14.
256213435Shselasky			 *
257213435Shselasky			 * We can't easily tell whether the capture was done
258184610Salfred			 * in raw mode or cooked mode, so we'll assume it was
259194228Sthompsa			 * cooked mode, and add 14 to the snapshot length.
260193644Sthompsa			 * That means that, for a raw capture, the snapshot
261184610Salfred			 * length will be misleading if you use it to figure
262193644Sthompsa			 * out why a capture doesn't have all the packet data,
263184610Salfred			 * but there's not much we can do to avoid that.
264184610Salfred			 */
265184610Salfred			p->snapshot += 14;
266193318Sthompsa		}
267193644Sthompsa	} else
268193644Sthompsa		p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr);
269193644Sthompsa
270193644Sthompsa	/*
271193644Sthompsa	 * Allocate a buffer for the packet data.
272184610Salfred	 */
273184610Salfred	p->bufsize = p->snapshot;
274184610Salfred	if (p->bufsize <= 0)
275184610Salfred		p->bufsize = BPF_MAXBUFSIZE;
276184610Salfred	p->buffer = malloc(p->bufsize);
277184610Salfred	if (p->buffer == NULL) {
278193644Sthompsa		snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
279184610Salfred		return (-1);
280184610Salfred	}
281184610Salfred
282184610Salfred	return (1);
283184610Salfred}
284194228Sthompsa
285184610Salfred/*
286184610Salfred * Read and return the next packet from the savefile.  Return the header
287194677Sthompsa * in hdr and a pointer to the contents in data.  Return 0 on success, 1
288184610Salfred * if there were no more packets, and -1 on an error.
289187173Sthompsa */
290184610Salfredstatic int
291194228Sthompsapcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
292184610Salfred{
293187173Sthompsa	struct pcap_sf_patched_pkthdr sf_hdr;
294184610Salfred	FILE *fp = p->sf.rfile;
295184610Salfred	size_t amt_read;
296193644Sthompsa	bpf_u_int32 t;
297193318Sthompsa
298193318Sthompsa	/*
299184610Salfred	 * Read the packet header; the structure we use as a buffer
300184610Salfred	 * is the longer structure for files generated by the patched
301222786Shselasky	 * libpcap, but if the file has the magic number for an
302184610Salfred	 * unpatched libpcap we only read as many bytes as the regular
303222786Shselasky	 * header has.
304222786Shselasky	 */
305225000Shselasky	amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp);
306225000Shselasky	if (amt_read != p->sf.hdrsize) {
307225000Shselasky		if (ferror(fp)) {
308225000Shselasky			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
309225000Shselasky			    "error reading dump file: %s",
310225000Shselasky			    pcap_strerror(errno));
311225000Shselasky			return (-1);
312222786Shselasky		} else {
313222786Shselasky			if (amt_read != 0) {
314222786Shselasky				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
315222786Shselasky				    "truncated dump file; tried to read %lu header bytes, only got %lu",
316222786Shselasky				    (unsigned long)p->sf.hdrsize,
317222786Shselasky				    (unsigned long)amt_read);
318222786Shselasky				return (-1);
319222786Shselasky			}
320222786Shselasky			/* EOF */
321222786Shselasky			return (1);
322222786Shselasky		}
323222786Shselasky	}
324222786Shselasky
325184610Salfred	if (p->sf.swapped) {
326184610Salfred		/* these were written in opposite byte order */
327184610Salfred		hdr->caplen = SWAPLONG(sf_hdr.caplen);
328184610Salfred		hdr->len = SWAPLONG(sf_hdr.len);
329193644Sthompsa		hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
330193644Sthompsa		hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
331187173Sthompsa	} else {
332184610Salfred		hdr->caplen = sf_hdr.caplen;
333184610Salfred		hdr->len = sf_hdr.len;
334193045Sthompsa		hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
335194228Sthompsa		hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
336191402Sthompsa	}
337191402Sthompsa	/* Swap the caplen and len fields, if necessary. */
338192499Sthompsa	switch (p->sf.lengths_swapped) {
339194228Sthompsa
340191402Sthompsa	case NOT_SWAPPED:
341191402Sthompsa		break;
342191402Sthompsa
343191402Sthompsa	case MAYBE_SWAPPED:
344191402Sthompsa		if (hdr->caplen <= hdr->len) {
345191402Sthompsa			/*
346184610Salfred			 * The captured length is <= the actual length,
347194228Sthompsa			 * so presumably they weren't swapped.
348184610Salfred			 */
349184610Salfred			break;
350184610Salfred		}
351192984Sthompsa		/* FALLTHROUGH */
352184610Salfred
353184610Salfred	case SWAPPED:
354184610Salfred		t = hdr->caplen;
355184610Salfred		hdr->caplen = hdr->len;
356184610Salfred		hdr->len = t;
357184610Salfred		break;
358184610Salfred	}
359184610Salfred
360184610Salfred	if (hdr->caplen > p->bufsize) {
361184610Salfred		/*
362184610Salfred		 * This can happen due to Solaris 2.3 systems tripping
363184610Salfred		 * over the BUFMOD problem and not setting the snapshot
364184610Salfred		 * correctly in the savefile header.  If the caplen isn't
365184610Salfred		 * grossly wrong, try to salvage.
366184610Salfred		 */
367184610Salfred		static u_char *tp = NULL;
368184610Salfred		static size_t tsize = 0;
369184610Salfred
370184610Salfred		if (hdr->caplen > 65535) {
371184610Salfred			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
372184610Salfred			    "bogus savefile header");
373184610Salfred			return (-1);
374184610Salfred		}
375184610Salfred
376184610Salfred		if (tsize < hdr->caplen) {
377184610Salfred			tsize = ((hdr->caplen + 1023) / 1024) * 1024;
378184610Salfred			if (tp != NULL)
379184610Salfred				free((u_char *)tp);
380184610Salfred			tp = (u_char *)malloc(tsize);
381184610Salfred			if (tp == NULL) {
382184610Salfred				tsize = 0;
383184610Salfred				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
384184610Salfred				    "BUFMOD hack malloc");
385184610Salfred				return (-1);
386184610Salfred			}
387184610Salfred		}
388184610Salfred		amt_read = fread((char *)tp, 1, hdr->caplen, fp);
389184610Salfred		if (amt_read != hdr->caplen) {
390184610Salfred			if (ferror(fp)) {
391184610Salfred				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
392184610Salfred				    "error reading dump file: %s",
393184610Salfred				    pcap_strerror(errno));
394194228Sthompsa			} else {
395184610Salfred				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
396184610Salfred				    "truncated dump file; tried to read %u captured bytes, only got %lu",
397184610Salfred				    hdr->caplen, (unsigned long)amt_read);
398184610Salfred			}
399184610Salfred			return (-1);
400184610Salfred		}
401193045Sthompsa		/*
402194228Sthompsa		 * We can only keep up to p->bufsize bytes.  Since
403192984Sthompsa		 * caplen > p->bufsize is exactly how we got here,
404193045Sthompsa		 * we know we can only keep the first p->bufsize bytes
405184610Salfred		 * and must drop the remainder.  Adjust caplen accordingly,
406208018Sthompsa		 * so we don't get confused later as to how many bytes we
407208018Sthompsa		 * have to play with.
408208018Sthompsa		 */
409193045Sthompsa		hdr->caplen = p->bufsize;
410192984Sthompsa		memcpy(p->buffer, (char *)tp, p->bufsize);
411184610Salfred	} else {
412184610Salfred		/* read the packet itself */
413193045Sthompsa		amt_read = fread(p->buffer, 1, hdr->caplen, fp);
414193045Sthompsa		if (amt_read != hdr->caplen) {
415193045Sthompsa			if (ferror(fp)) {
416184610Salfred				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
417184610Salfred				    "error reading dump file: %s",
418208018Sthompsa				    pcap_strerror(errno));
419208008Sthompsa			} else {
420184610Salfred				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
421184610Salfred				    "truncated dump file; tried to read %u captured bytes, only got %lu",
422184610Salfred				    hdr->caplen, (unsigned long)amt_read);
423184610Salfred			}
424184610Salfred			return (-1);
425184610Salfred		}
426184610Salfred	}
427184610Salfred	*data = p->buffer;
428184610Salfred
429184610Salfred	if (p->sf.swapped) {
430184610Salfred		/*
431208008Sthompsa		 * Convert pseudo-headers from the byte order of
432208008Sthompsa		 * the host on which the file was saved to our
433184610Salfred		 * byte order, as necessary.
434184610Salfred		 */
435184610Salfred		switch (p->linktype) {
436184610Salfred
437184610Salfred		case DLT_USB_LINUX:
438184610Salfred			swap_linux_usb_header(hdr, *data, 0);
439184610Salfred			break;
440191494Sthompsa
441191494Sthompsa		case DLT_USB_LINUX_MMAPPED:
442191494Sthompsa			swap_linux_usb_header(hdr, *data, 1);
443191494Sthompsa			break;
444191494Sthompsa		}
445191494Sthompsa	}
446184610Salfred
447184610Salfred	return (0);
448184610Salfred}
449184610Salfred
450190735Sthompsastatic int
451184610Salfredsf_write_header(FILE *fp, int linktype, int thiszone, int snaplen)
452190735Sthompsa{
453190180Sthompsa	struct pcap_file_header hdr;
454190180Sthompsa
455190180Sthompsa	hdr.magic = TCPDUMP_MAGIC;
456190180Sthompsa	hdr.version_major = PCAP_VERSION_MAJOR;
457208008Sthompsa	hdr.version_minor = PCAP_VERSION_MINOR;
458184610Salfred
459208008Sthompsa	hdr.thiszone = thiszone;
460184610Salfred	hdr.snaplen = snaplen;
461208008Sthompsa	hdr.sigfigs = 0;
462184610Salfred	hdr.linktype = linktype;
463208008Sthompsa
464208008Sthompsa	if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
465208008Sthompsa		return (-1);
466208008Sthompsa
467208008Sthompsa	return (0);
468208008Sthompsa}
469208008Sthompsa
470184610Salfred/*
471184610Salfred * Output a packet to the initialized dump file.
472184610Salfred */
473207079Sthompsavoid
474184610Salfredpcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
475194228Sthompsa{
476190735Sthompsa	register FILE *f;
477191402Sthompsa	struct pcap_sf_pkthdr sf_hdr;
478191402Sthompsa
479190735Sthompsa	f = (FILE *)user;
480191402Sthompsa	sf_hdr.ts.tv_sec  = h->ts.tv_sec;
481191402Sthompsa	sf_hdr.ts.tv_usec = h->ts.tv_usec;
482191402Sthompsa	sf_hdr.caplen     = h->caplen;
483191402Sthompsa	sf_hdr.len        = h->len;
484190735Sthompsa	/* XXX we should check the return status */
485191402Sthompsa	(void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
486191402Sthompsa	(void)fwrite(sp, h->caplen, 1, f);
487191402Sthompsa}
488191402Sthompsa
489190735Sthompsastatic pcap_dumper_t *
490190735Sthompsapcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
491190735Sthompsa{
492191402Sthompsa
493191402Sthompsa#if defined(WIN32) || defined(MSDOS)
494190735Sthompsa	/*
495191402Sthompsa	 * If we're writing to the standard output, put it in binary
496190735Sthompsa	 * mode, as savefiles are binary files.
497190735Sthompsa	 *
498190735Sthompsa	 * Otherwise, we turn off buffering.
499190735Sthompsa	 * XXX - why?  And why not on the standard output?
500190735Sthompsa	 */
501191402Sthompsa	if (f == stdout)
502190735Sthompsa		SET_BINMODE(f);
503190735Sthompsa	else
504190735Sthompsa		setbuf(f, NULL);
505190735Sthompsa#endif
506191402Sthompsa	if (sf_write_header(f, linktype, p->tzoff, p->snapshot) == -1) {
507190735Sthompsa		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s",
508190735Sthompsa		    fname, pcap_strerror(errno));
509190735Sthompsa		if (f != stdout)
510190735Sthompsa			(void)fclose(f);
511190735Sthompsa		return (NULL);
512190735Sthompsa	}
513190735Sthompsa	return ((pcap_dumper_t *)f);
514191402Sthompsa}
515190735Sthompsa
516190735Sthompsa/*
517190735Sthompsa * Initialize so that sf_write() will output to the file named 'fname'.
518190735Sthompsa */
519190735Sthompsapcap_dumper_t *
520191402Sthompsapcap_dump_open(pcap_t *p, const char *fname)
521190735Sthompsa{
522191402Sthompsa	FILE *f;
523190735Sthompsa	int linktype;
524190735Sthompsa
525184610Salfred	/*
526184610Salfred	 * If this pcap_t hasn't been activated, it doesn't have a
527184610Salfred	 * link-layer type, so we can't use it.
528207080Sthompsa	 */
529184610Salfred	if (!p->activated) {
530207080Sthompsa		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
531184610Salfred		    "%s: not-yet-activated pcap_t passed to pcap_dump_open",
532184610Salfred		    fname);
533184610Salfred		return (NULL);
534184610Salfred	}
535184610Salfred	linktype = dlt_to_linktype(p->linktype);
536208018Sthompsa	if (linktype == -1) {
537208018Sthompsa		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
538208018Sthompsa		    "%s: link-layer type %d isn't supported in savefiles",
539208018Sthompsa		    fname, p->linktype);
540208018Sthompsa		return (NULL);
541208018Sthompsa	}
542208018Sthompsa	linktype |= p->linktype_ext;
543208018Sthompsa
544208018Sthompsa	if (fname[0] == '-' && fname[1] == '\0') {
545184824Sthompsa		f = stdout;
546184610Salfred		fname = "standard output";
547190734Sthompsa	} else {
548184610Salfred#if !defined(WIN32) && !defined(MSDOS)
549190734Sthompsa		f = fopen(fname, "w");
550184610Salfred#else
551184610Salfred		f = fopen(fname, "wb");
552190734Sthompsa#endif
553190734Sthompsa		if (f == NULL) {
554190734Sthompsa			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
555190734Sthompsa			    fname, pcap_strerror(errno));
556190734Sthompsa			return (NULL);
557184610Salfred		}
558184610Salfred	}
559184610Salfred	return (pcap_setup_dump(p, linktype, f, fname));
560184610Salfred}
561184610Salfred
562184610Salfred/*
563194228Sthompsa * Initialize so that sf_write() will output to the given stream.
564184610Salfred */
565194677Sthompsapcap_dumper_t *
566184610Salfredpcap_dump_fopen(pcap_t *p, FILE *f)
567184610Salfred{
568184610Salfred	int linktype;
569208018Sthompsa
570194677Sthompsa	linktype = dlt_to_linktype(p->linktype);
571184610Salfred	if (linktype == -1) {
572208018Sthompsa		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
573208018Sthompsa		    "stream: link-layer type %d isn't supported in savefiles",
574208018Sthompsa		    p->linktype);
575208018Sthompsa		return (NULL);
576208018Sthompsa	}
577208018Sthompsa	linktype |= p->linktype_ext;
578208018Sthompsa
579208018Sthompsa	return (pcap_setup_dump(p, linktype, f, "stream"));
580208018Sthompsa}
581208018Sthompsa
582208018SthompsaFILE *
583208018Sthompsapcap_dump_file(pcap_dumper_t *p)
584208018Sthompsa{
585208018Sthompsa	return ((FILE *)p);
586208018Sthompsa}
587208018Sthompsa
588208018Sthompsalong
589208018Sthompsapcap_dump_ftell(pcap_dumper_t *p)
590208018Sthompsa{
591208018Sthompsa	return (ftell((FILE *)p));
592194677Sthompsa}
593184610Salfred
594184610Salfredint
595184610Salfredpcap_dump_flush(pcap_dumper_t *p)
596190180Sthompsa{
597184610Salfred
598184824Sthompsa	if (fflush((FILE *)p) == EOF)
599194228Sthompsa		return (-1);
600184610Salfred	else
601184824Sthompsa		return (0);
602184610Salfred}
603184610Salfred
604184610Salfredvoid
605184610Salfredpcap_dump_close(pcap_dumper_t *p)
606190180Sthompsa{
607190180Sthompsa
608194228Sthompsa#ifdef notyet
609190180Sthompsa	if (ferror((FILE *)p))
610184610Salfred		return-an-error;
611208018Sthompsa	/* XXX should check return from fclose() too */
612184610Salfred#endif
613208018Sthompsa	(void)fclose((FILE *)p);
614184610Salfred}
615208018Sthompsa