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  * 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
     32 static 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 
     83 static int
     84 sf_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 
     93 static int
     94 sf_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 
    109 static int
    110 sf_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
    118 static int
    119 sf_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 
    126 static int
    127 sf_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 
    134 static int
    135 sf_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 
    143 static int
    144 sf_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  */
    155 static int
    156 sf_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 
    163 void
    164 sf_cleanup(pcap_t *p)
    165 {
    166 	if (p->rfile != stdin)
    167 		(void)fclose(p->rfile);
    168 	if (p->buffer != NULL)
    169 		free(p->buffer);
    170 	pcap_freecode(&p->fcode);
    171 }
    172 
    173 pcap_t *
    174 pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
    175     char *errbuf)
    176 {
    177 	FILE *fp;
    178 	pcap_t *p;
    179 
    180 	if (fname[0] == '-' && fname[1] == '\0')
    181 	{
    182 		fp = stdin;
    183 #if defined(WIN32) || defined(MSDOS)
    184 		/*
    185 		 * We're reading from the standard input, so put it in binary
    186 		 * mode, as savefiles are binary files.
    187 		 */
    188 		SET_BINMODE(fp);
    189 #endif
    190 	}
    191 	else {
    192 #if !defined(WIN32) && !defined(MSDOS)
    193 		fp = fopen(fname, "r");
    194 #else
    195 		fp = fopen(fname, "rb");
    196 #endif
    197 		if (fp == NULL) {
    198 			snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname,
    199 			    pcap_strerror(errno));
    200 			return (NULL);
    201 		}
    202 	}
    203 	p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf);
    204 	if (p == NULL) {
    205 		if (fp != stdin)
    206 			fclose(fp);
    207 	}
    208 	return (p);
    209 }
    210 
    211 pcap_t *
    212 pcap_open_offline(const char *fname, char *errbuf)
    213 {
    214 	return (pcap_open_offline_with_tstamp_precision(fname,
    215 	    PCAP_TSTAMP_PRECISION_MICRO, errbuf));
    216 }
    217 
    218 #ifdef WIN32
    219 pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision,
    220     char *errbuf)
    221 {
    222 	int fd;
    223 	FILE *file;
    224 
    225 	fd = _open_osfhandle(osfd, _O_RDONLY);
    226 	if ( fd < 0 )
    227 	{
    228 		snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
    229 		return NULL;
    230 	}
    231 
    232 	file = _fdopen(fd, "rb");
    233 	if ( file == NULL )
    234 	{
    235 		snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
    236 		return NULL;
    237 	}
    238 
    239 	return pcap_fopen_offline_with_tstamp_precision(file, precision,
    240 	    errbuf);
    241 }
    242 
    243 pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf)
    244 {
    245 	return pcap_hopen_offline_with_tstamp_precision(osfd,
    246 	    PCAP_TSTAMP_PRECISION_MICRO, errbuf);
    247 }
    248 #endif
    249 
    250 static pcap_t *(*check_headers[])(bpf_u_int32, FILE *, u_int, char *, int *) = {
    251 	pcap_check_header,
    252 	pcap_ng_check_header
    253 };
    254 
    255 #define	N_FILE_TYPES	(sizeof check_headers / sizeof check_headers[0])
    256 
    257 #ifdef WIN32
    258 static
    259 #endif
    260 pcap_t *
    261 pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
    262     char *errbuf)
    263 {
    264 	register pcap_t *p;
    265 	bpf_u_int32 magic;
    266 	size_t amt_read;
    267 	u_int i;
    268 	int err;
    269 
    270 	/*
    271 	 * Read the first 4 bytes of the file; the network analyzer dump
    272 	 * file formats we support (pcap and pcap-ng), and several other
    273 	 * formats we might support in the future (such as snoop, DOS and
    274 	 * Windows Sniffer, and Microsoft Network Monitor) all have magic
    275 	 * numbers that are unique in their first 4 bytes.
    276 	 */
    277 	amt_read = fread((char *)&magic, 1, sizeof(magic), fp);
    278 	if (amt_read != sizeof(magic)) {
    279 		if (ferror(fp)) {
    280 			snprintf(errbuf, PCAP_ERRBUF_SIZE,
    281 			    "error reading dump file: %s",
    282 			    pcap_strerror(errno));
    283 		} else {
    284 			snprintf(errbuf, PCAP_ERRBUF_SIZE,
    285 			    "truncated dump file; tried to read %lu file header bytes, only got %lu",
    286 			    (unsigned long)sizeof(magic),
    287 			    (unsigned long)amt_read);
    288 		}
    289 		return (NULL);
    290 	}
    291 
    292 	/*
    293 	 * Try all file types.
    294 	 */
    295 	for (i = 0; i < N_FILE_TYPES; i++) {
    296 		p = (*check_headers[i])(magic, fp, precision, errbuf, &err);
    297 		if (p != NULL) {
    298 			/* Yup, that's it. */
    299 			goto found;
    300 		}
    301 		if (err) {
    302 			/*
    303 			 * Error trying to read the header.
    304 			 */
    305 			return (NULL);
    306 		}
    307 	}
    308 
    309 	/*
    310 	 * Well, who knows what this mess is....
    311 	 */
    312 	snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
    313 	return (NULL);
    314 
    315 found:
    316 	p->rfile = fp;
    317 
    318 	/* Padding only needed for live capture fcode */
    319 	p->fddipad = 0;
    320 
    321 #if !defined(WIN32) && !defined(MSDOS)
    322 	/*
    323 	 * You can do "select()" and "poll()" on plain files on most
    324 	 * platforms, and should be able to do so on pipes.
    325 	 *
    326 	 * You can't do "select()" on anything other than sockets in
    327 	 * Windows, so, on Win32 systems, we don't have "selectable_fd".
    328 	 */
    329 	p->selectable_fd = fileno(fp);
    330 #endif
    331 
    332 	p->read_op = pcap_offline_read;
    333 	p->inject_op = sf_inject;
    334 	p->setfilter_op = install_bpf_program;
    335 	p->setdirection_op = sf_setdirection;
    336 	p->set_datalink_op = NULL;	/* we don't support munging link-layer headers */
    337 	p->getnonblock_op = sf_getnonblock;
    338 	p->setnonblock_op = sf_setnonblock;
    339 	p->stats_op = sf_stats;
    340 #ifdef WIN32
    341 	p->setbuff_op = sf_setbuff;
    342 	p->setmode_op = sf_setmode;
    343 	p->setmintocopy_op = sf_setmintocopy;
    344 #endif
    345 
    346 	/*
    347 	 * For offline captures, the standard one-shot callback can
    348 	 * be used for pcap_next()/pcap_next_ex().
    349 	 */
    350 	p->oneshot_callback = pcap_oneshot;
    351 
    352 	p->activated = 1;
    353 
    354 	return (p);
    355 }
    356 
    357 #ifdef WIN32
    358 static
    359 #endif
    360 pcap_t *
    361 pcap_fopen_offline(FILE *fp, char *errbuf)
    362 {
    363 	return (pcap_fopen_offline_with_tstamp_precision(fp,
    364 	    PCAP_TSTAMP_PRECISION_MICRO, errbuf));
    365 }
    366 
    367 /*
    368  * Read packets from a capture file, and call the callback for each
    369  * packet.
    370  * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
    371  */
    372 int
    373 pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
    374 {
    375 	struct bpf_insn *fcode;
    376 	int status = 0;
    377 	int n = 0;
    378 	u_char *data;
    379 
    380 	while (status == 0) {
    381 		struct pcap_pkthdr h;
    382 
    383 		/*
    384 		 * Has "pcap_breakloop()" been called?
    385 		 * If so, return immediately - if we haven't read any
    386 		 * packets, clear the flag and return -2 to indicate
    387 		 * that we were told to break out of the loop, otherwise
    388 		 * leave the flag set, so that the *next* call will break
    389 		 * out of the loop without having read any packets, and
    390 		 * return the number of packets we've processed so far.
    391 		 */
    392 		if (p->break_loop) {
    393 			if (n == 0) {
    394 				p->break_loop = 0;
    395 				return (-2);
    396 			} else
    397 				return (n);
    398 		}
    399 
    400 		status = p->next_packet_op(p, &h, &data);
    401 		if (status) {
    402 			if (status == 1)
    403 				return (0);
    404 			return (status);
    405 		}
    406 
    407 		if ((fcode = p->fcode.bf_insns) == NULL ||
    408 		    bpf_filter(fcode, data, h.len, h.caplen)) {
    409 			(*callback)(user, &h, data);
    410 			if (++n >= cnt && cnt > 0)
    411 				break;
    412 		}
    413 	}
    414 	/*XXX this breaks semantics tcpslice expects */
    415 	return (n);
    416 }
    417