1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1993, 1994, 1995, 1996, 1997
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that: (1) source code distributions
|
|
|
|
* retain the above copyright notice and this paragraph in its entirety, (2)
|
|
|
|
* distributions including binary code include the above copyright notice and
|
|
|
|
* this paragraph in its entirety in the documentation or other materials
|
|
|
|
* provided with the distribution, and (3) all advertising materials mentioning
|
|
|
|
* features or use of this software display the following acknowledgement:
|
|
|
|
* ``This product includes software developed by the University of California,
|
|
|
|
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
|
|
|
|
* the University nor the names of its contributors may be used to endorse
|
|
|
|
* or promote products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*
|
|
|
|
* savefile.c - supports offline use of tcpdump
|
|
|
|
* Extraction/creation by Jeffrey Mogul, DECWRL
|
|
|
|
* Modified by Steve McCanne, LBL.
|
|
|
|
*
|
|
|
|
* Used to save the received packet headers, after filtering, to
|
|
|
|
* a file, and then read them later.
|
|
|
|
* The first record in the file contains saved values for the machine
|
|
|
|
* dependent values so we can print the dump file on any architecture.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef lint
|
2003-11-15 23:23:57 +00:00
|
|
|
static const char rcsid[] _U_ =
|
2008-12-23 20:13:29 +00:00
|
|
|
"@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.183 2008-12-23 20:13:29 guy Exp $ (LBL)";
|
2000-07-11 00:37:04 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
1999-10-07 23:46:40 +00:00
|
|
|
#endif
|
|
|
|
|
2009-07-08 08:10:18 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
#include <pcap-stdinc.h>
|
|
|
|
#else /* WIN32 */
|
|
|
|
#if HAVE_INTTYPES_H
|
|
|
|
#include <inttypes.h>
|
|
|
|
#elif HAVE_STDINT_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_BITYPES_H
|
|
|
|
#include <sys/bitypes.h>
|
|
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <memory.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2000-10-10 04:53:08 +00:00
|
|
|
#include <string.h>
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#include "pcap-int.h"
|
2007-01-29 20:08:06 +00:00
|
|
|
#include "pcap/usb.h"
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_OS_PROTO_H
|
|
|
|
#include "os-proto.h"
|
|
|
|
#endif
|
|
|
|
|
2010-01-10 00:58:15 +00:00
|
|
|
#include "sf-pcap.h"
|
|
|
|
#include "sf-pcap-ng.h"
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
|
2007-09-29 19:33:29 +00:00
|
|
|
/*
|
2010-01-10 00:58:15 +00:00
|
|
|
* Setting O_BINARY on DOS/Windows is a bit tricky
|
2007-09-29 19:33:29 +00:00
|
|
|
*/
|
2010-01-10 00:58:15 +00:00
|
|
|
#if defined(WIN32)
|
|
|
|
#define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY)
|
|
|
|
#elif defined(MSDOS)
|
|
|
|
#if defined(__HIGHC__)
|
|
|
|
#define SET_BINMODE(f) setmode(f, O_BINARY)
|
|
|
|
#else
|
|
|
|
#define SET_BINMODE(f) setmode(fileno(f), O_BINARY)
|
|
|
|
#endif
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
|
2003-11-20 02:02:38 +00:00
|
|
|
static int
|
|
|
|
sf_getnonblock(pcap_t *p, char *errbuf)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This is a savefile, not a live capture file, so never say
|
|
|
|
* it's in non-blocking mode.
|
|
|
|
*/
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sf_setnonblock(pcap_t *p, int nonblock, char *errbuf)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This is a savefile, not a live capture file, so ignore
|
|
|
|
* requests to put it in non-blocking mode.
|
|
|
|
*/
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-07-25 04:04:56 +00:00
|
|
|
static int
|
|
|
|
sf_stats(pcap_t *p, struct pcap_stat *ps)
|
|
|
|
{
|
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"Statistics aren't available from savefiles");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2007-10-17 18:52:41 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
static int
|
|
|
|
sf_setbuff(pcap_t *p, int dim)
|
|
|
|
{
|
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"The kernel buffer size cannot be set while reading from a file");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sf_setmode(pcap_t *p, int mode)
|
|
|
|
{
|
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"impossible to set mode while reading from a file");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sf_setmintocopy(pcap_t *p, int size)
|
|
|
|
{
|
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"The mintocopy parameter cannot be set while reading from a file");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-03-23 19:18:04 +00:00
|
|
|
static int
|
|
|
|
sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
|
|
|
|
{
|
|
|
|
strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
|
|
|
|
PCAP_ERRBUF_SIZE);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2005-05-23 20:30:44 +00:00
|
|
|
/*
|
|
|
|
* Set direction flag: Which packets do we accept on a forwarding
|
|
|
|
* single device? IN, OUT or both?
|
|
|
|
*/
|
|
|
|
static int
|
2005-07-07 01:57:00 +00:00
|
|
|
sf_setdirection(pcap_t *p, pcap_direction_t d)
|
2005-05-23 20:30:44 +00:00
|
|
|
{
|
|
|
|
snprintf(p->errbuf, sizeof(p->errbuf),
|
|
|
|
"Setting direction is not supported on savefiles");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2003-07-25 03:25:45 +00:00
|
|
|
static void
|
2008-04-14 20:40:58 +00:00
|
|
|
sf_cleanup(pcap_t *p)
|
2003-07-25 03:25:45 +00:00
|
|
|
{
|
|
|
|
if (p->sf.rfile != stdin)
|
|
|
|
(void)fclose(p->sf.rfile);
|
2010-01-10 00:58:15 +00:00
|
|
|
if (p->buffer != NULL)
|
|
|
|
free(p->buffer);
|
2003-07-25 03:25:45 +00:00
|
|
|
}
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
pcap_t *
|
|
|
|
pcap_open_offline(const char *fname, char *errbuf)
|
|
|
|
{
|
2004-11-07 21:40:48 +00:00
|
|
|
FILE *fp;
|
2004-12-17 20:26:16 +00:00
|
|
|
pcap_t *p;
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
if (fname[0] == '-' && fname[1] == '\0')
|
2005-04-26 00:54:23 +00:00
|
|
|
{
|
1999-10-07 23:46:40 +00:00
|
|
|
fp = stdin;
|
2005-04-26 00:54:23 +00:00
|
|
|
#if defined(WIN32) || defined(MSDOS)
|
|
|
|
/*
|
2005-05-01 19:57:31 +00:00
|
|
|
* We're reading from the standard input, so put it in binary
|
2005-05-01 19:53:11 +00:00
|
|
|
* mode, as savefiles are binary files.
|
|
|
|
*/
|
2005-05-01 19:57:31 +00:00
|
|
|
SET_BINMODE(fp);
|
2005-04-26 00:54:23 +00:00
|
|
|
#endif
|
|
|
|
}
|
1999-10-07 23:46:40 +00:00
|
|
|
else {
|
2004-12-18 08:52:08 +00:00
|
|
|
#if !defined(WIN32) && !defined(MSDOS)
|
1999-10-07 23:46:40 +00:00
|
|
|
fp = fopen(fname, "r");
|
2002-08-01 08:33:01 +00:00
|
|
|
#else
|
|
|
|
fp = fopen(fname, "rb");
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
if (fp == NULL) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname,
|
|
|
|
pcap_strerror(errno));
|
2004-12-17 20:26:16 +00:00
|
|
|
return (NULL);
|
1999-10-07 23:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
2004-12-17 20:26:16 +00:00
|
|
|
p = pcap_fopen_offline(fp, errbuf);
|
|
|
|
if (p == NULL) {
|
|
|
|
if (fp != stdin)
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
return (p);
|
2004-11-07 21:40:48 +00:00
|
|
|
}
|
|
|
|
|
2008-10-06 15:27:32 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
fd = _open_osfhandle(osfd, _O_RDONLY);
|
|
|
|
if ( fd < 0 )
|
|
|
|
{
|
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
file = _fdopen(fd, "rb");
|
|
|
|
if ( file == NULL )
|
|
|
|
{
|
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE, pcap_strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pcap_fopen_offline(file, errbuf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-01-10 00:58:15 +00:00
|
|
|
static int (*check_headers[])(pcap_t *, bpf_u_int32, FILE *, char *) = {
|
|
|
|
pcap_check_header,
|
|
|
|
pcap_ng_check_header
|
|
|
|
};
|
|
|
|
|
|
|
|
#define N_FILE_TYPES (sizeof check_headers / sizeof check_headers[0])
|
|
|
|
|
2008-10-06 15:27:32 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
static
|
|
|
|
#endif
|
2004-11-07 21:40:48 +00:00
|
|
|
pcap_t *
|
|
|
|
pcap_fopen_offline(FILE *fp, char *errbuf)
|
|
|
|
{
|
|
|
|
register pcap_t *p;
|
|
|
|
bpf_u_int32 magic;
|
2010-01-10 00:58:15 +00:00
|
|
|
size_t amt_read;
|
|
|
|
u_int i;
|
2004-11-07 21:40:48 +00:00
|
|
|
|
2009-08-12 05:10:51 +00:00
|
|
|
p = pcap_create_common("(savefile)", errbuf);
|
2009-08-12 05:06:38 +00:00
|
|
|
if (p == NULL)
|
2004-11-07 21:40:48 +00:00
|
|
|
return (NULL);
|
|
|
|
|
2010-01-10 00:58:15 +00:00
|
|
|
/*
|
|
|
|
* Read the first 4 bytes of the file; the network analyzer dump
|
|
|
|
* file formats we support (pcap and pcap-ng), and several other
|
|
|
|
* formats we might support in the future (such as snoop, DOS and
|
|
|
|
* Windows Sniffer, and Microsoft Network Monitor) all have magic
|
|
|
|
* numbers that are unique in their first 4 bytes.
|
|
|
|
*/
|
|
|
|
amt_read = fread((char *)&magic, 1, sizeof(magic), fp);
|
|
|
|
if (amt_read != sizeof(magic)) {
|
2004-12-15 09:00:11 +00:00
|
|
|
if (ferror(fp)) {
|
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"error reading dump file: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
} else {
|
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"truncated dump file; tried to read %lu file header bytes, only got %lu",
|
2010-01-10 00:58:15 +00:00
|
|
|
(unsigned long)sizeof(magic),
|
2004-12-27 01:12:17 +00:00
|
|
|
(unsigned long)amt_read);
|
2004-12-15 09:00:11 +00:00
|
|
|
}
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2010-01-10 00:58:15 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try all file types.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < N_FILE_TYPES; i++) {
|
|
|
|
switch ((*check_headers[i])(p, magic, fp, errbuf)) {
|
|
|
|
|
|
|
|
case -1:
|
|
|
|
/*
|
|
|
|
* Error trying to read the header.
|
|
|
|
*/
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
2010-01-10 00:58:15 +00:00
|
|
|
|
|
|
|
case 1:
|
|
|
|
/*
|
|
|
|
* Yup, that's it.
|
|
|
|
*/
|
|
|
|
goto found;
|
1999-10-07 23:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-10 00:58:15 +00:00
|
|
|
/*
|
|
|
|
* Well, who knows what this mess is....
|
|
|
|
*/
|
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format");
|
|
|
|
goto bad;
|
1999-10-07 23:46:40 +00:00
|
|
|
|
2010-01-10 00:58:15 +00:00
|
|
|
found:
|
|
|
|
p->sf.rfile = fp;
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#ifdef PCAP_FDDIPAD
|
2004-12-15 00:25:08 +00:00
|
|
|
/* Padding only needed for live capture fcode */
|
|
|
|
p->fddipad = 0;
|
1999-10-07 23:46:40 +00:00
|
|
|
#endif
|
|
|
|
|
2004-12-18 08:52:08 +00:00
|
|
|
#if !defined(WIN32) && !defined(MSDOS)
|
2003-11-21 10:19:33 +00:00
|
|
|
/*
|
|
|
|
* You can do "select()" and "poll()" on plain files on most
|
|
|
|
* platforms, and should be able to do so on pipes.
|
2003-12-21 21:58:50 +00:00
|
|
|
*
|
|
|
|
* You can't do "select()" on anything other than sockets in
|
|
|
|
* Windows, so, on Win32 systems, we don't have "selectable_fd".
|
2003-11-21 10:19:33 +00:00
|
|
|
*/
|
|
|
|
p->selectable_fd = fileno(fp);
|
2003-12-21 21:58:50 +00:00
|
|
|
#endif
|
2003-11-21 10:19:33 +00:00
|
|
|
|
2003-07-25 05:32:02 +00:00
|
|
|
p->read_op = pcap_offline_read;
|
2004-03-23 19:18:04 +00:00
|
|
|
p->inject_op = sf_inject;
|
2003-07-25 04:42:02 +00:00
|
|
|
p->setfilter_op = install_bpf_program;
|
2005-05-23 20:30:44 +00:00
|
|
|
p->setdirection_op = sf_setdirection;
|
2003-07-25 05:07:01 +00:00
|
|
|
p->set_datalink_op = NULL; /* we don't support munging link-layer headers */
|
2003-11-20 02:02:38 +00:00
|
|
|
p->getnonblock_op = sf_getnonblock;
|
|
|
|
p->setnonblock_op = sf_setnonblock;
|
2003-07-25 04:04:56 +00:00
|
|
|
p->stats_op = sf_stats;
|
2007-10-17 18:52:41 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
p->setbuff_op = sf_setbuff;
|
|
|
|
p->setmode_op = sf_setmode;
|
|
|
|
p->setmintocopy_op = sf_setmintocopy;
|
|
|
|
#endif
|
2008-04-14 20:40:58 +00:00
|
|
|
p->cleanup_op = sf_cleanup;
|
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.
Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5. (Very much "initial" for Linux, which is a twisty little maze of
wireless drivers, many different.)
Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.
2008-04-04 19:37:44 +00:00
|
|
|
p->activated = 1;
|
2003-07-25 03:25:45 +00:00
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
return (p);
|
|
|
|
bad:
|
|
|
|
free(p);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-01-10 00:58:15 +00:00
|
|
|
* Read packets from a capture file, and call the callback for each
|
|
|
|
* packet.
|
1999-10-07 23:46:40 +00:00
|
|
|
* If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|
|
|
{
|
2004-11-30 10:51:41 +00:00
|
|
|
struct bpf_insn *fcode;
|
1999-10-07 23:46:40 +00:00
|
|
|
int status = 0;
|
|
|
|
int n = 0;
|
2010-01-10 00:58:15 +00:00
|
|
|
u_char *data;
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
while (status == 0) {
|
|
|
|
struct pcap_pkthdr h;
|
|
|
|
|
2003-11-04 07:05:32 +00:00
|
|
|
/*
|
|
|
|
* Has "pcap_breakloop()" been called?
|
|
|
|
* If so, return immediately - if we haven't read any
|
|
|
|
* packets, clear the flag and return -2 to indicate
|
|
|
|
* that we were told to break out of the loop, otherwise
|
|
|
|
* leave the flag set, so that the *next* call will break
|
|
|
|
* out of the loop without having read any packets, and
|
|
|
|
* return the number of packets we've processed so far.
|
|
|
|
*/
|
|
|
|
if (p->break_loop) {
|
|
|
|
if (n == 0) {
|
|
|
|
p->break_loop = 0;
|
|
|
|
return (-2);
|
|
|
|
} else
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
|
2010-01-10 00:58:15 +00:00
|
|
|
status = p->sf.next_packet_op(p, &h, &data);
|
1999-10-07 23:46:40 +00:00
|
|
|
if (status) {
|
|
|
|
if (status == 1)
|
|
|
|
return (0);
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
2004-11-30 10:51:41 +00:00
|
|
|
if ((fcode = p->fcode.bf_insns) == NULL ||
|
1999-10-07 23:46:40 +00:00
|
|
|
bpf_filter(fcode, p->buffer, h.len, h.caplen)) {
|
2010-01-10 00:58:15 +00:00
|
|
|
(*callback)(user, &h, data);
|
1999-10-07 23:46:40 +00:00
|
|
|
if (++n >= cnt && cnt > 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*XXX this breaks semantics tcpslice expects */
|
|
|
|
return (n);
|
|
|
|
}
|