Home | History | Annotate | Download | only in libpcap
      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  * sf-pcap.c - libpcap-file-format-specific code from savefile.c
     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
     32 static const char rcsid[] _U_ =
     33     "@(#) $Header$ (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 
     62 #include "pcap-common.h"
     63 
     64 #ifdef HAVE_OS_PROTO_H
     65 #include "os-proto.h"
     66 #endif
     67 
     68 #include "sf-pcap.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 
     83 /*
     84  * Standard libpcap format.
     85  */
     86 #define TCPDUMP_MAGIC		0xa1b2c3d4
     87 
     88 /*
     89  * Alexey Kuznetzov's modified libpcap format.
     90  */
     91 #define KUZNETZOV_TCPDUMP_MAGIC	0xa1b2cd34
     92 
     93 /*
     94  * Reserved for Francisco Mesquita <francisco.mesquita (at) radiomovel.pt>
     95  * for another modified format.
     96  */
     97 #define FMESQUITA_TCPDUMP_MAGIC	0xa1b234cd
     98 
     99 /*
    100  * Navtel Communcations' format, with nanosecond timestamps,
    101  * as per a request from Dumas Hwang <dumas.hwang (at) navtelcom.com>.
    102  */
    103 #define NAVTEL_TCPDUMP_MAGIC	0xa12b3c4d
    104 
    105 /*
    106  * Normal libpcap format, except for seconds/nanoseconds timestamps,
    107  * as per a request by Ulf Lamping <ulf.lamping (at) web.de>
    108  */
    109 #define NSEC_TCPDUMP_MAGIC	0xa1b23c4d
    110 
    111 /*
    112  * Mechanism for storing information about a capture in the upper
    113  * 6 bits of a linktype value in a capture file.
    114  *
    115  * LT_LINKTYPE_EXT(x) extracts the additional information.
    116  *
    117  * The rest of the bits are for a value describing the link-layer
    118  * value.  LT_LINKTYPE(x) extracts that value.
    119  */
    120 #define LT_LINKTYPE(x)		((x) & 0x03FFFFFF)
    121 #define LT_LINKTYPE_EXT(x)	((x) & 0xFC000000)
    122 
    123 static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap);
    124 
    125 /*
    126  * Private data for reading pcap savefiles.
    127  */
    128 typedef enum {
    129 	NOT_SWAPPED,
    130 	SWAPPED,
    131 	MAYBE_SWAPPED
    132 } swapped_type_t;
    133 
    134 typedef enum {
    135 	PASS_THROUGH,
    136 	SCALE_UP,
    137 	SCALE_DOWN
    138 } tstamp_scale_type_t;
    139 
    140 struct pcap_sf {
    141 	size_t hdrsize;
    142 	swapped_type_t lengths_swapped;
    143 	tstamp_scale_type_t scale_type;
    144 };
    145 
    146 /*
    147  * Check whether this is a pcap savefile and, if it is, extract the
    148  * relevant information from the header.
    149  */
    150 pcap_t *
    151 pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
    152 		  int *err)
    153 {
    154 	struct pcap_file_header hdr;
    155 	size_t amt_read;
    156 	pcap_t *p;
    157 	int swapped = 0;
    158 	struct pcap_sf *ps;
    159 
    160 	/*
    161 	 * Assume no read errors.
    162 	 */
    163 	*err = 0;
    164 
    165 	/*
    166 	 * Check whether the first 4 bytes of the file are the magic
    167 	 * number for a pcap savefile, or for a byte-swapped pcap
    168 	 * savefile.
    169 	 */
    170 	if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC &&
    171 	    magic != NSEC_TCPDUMP_MAGIC) {
    172 		magic = SWAPLONG(magic);
    173 		if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC &&
    174 		    magic != NSEC_TCPDUMP_MAGIC)
    175 			return (NULL);	/* nope */
    176 		swapped = 1;
    177 	}
    178 
    179 	/*
    180 	 * They are.  Put the magic number in the header, and read
    181 	 * the rest of the header.
    182 	 */
    183 	hdr.magic = magic;
    184 	amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1,
    185 	    sizeof(hdr) - sizeof(hdr.magic), fp);
    186 	if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) {
    187 		if (ferror(fp)) {
    188 			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
    189 			    "error reading dump file: %s",
    190 			    pcap_strerror(errno));
    191 		} else {
    192 			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
    193 			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
    194 			    (unsigned long)sizeof(hdr),
    195 			    (unsigned long)amt_read);
    196 		}
    197 		*err = 1;
    198 		return (NULL);
    199 	}
    200 
    201 	/*
    202 	 * If it's a byte-swapped capture file, byte-swap the header.
    203 	 */
    204 	if (swapped) {
    205 		hdr.version_major = SWAPSHORT(hdr.version_major);
    206 		hdr.version_minor = SWAPSHORT(hdr.version_minor);
    207 		hdr.thiszone = SWAPLONG(hdr.thiszone);
    208 		hdr.sigfigs = SWAPLONG(hdr.sigfigs);
    209 		hdr.snaplen = SWAPLONG(hdr.snaplen);
    210 		hdr.linktype = SWAPLONG(hdr.linktype);
    211 	}
    212 
    213 	if (hdr.version_major < PCAP_VERSION_MAJOR) {
    214 		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
    215 		    "archaic pcap savefile format");
    216 		*err = 1;
    217 		return (NULL);
    218 	}
    219 
    220 	/*
    221 	 * currently only versions 2.[0-4] are supported with
    222 	 * the exception of 543.0 for DG/UX tcpdump.
    223 	 */
    224 	if (! ((hdr.version_major == PCAP_VERSION_MAJOR &&
    225 		hdr.version_minor <= PCAP_VERSION_MINOR) ||
    226 	       (hdr.version_major == 543 &&
    227 		hdr.version_minor == 0))) {
    228 		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
    229 			 "unsupported pcap savefile version %u.%u",
    230 			 hdr.version_major, hdr.version_minor);
    231 		*err = 1;
    232 		return NULL;
    233 	}
    234 
    235 	if (hdr.snaplen > MAXIMUM_SNAPLEN) {
    236 		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
    237 			 "invalid file capture length %u, bigger than "
    238 			 "maximum of %u", hdr.snaplen, MAXIMUM_SNAPLEN);
    239 		*err = 1;
    240 		return NULL;
    241 	}
    242 
    243 	/*
    244 	 * OK, this is a good pcap file.
    245 	 * Allocate a pcap_t for it.
    246 	 */
    247 	p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf));
    248 	if (p == NULL) {
    249 		/* Allocation failed. */
    250 		*err = 1;
    251 		return (NULL);
    252 	}
    253 	p->swapped = swapped;
    254 	p->version_major = hdr.version_major;
    255 	p->version_minor = hdr.version_minor;
    256 	p->tzoff = hdr.thiszone;
    257 	p->snapshot = hdr.snaplen;
    258 	p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype));
    259 	p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype);
    260 
    261 	p->next_packet_op = pcap_next_packet;
    262 
    263 	ps = p->priv;
    264 
    265 	p->opt.tstamp_precision = precision;
    266 
    267 	/*
    268 	 * Will we need to scale the timestamps to match what the
    269 	 * user wants?
    270 	 */
    271 	switch (precision) {
    272 
    273 	case PCAP_TSTAMP_PRECISION_MICRO:
    274 		if (magic == NSEC_TCPDUMP_MAGIC) {
    275 			/*
    276 			 * The file has nanoseconds, the user
    277 			 * wants microseconds; scale the
    278 			 * precision down.
    279 			 */
    280 			ps->scale_type = SCALE_DOWN;
    281 		} else {
    282 			/*
    283 			 * The file has microseconds, the
    284 			 * user wants microseconds; nothing to do.
    285 			 */
    286 			ps->scale_type = PASS_THROUGH;
    287 		}
    288 		break;
    289 
    290 	case PCAP_TSTAMP_PRECISION_NANO:
    291 		if (magic == NSEC_TCPDUMP_MAGIC) {
    292 			/*
    293 			 * The file has nanoseconds, the
    294 			 * user wants nanoseconds; nothing to do.
    295 			 */
    296 			ps->scale_type = PASS_THROUGH;
    297 		} else {
    298 			/*
    299 			 * The file has microoseconds, the user
    300 			 * wants nanoseconds; scale the
    301 			 * precision up.
    302 			 */
    303 			ps->scale_type = SCALE_UP;
    304 		}
    305 		break;
    306 
    307 	default:
    308 		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
    309 		    "unknown time stamp resolution %u", precision);
    310 		free(p);
    311 		*err = 1;
    312 		return (NULL);
    313 	}
    314 
    315 	/*
    316 	 * We interchanged the caplen and len fields at version 2.3,
    317 	 * in order to match the bpf header layout.  But unfortunately
    318 	 * some files were written with version 2.3 in their headers
    319 	 * but without the interchanged fields.
    320 	 *
    321 	 * In addition, DG/UX tcpdump writes out files with a version
    322 	 * number of 543.0, and with the caplen and len fields in the
    323 	 * pre-2.3 order.
    324 	 */
    325 	switch (hdr.version_major) {
    326 
    327 	case 2:
    328 		if (hdr.version_minor < 3)
    329 			ps->lengths_swapped = SWAPPED;
    330 		else if (hdr.version_minor == 3)
    331 			ps->lengths_swapped = MAYBE_SWAPPED;
    332 		else
    333 			ps->lengths_swapped = NOT_SWAPPED;
    334 		break;
    335 
    336 	case 543:
    337 		ps->lengths_swapped = SWAPPED;
    338 		break;
    339 
    340 	default:
    341 		ps->lengths_swapped = NOT_SWAPPED;
    342 		break;
    343 	}
    344 
    345 	if (magic == KUZNETZOV_TCPDUMP_MAGIC) {
    346 		/*
    347 		 * XXX - the patch that's in some versions of libpcap
    348 		 * changes the packet header but not the magic number,
    349 		 * and some other versions with this magic number have
    350 		 * some extra debugging information in the packet header;
    351 		 * we'd have to use some hacks^H^H^H^H^Hheuristics to
    352 		 * detect those variants.
    353 		 *
    354 		 * Ethereal does that, but it does so by trying to read
    355 		 * the first two packets of the file with each of the
    356 		 * record header formats.  That currently means it seeks
    357 		 * backwards and retries the reads, which doesn't work
    358 		 * on pipes.  We want to be able to read from a pipe, so
    359 		 * that strategy won't work; we'd have to buffer some
    360 		 * data ourselves and read from that buffer in order to
    361 		 * make that work.
    362 		 */
    363 		ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr);
    364 
    365 		if (p->linktype == DLT_EN10MB) {
    366 			/*
    367 			 * This capture might have been done in raw mode
    368 			 * or cooked mode.
    369 			 *
    370 			 * If it was done in cooked mode, p->snapshot was
    371 			 * passed to recvfrom() as the buffer size, meaning
    372 			 * that the most packet data that would be copied
    373 			 * would be p->snapshot.  However, a faked Ethernet
    374 			 * header would then have been added to it, so the
    375 			 * most data that would be in a packet in the file
    376 			 * would be p->snapshot + 14.
    377 			 *
    378 			 * We can't easily tell whether the capture was done
    379 			 * in raw mode or cooked mode, so we'll assume it was
    380 			 * cooked mode, and add 14 to the snapshot length.
    381 			 * That means that, for a raw capture, the snapshot
    382 			 * length will be misleading if you use it to figure
    383 			 * out why a capture doesn't have all the packet data,
    384 			 * but there's not much we can do to avoid that.
    385 			 */
    386 			p->snapshot += 14;
    387 		}
    388 	} else
    389 		ps->hdrsize = sizeof(struct pcap_sf_pkthdr);
    390 
    391 	/*
    392 	 * Allocate a buffer for the packet data.
    393 	 */
    394 	p->bufsize = p->snapshot;
    395 	if (p->bufsize <= 0) {
    396 		/*
    397 		 * Bogus snapshot length; use the maximum as a fallback.
    398 		 */
    399 		p->bufsize = MAXIMUM_SNAPLEN;
    400 	}
    401 	p->buffer = malloc(p->bufsize);
    402 	if (p->buffer == NULL) {
    403 		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
    404 		free(p);
    405 		*err = 1;
    406 		return (NULL);
    407 	}
    408 
    409 	p->cleanup_op = sf_cleanup;
    410 
    411 	return (p);
    412 }
    413 
    414 /*
    415  * Read and return the next packet from the savefile.  Return the header
    416  * in hdr and a pointer to the contents in data.  Return 0 on success, 1
    417  * if there were no more packets, and -1 on an error.
    418  */
    419 static int
    420 pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
    421 {
    422 	struct pcap_sf *ps = p->priv;
    423 	struct pcap_sf_patched_pkthdr sf_hdr;
    424 	FILE *fp = p->rfile;
    425 	size_t amt_read;
    426 	bpf_u_int32 t;
    427 
    428 	/*
    429 	 * Read the packet header; the structure we use as a buffer
    430 	 * is the longer structure for files generated by the patched
    431 	 * libpcap, but if the file has the magic number for an
    432 	 * unpatched libpcap we only read as many bytes as the regular
    433 	 * header has.
    434 	 */
    435 	amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp);
    436 	if (amt_read != ps->hdrsize) {
    437 		if (ferror(fp)) {
    438 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    439 			    "error reading dump file: %s",
    440 			    pcap_strerror(errno));
    441 			return (-1);
    442 		} else {
    443 			if (amt_read != 0) {
    444 				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    445 				    "truncated dump file; tried to read %lu header bytes, only got %lu",
    446 				    (unsigned long)ps->hdrsize,
    447 				    (unsigned long)amt_read);
    448 				return (-1);
    449 			}
    450 			/* EOF */
    451 			return (1);
    452 		}
    453 	}
    454 
    455 	if (p->swapped) {
    456 		/* these were written in opposite byte order */
    457 		hdr->caplen = SWAPLONG(sf_hdr.caplen);
    458 		hdr->len = SWAPLONG(sf_hdr.len);
    459 		hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
    460 		hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
    461 	} else {
    462 		hdr->caplen = sf_hdr.caplen;
    463 		hdr->len = sf_hdr.len;
    464 		hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
    465 		hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
    466 	}
    467 
    468 	switch (ps->scale_type) {
    469 
    470 	case PASS_THROUGH:
    471 		/*
    472 		 * Just pass the time stamp through.
    473 		 */
    474 		break;
    475 
    476 	case SCALE_UP:
    477 		/*
    478 		 * File has microseconds, user wants nanoseconds; convert
    479 		 * it.
    480 		 */
    481 		hdr->ts.tv_usec = hdr->ts.tv_usec * 1000;
    482 		break;
    483 
    484 	case SCALE_DOWN:
    485 		/*
    486 		 * File has nanoseconds, user wants microseconds; convert
    487 		 * it.
    488 		 */
    489 		hdr->ts.tv_usec = hdr->ts.tv_usec / 1000;
    490 		break;
    491 	}
    492 
    493 	/* Swap the caplen and len fields, if necessary. */
    494 	switch (ps->lengths_swapped) {
    495 
    496 	case NOT_SWAPPED:
    497 		break;
    498 
    499 	case MAYBE_SWAPPED:
    500 		if (hdr->caplen <= hdr->len) {
    501 			/*
    502 			 * The captured length is <= the actual length,
    503 			 * so presumably they weren't swapped.
    504 			 */
    505 			break;
    506 		}
    507 		/* FALLTHROUGH */
    508 
    509 	case SWAPPED:
    510 		t = hdr->caplen;
    511 		hdr->caplen = hdr->len;
    512 		hdr->len = t;
    513 		break;
    514 	}
    515 
    516 	if (hdr->caplen > p->bufsize) {
    517 		/*
    518 		 * This can happen due to Solaris 2.3 systems tripping
    519 		 * over the BUFMOD problem and not setting the snapshot
    520 		 * correctly in the savefile header.
    521 		 * This can also happen with a corrupted savefile or a
    522 		 * savefile built/modified by a fuzz tester.
    523 		 * If the caplen isn't grossly wrong, try to salvage.
    524 		 */
    525 		size_t bytes_to_discard;
    526 		size_t bytes_to_read, bytes_read;
    527 		char discard_buf[4096];
    528 
    529 		if (hdr->caplen > MAXIMUM_SNAPLEN) {
    530 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    531 			    "invalid packet capture length %u, bigger than "
    532 			    "maximum of %u", hdr->caplen, MAXIMUM_SNAPLEN);
    533 			return (-1);
    534 		}
    535 
    536 		/*
    537 		 * XXX - we don't grow the buffer here because some
    538 		 * program might assume that it will never get packets
    539 		 * bigger than the snapshot length; for example, it might
    540 		 * copy data from our buffer to a buffer of its own,
    541 		 * allocated based on the return value of pcap_snapshot().
    542 		 *
    543 		 * Read the first p->bufsize bytes into the buffer.
    544 		 */
    545 		amt_read = fread(p->buffer, 1, p->bufsize, fp);
    546 		if (amt_read != p->bufsize) {
    547 			if (ferror(fp)) {
    548 				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    549 				    "error reading dump file: %s",
    550 				    pcap_strerror(errno));
    551 			} else {
    552 				/*
    553 				 * Yes, this uses hdr->caplen; technically,
    554 				 * it's true, because we would try to read
    555 				 * and discard the rest of those bytes, and
    556 				 * that would fail because we got EOF before
    557 				 * the read finished.
    558 				 */
    559 				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    560 				    "truncated dump file; tried to read %u captured bytes, only got %lu",
    561 				    hdr->caplen, (unsigned long)amt_read);
    562 			}
    563 			return (-1);
    564 		}
    565 
    566 		/*
    567 		 * Now read and discard what's left.
    568 		 */
    569 		bytes_to_discard = hdr->caplen - p->bufsize;
    570 		bytes_read = amt_read;
    571 		while (bytes_to_discard != 0) {
    572 			bytes_to_read = bytes_to_discard;
    573 			if (bytes_to_read > sizeof (discard_buf))
    574 				bytes_to_read = sizeof (discard_buf);
    575 			amt_read = fread(discard_buf, 1, bytes_to_read, fp);
    576 			bytes_read += amt_read;
    577 			if (amt_read != bytes_to_read) {
    578 				if (ferror(fp)) {
    579 					pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    580 					    "error reading dump file: %s",
    581 					    pcap_strerror(errno));
    582 				} else {
    583 					pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    584 					    "truncated dump file; tried to read %u captured bytes, only got %lu",
    585 					    hdr->caplen, (unsigned long)bytes_read);
    586 				}
    587 				return (-1);
    588 			}
    589 			bytes_to_discard -= amt_read;
    590 		}
    591 
    592 		/*
    593 		 * Adjust caplen accordingly, so we don't get confused later
    594 		 * as to how many bytes we have to play with.
    595 		 */
    596 		hdr->caplen = p->bufsize;
    597 	} else {
    598 		/* read the packet itself */
    599 		amt_read = fread(p->buffer, 1, hdr->caplen, fp);
    600 		if (amt_read != hdr->caplen) {
    601 			if (ferror(fp)) {
    602 				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    603 				    "error reading dump file: %s",
    604 				    pcap_strerror(errno));
    605 			} else {
    606 				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    607 				    "truncated dump file; tried to read %u captured bytes, only got %lu",
    608 				    hdr->caplen, (unsigned long)amt_read);
    609 			}
    610 			return (-1);
    611 		}
    612 	}
    613 	*data = p->buffer;
    614 
    615 	if (p->swapped)
    616 		swap_pseudo_headers(p->linktype, hdr, *data);
    617 
    618 	return (0);
    619 }
    620 
    621 static int
    622 sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen)
    623 {
    624 	struct pcap_file_header hdr;
    625 
    626 	hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC;
    627 	hdr.version_major = PCAP_VERSION_MAJOR;
    628 	hdr.version_minor = PCAP_VERSION_MINOR;
    629 
    630 	hdr.thiszone = thiszone;
    631 	hdr.snaplen = snaplen;
    632 	hdr.sigfigs = 0;
    633 	hdr.linktype = linktype;
    634 
    635 	if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
    636 		return (-1);
    637 
    638 	return (0);
    639 }
    640 
    641 /*
    642  * Output a packet to the initialized dump file.
    643  */
    644 void
    645 pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
    646 {
    647 	register FILE *f;
    648 	struct pcap_sf_pkthdr sf_hdr;
    649 
    650 	f = (FILE *)user;
    651 	sf_hdr.ts.tv_sec  = h->ts.tv_sec;
    652 	sf_hdr.ts.tv_usec = h->ts.tv_usec;
    653 	sf_hdr.caplen     = h->caplen;
    654 	sf_hdr.len        = h->len;
    655 	/* XXX we should check the return status */
    656 	(void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
    657 	(void)fwrite(sp, h->caplen, 1, f);
    658 }
    659 
    660 static pcap_dumper_t *
    661 pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname)
    662 {
    663 
    664 #if defined(_WIN32) || defined(MSDOS)
    665 	/*
    666 	 * If we're writing to the standard output, put it in binary
    667 	 * mode, as savefiles are binary files.
    668 	 *
    669 	 * Otherwise, we turn off buffering.
    670 	 * XXX - why?  And why not on the standard output?
    671 	 */
    672 	if (f == stdout)
    673 		SET_BINMODE(f);
    674 	else
    675 		setbuf(f, NULL);
    676 #endif
    677 	if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) {
    678 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s",
    679 		    fname, pcap_strerror(errno));
    680 		if (f != stdout)
    681 			(void)fclose(f);
    682 		return (NULL);
    683 	}
    684 	return ((pcap_dumper_t *)f);
    685 }
    686 
    687 /*
    688  * Initialize so that sf_write() will output to the file named 'fname'.
    689  */
    690 pcap_dumper_t *
    691 pcap_dump_open(pcap_t *p, const char *fname)
    692 {
    693 	FILE *f;
    694 	int linktype;
    695 
    696 	/*
    697 	 * If this pcap_t hasn't been activated, it doesn't have a
    698 	 * link-layer type, so we can't use it.
    699 	 */
    700 	if (!p->activated) {
    701 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    702 		    "%s: not-yet-activated pcap_t passed to pcap_dump_open",
    703 		    fname);
    704 		return (NULL);
    705 	}
    706 	linktype = dlt_to_linktype(p->linktype);
    707 	if (linktype == -1) {
    708 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    709 		    "%s: link-layer type %d isn't supported in savefiles",
    710 		    fname, p->linktype);
    711 		return (NULL);
    712 	}
    713 	linktype |= p->linktype_ext;
    714 
    715 	if (fname == NULL) {
    716 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    717 		    "A null pointer was supplied as the file name");
    718 		return NULL;
    719 	}
    720 	if (fname[0] == '-' && fname[1] == '\0') {
    721 		f = stdout;
    722 		fname = "standard output";
    723 	} else {
    724 #if !defined(_WIN32) && !defined(MSDOS)
    725 		f = fopen(fname, "w");
    726 #else
    727 		f = fopen(fname, "wb");
    728 #endif
    729 		if (f == NULL) {
    730 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
    731 			    fname, pcap_strerror(errno));
    732 			return (NULL);
    733 		}
    734 	}
    735 	return (pcap_setup_dump(p, linktype, f, fname));
    736 }
    737 
    738 /*
    739  * Initialize so that sf_write() will output to the given stream.
    740  */
    741 pcap_dumper_t *
    742 pcap_dump_fopen(pcap_t *p, FILE *f)
    743 {
    744 	int linktype;
    745 
    746 	linktype = dlt_to_linktype(p->linktype);
    747 	if (linktype == -1) {
    748 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    749 		    "stream: link-layer type %d isn't supported in savefiles",
    750 		    p->linktype);
    751 		return (NULL);
    752 	}
    753 	linktype |= p->linktype_ext;
    754 
    755 	return (pcap_setup_dump(p, linktype, f, "stream"));
    756 }
    757 
    758 pcap_dumper_t *
    759 pcap_dump_open_append(pcap_t *p, const char *fname)
    760 {
    761 	FILE *f;
    762 	int linktype;
    763 	size_t amt_read;
    764 	struct pcap_file_header ph;
    765 
    766 	linktype = dlt_to_linktype(p->linktype);
    767 	if (linktype == -1) {
    768 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    769 		    "%s: link-layer type %d isn't supported in savefiles",
    770 		    fname, linktype);
    771 		return (NULL);
    772 	}
    773 
    774 	if (fname == NULL) {
    775 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    776 		    "A null pointer was supplied as the file name");
    777 		return NULL;
    778 	}
    779 	if (fname[0] == '-' && fname[1] == '\0')
    780 		return (pcap_setup_dump(p, linktype, stdout, "standard output"));
    781 
    782 #if !defined(_WIN32) && !defined(MSDOS)
    783 	f = fopen(fname, "r+");
    784 #else
    785 	f = fopen(fname, "rb+");
    786 #endif
    787 	if (f == NULL) {
    788 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
    789 		    fname, pcap_strerror(errno));
    790 		return (NULL);
    791 	}
    792 
    793 	/*
    794 	 * Try to read a pcap header.
    795 	 */
    796 	amt_read = fread(&ph, 1, sizeof (ph), f);
    797 	if (amt_read != sizeof (ph)) {
    798 		if (ferror(f)) {
    799 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
    800 			    fname, pcap_strerror(errno));
    801 			fclose(f);
    802 			return (NULL);
    803 		} else if (feof(f) && amt_read > 0) {
    804 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    805 			    "%s: truncated pcap file header", fname);
    806 			fclose(f);
    807 			return (NULL);
    808 		}
    809 	}
    810 
    811 #if defined(_WIN32) || defined(MSDOS)
    812 	/*
    813 	 * We turn off buffering.
    814 	 * XXX - why?  And why not on the standard output?
    815 	 */
    816 	setbuf(f, NULL);
    817 #endif
    818 
    819 	/*
    820 	 * If a header is already present and:
    821 	 *
    822 	 *	it's not for a pcap file of the appropriate resolution
    823 	 *	and the right byte order for this machine;
    824 	 *
    825 	 *	the link-layer header types don't match;
    826 	 *
    827 	 *	the snapshot lengths don't match;
    828 	 *
    829 	 * return an error.
    830 	 */
    831 	if (amt_read > 0) {
    832 		/*
    833 		 * A header is already present.
    834 		 * Do the checks.
    835 		 */
    836 		switch (ph.magic) {
    837 
    838 		case TCPDUMP_MAGIC:
    839 			if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) {
    840 				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    841 				    "%s: different time stamp precision, cannot append to file", fname);
    842 				fclose(f);
    843 				return (NULL);
    844 			}
    845 			break;
    846 
    847 		case NSEC_TCPDUMP_MAGIC:
    848 			if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) {
    849 				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    850 				    "%s: different time stamp precision, cannot append to file", fname);
    851 				fclose(f);
    852 				return (NULL);
    853 			}
    854 			break;
    855 
    856 		case SWAPLONG(TCPDUMP_MAGIC):
    857 		case SWAPLONG(NSEC_TCPDUMP_MAGIC):
    858 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    859 			    "%s: different byte order, cannot append to file", fname);
    860 			fclose(f);
    861 			return (NULL);
    862 
    863 		case KUZNETZOV_TCPDUMP_MAGIC:
    864 		case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC):
    865 		case NAVTEL_TCPDUMP_MAGIC:
    866 		case SWAPLONG(NAVTEL_TCPDUMP_MAGIC):
    867 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    868 			    "%s: not a pcap file to which we can append", fname);
    869 			fclose(f);
    870 			return (NULL);
    871 
    872 		default:
    873 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    874 			    "%s: not a pcap file", fname);
    875 			fclose(f);
    876 			return (NULL);
    877 		}
    878 
    879 		/*
    880 		 * Good version?
    881 		 */
    882 		if (ph.version_major != PCAP_VERSION_MAJOR ||
    883 		    ph.version_minor != PCAP_VERSION_MINOR) {
    884 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    885 			    "%s: version is %u.%u, cannot append to file", fname,
    886 			    ph.version_major, ph.version_minor);
    887 			fclose(f);
    888 			return (NULL);
    889 		}
    890 		if ((bpf_u_int32)linktype != ph.linktype) {
    891 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    892 			    "%s: different linktype, cannot append to file", fname);
    893 			fclose(f);
    894 			return (NULL);
    895 		}
    896 		if ((bpf_u_int32)p->snapshot != ph.snaplen) {
    897 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    898 			    "%s: different snaplen, cannot append to file", fname);
    899 			fclose(f);
    900 			return (NULL);
    901 		}
    902 	} else {
    903 		/*
    904 		 * A header isn't present; attempt to write it.
    905 		 */
    906 		if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) {
    907 			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s",
    908 			    fname, pcap_strerror(errno));
    909 			(void)fclose(f);
    910 			return (NULL);
    911 		}
    912 	}
    913 
    914 	/*
    915 	 * Start writing at the end of the file.
    916 	 */
    917 	if (fseek(f, 0, SEEK_END) == -1) {
    918 		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't seek to end of %s: %s",
    919 		    fname, pcap_strerror(errno));
    920 		(void)fclose(f);
    921 		return (NULL);
    922 	}
    923 	return ((pcap_dumper_t *)f);
    924 }
    925 
    926 FILE *
    927 pcap_dump_file(pcap_dumper_t *p)
    928 {
    929 	return ((FILE *)p);
    930 }
    931 
    932 long
    933 pcap_dump_ftell(pcap_dumper_t *p)
    934 {
    935 	return (ftell((FILE *)p));
    936 }
    937 
    938 int
    939 pcap_dump_flush(pcap_dumper_t *p)
    940 {
    941 
    942 	if (fflush((FILE *)p) == EOF)
    943 		return (-1);
    944 	else
    945 		return (0);
    946 }
    947 
    948 void
    949 pcap_dump_close(pcap_dumper_t *p)
    950 {
    951 
    952 #ifdef notyet
    953 	if (ferror((FILE *)p))
    954 		return-an-error;
    955 	/* XXX should check return from fclose() too */
    956 #endif
    957 	(void)fclose((FILE *)p);
    958 }
    959