When capturing, we only support writing to libpcap files. Given that,

bypass Wiretap; that means we don't have to run the packet through
wtap_process_pcap_packet() and then undo that conversion in Wiretap if
we're just going to write it out, shortening the code path.

svn path=/trunk/; revision=17461
This commit is contained in:
Guy Harris 2006-03-04 22:33:04 +00:00
parent a8b8b3d9ff
commit e6886d90ce
8 changed files with 376 additions and 138 deletions

View File

@ -58,6 +58,7 @@ ETHEREAL_COMMON_SRC = \
packet-range.c \ packet-range.c \
print.c \ print.c \
ps.c \ ps.c \
pcapio.c \
ringbuffer.c \ ringbuffer.c \
timestats.c \ timestats.c \
util.c \ util.c \
@ -81,6 +82,7 @@ ETHEREAL_COMMON_INCLUDES = \
fileset.h \ fileset.h \
isprint.h \ isprint.h \
packet-range.h \ packet-range.h \
pcapio.h \
print.h \ print.h \
ps.h \ ps.h \
register.h \ register.h \
@ -221,6 +223,7 @@ dumpcap_SOURCES = \
clopts_common.c \ clopts_common.c \
conditions.c \ conditions.c \
dumpcap.c \ dumpcap.c \
pcapio.c \
ringbuffer.c \ ringbuffer.c \
tempfile.c \ tempfile.c \
version_info.c version_info.c

View File

@ -68,8 +68,7 @@
#include <pcap.h> #include <pcap.h>
#include "wiretap/wtap.h" #include "pcapio.h"
#include "wiretap/wtap-capture.h"
#include "capture-pcap-util.h" #include "capture-pcap-util.h"
@ -640,7 +639,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
} }
/* open the capture input file (pcap or capture pipe) */ /* close the capture input file (pcap or capture pipe) */
static void capture_loop_close_input(loop_data *ld) { static void capture_loop_close_input(loop_data *ld) {
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input"); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input");
@ -746,14 +745,14 @@ gboolean capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const
} }
/* open the wiretap part of the capture output file */ /* set up to write to the already-opened capture output file/files */
gboolean capture_loop_init_wiretap_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len) { gboolean capture_loop_init_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len) {
int pcap_encap; int pcap_encap;
int file_snaplen; int file_snaplen;
int err; int err;
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_init_wiretap_output"); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_init_output");
/* get packet encapsulation type and snaplen */ /* get packet encapsulation type and snaplen */
#ifndef _WIN32 #ifndef _WIN32
@ -768,22 +767,15 @@ gboolean capture_loop_init_wiretap_output(capture_options *capture_opts, int sav
} }
/* Set up to write to the capture file. */ /* Set up to write to the capture file. */
ld->wtap_linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap); ld->linktype = pcap_encap;
if (ld->wtap_linktype == WTAP_ENCAP_UNKNOWN) {
g_snprintf(errmsg, errmsg_len,
"The network you're capturing from is of a type"
" that (T)Ethereal doesn't support (data link type %d).", pcap_encap);
return FALSE;
}
if (capture_opts->multi_files_on) { if (capture_opts->multi_files_on) {
ld->wtap_pdh = ringbuf_init_wtap_dump_fdopen(WTAP_FILE_PCAP, ld->wtap_linktype, ld->pdh = ringbuf_init_libpcap_fdopen(ld->linktype, file_snaplen, &err);
file_snaplen, &err);
} else { } else {
ld->wtap_pdh = wtap_dump_fdopen(save_file_fd, WTAP_FILE_PCAP, ld->pdh = libpcap_fdopen(save_file_fd, ld->linktype, file_snaplen,
ld->wtap_linktype, file_snaplen, FALSE /* compressed */, &err); &ld->bytes_written, &err);
} }
if (ld->wtap_pdh == NULL) { if (ld->pdh == NULL) {
/* We couldn't set up to write to the capture file. */ /* We couldn't set up to write to the capture file. */
/* XXX - use cf_open_error_message from tethereal instead? */ /* XXX - use cf_open_error_message from tethereal instead? */
switch (err) { switch (err) {
@ -824,9 +816,9 @@ gboolean capture_loop_close_output(capture_options *capture_opts, loop_data *ld,
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_output"); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_output");
if (capture_opts->multi_files_on) { if (capture_opts->multi_files_on) {
return ringbuf_wtap_dump_close(&capture_opts->save_file, err_close); return ringbuf_libpcap_dump_close(&capture_opts->save_file, err_close);
} else { } else {
return wtap_dump_close(ld->wtap_pdh, err_close); return libpcap_dump_close(ld->pdh, err_close);
} }
} }
@ -1129,7 +1121,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
ld.wtap_linktype = WTAP_ENCAP_UNKNOWN; ld.wtap_linktype = WTAP_ENCAP_UNKNOWN;
ld.pcap_err = FALSE; ld.pcap_err = FALSE;
ld.from_cap_pipe = FALSE; ld.from_cap_pipe = FALSE;
ld.wtap_pdh = NULL; ld.pdh = NULL;
#ifndef _WIN32 #ifndef _WIN32
ld.cap_pipe_fd = -1; ld.cap_pipe_fd = -1;
#endif #endif
@ -1168,8 +1160,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
goto error; goto error;
} }
/* open the wiretap part of the output file (the output file is already open) */ /* set up to write to the already-opened capture output file/files */
if (!capture_loop_init_wiretap_output(capture_opts, save_file_fd, &ld, errmsg, sizeof(errmsg))) { if (!capture_loop_init_output(capture_opts, save_file_fd, &ld, errmsg, sizeof(errmsg))) {
goto error; goto error;
} }
@ -1186,7 +1178,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
message to our parent so that they'll open the capture file and message to our parent so that they'll open the capture file and
update its windows to indicate that we have a live capture in update its windows to indicate that we have a live capture in
progress. */ progress. */
wtap_dump_flush(ld.wtap_pdh); libpcap_dump_flush(ld.pdh, NULL);
sync_pipe_filename_to_parent(capture_opts->save_file); sync_pipe_filename_to_parent(capture_opts->save_file);
/* initialize capture stop (and alike) conditions */ /* initialize capture stop (and alike) conditions */
@ -1233,7 +1225,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
/* check capture size condition */ /* check capture size condition */
if (cnd_autostop_size != NULL && cnd_eval(cnd_autostop_size, if (cnd_autostop_size != NULL && cnd_eval(cnd_autostop_size,
(guint32)wtap_get_bytes_dumped(ld.wtap_pdh))){ (guint32)ld.bytes_written)){
/* Capture size limit reached, do we have another file? */ /* Capture size limit reached, do we have another file? */
if (capture_opts->multi_files_on) { if (capture_opts->multi_files_on) {
if (cnd_autostop_files != NULL && cnd_eval(cnd_autostop_files, ++autostop_files)) { if (cnd_autostop_files != NULL && cnd_eval(cnd_autostop_files, ++autostop_files)) {
@ -1243,15 +1235,15 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
} }
/* Switch to the next ringbuffer file */ /* Switch to the next ringbuffer file */
if (ringbuf_switch_file(&ld.wtap_pdh, &capture_opts->save_file, &save_file_fd, &ld.err)) { if (ringbuf_switch_file(&ld.pdh, &capture_opts->save_file, &save_file_fd, &ld.err)) {
/* File switch succeeded: reset the conditions */ /* File switch succeeded: reset the conditions */
cnd_reset(cnd_autostop_size); cnd_reset(cnd_autostop_size);
if (cnd_file_duration) { if (cnd_file_duration) {
cnd_reset(cnd_file_duration); cnd_reset(cnd_file_duration);
} }
wtap_dump_flush(ld.wtap_pdh); libpcap_dump_flush(ld.pdh, NULL);
sync_pipe_packet_count_to_parent(inpkts_to_sync_pipe); sync_pipe_packet_count_to_parent(inpkts_to_sync_pipe);
inpkts_to_sync_pipe = 0; inpkts_to_sync_pipe = 0;
sync_pipe_filename_to_parent(capture_opts->save_file); sync_pipe_filename_to_parent(capture_opts->save_file);
} else { } else {
/* File switch failed: stop here */ /* File switch failed: stop here */
@ -1265,7 +1257,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
} }
} /* cnd_autostop_size */ } /* cnd_autostop_size */
if (capture_opts->output_to_pipe) { if (capture_opts->output_to_pipe) {
wtap_dump_flush(ld.wtap_pdh); libpcap_dump_flush(ld.pdh, NULL);
} }
} /* inpkts */ } /* inpkts */
@ -1285,10 +1277,10 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
/* Let the parent process know. */ /* Let the parent process know. */
if (inpkts_to_sync_pipe) { if (inpkts_to_sync_pipe) {
/* do sync here */ /* do sync here */
wtap_dump_flush(ld.wtap_pdh); libpcap_dump_flush(ld.pdh, NULL);
/* Send our parent a message saying we've written out "inpkts_to_sync_pipe" /* Send our parent a message saying we've written out "inpkts_to_sync_pipe"
packets to the capture file. */ packets to the capture file. */
sync_pipe_packet_count_to_parent(inpkts_to_sync_pipe); sync_pipe_packet_count_to_parent(inpkts_to_sync_pipe);
inpkts_to_sync_pipe = 0; inpkts_to_sync_pipe = 0;
@ -1312,14 +1304,14 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
} }
/* Switch to the next ringbuffer file */ /* Switch to the next ringbuffer file */
if (ringbuf_switch_file(&ld.wtap_pdh, &capture_opts->save_file, &save_file_fd, &ld.err)) { if (ringbuf_switch_file(&ld.pdh, &capture_opts->save_file, &save_file_fd, &ld.err)) {
/* file switch succeeded: reset the conditions */ /* file switch succeeded: reset the conditions */
cnd_reset(cnd_file_duration); cnd_reset(cnd_file_duration);
if(cnd_autostop_size) if(cnd_autostop_size)
cnd_reset(cnd_autostop_size); cnd_reset(cnd_autostop_size);
wtap_dump_flush(ld.wtap_pdh); libpcap_dump_flush(ld.pdh, NULL);
sync_pipe_packet_count_to_parent(inpkts_to_sync_pipe); sync_pipe_packet_count_to_parent(inpkts_to_sync_pipe);
inpkts_to_sync_pipe = 0; inpkts_to_sync_pipe = 0;
sync_pipe_filename_to_parent(capture_opts->save_file); sync_pipe_filename_to_parent(capture_opts->save_file);
} else { } else {
/* File switch failed: stop here */ /* File switch failed: stop here */
@ -1517,8 +1509,6 @@ static void
capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr,
const u_char *pd) const u_char *pd)
{ {
struct wtap_pkthdr whdr;
union wtap_pseudo_header pseudo_header;
loop_data *ld = (loop_data *) user; loop_data *ld = (loop_data *) user;
int err; int err;
@ -1529,22 +1519,11 @@ capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr,
ld->go = FALSE; ld->go = FALSE;
} }
/* Convert from libpcap to Wiretap format. if (ld->pdh) {
If that fails, set "ld->go" to FALSE, to stop the capture, and set
"ld->err" to the error. */
pd = wtap_process_pcap_packet(ld->wtap_linktype, phdr, pd, &pseudo_header,
&whdr, &err);
if (pd == NULL) {
ld->go = FALSE;
ld->err = err;
return;
}
if (ld->wtap_pdh) {
/* We're supposed to write the packet to a file; do so. /* We're supposed to write the packet to a file; do so.
If this fails, set "ld->go" to FALSE, to stop the capture, and set If this fails, set "ld->go" to FALSE, to stop the capture, and set
"ld->err" to the error. */ "ld->err" to the error. */
if (!wtap_dump(ld->wtap_pdh, &whdr, &pseudo_header, pd, &err)) { if (!libpcap_write_packet(ld->pdh, phdr, pd, &ld->bytes_written, &err)) {
ld->go = FALSE; ld->go = FALSE;
ld->err = err; ld->err = err;
} }

View File

@ -118,9 +118,11 @@ typedef struct _loop_data {
enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err; enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err;
#endif #endif
/* wiretap (output file) */ /* output file */
wtap_dumper *wtap_pdh; FILE *pdh;
int linktype;
gint wtap_linktype; gint wtap_linktype;
long bytes_written;
} loop_data; } loop_data;
@ -152,7 +154,7 @@ extern gboolean
capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, char *errmsg, int errmsg_len); capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, char *errmsg, int errmsg_len);
extern gboolean extern gboolean
capture_loop_init_wiretap_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len); capture_loop_init_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len);
extern gboolean extern gboolean
capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err_close); capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err_close);

186
pcapio.c Normal file
View File

@ -0,0 +1,186 @@
/* pcapio.c
* Our own private code for writing libpcap files when capturing.
*
* We have these because we want a way to open a stream for output given
* only a file descriptor. libpcap 0.9[.x] has "pcap_dump_fopen()", which
* provides that, but
*
* 1) earlier versions of libpcap doesn't have it
*
* and
*
* 2) WinPcap doesn't have it, because a file descriptor opened
* by code built for one version of the MSVC++ C library
* can't be used by library routines built for another version
* (e.g., threaded vs. unthreaded).
*
* Libpcap's pcap_dump() also doesn't return any error indications.
*
* $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
*
* Derived from code in the Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pcap.h>
#include <glib.h>
#include "pcapio.h"
/* Magic numbers in "libpcap" files.
"libpcap" file records are written in the byte order of the host that
writes them, and the reader is expected to fix this up.
PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC
is a byte-swapped version of that.
PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format,
which uses the same common file format as PCAP_MAGIC, but the
timestamps are saved in nanosecond resolution instead of microseconds.
PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */
#define PCAP_MAGIC 0xa1b2c3d4
#define PCAP_SWAPPED_MAGIC 0xd4c3b2a1
#define PCAP_NSEC_MAGIC 0xa1b23c4d
#define PCAP_SWAPPED_NSEC_MAGIC 0x4d3cb2a1
/* "libpcap" file header. */
struct pcap_hdr {
guint32 magic; /* magic number */
guint16 version_major; /* major version number */
guint16 version_minor; /* minor version number */
gint32 thiszone; /* GMT to local correction */
guint32 sigfigs; /* accuracy of timestamps */
guint32 snaplen; /* max length of captured packets, in octets */
guint32 network; /* data link type */
};
/* "libpcap" record header. */
struct pcaprec_hdr {
guint32 ts_sec; /* timestamp seconds */
guint32 ts_usec; /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */
guint32 incl_len; /* number of octets of packet saved in file */
guint32 orig_len; /* actual length of packet */
};
/* Returns a FILE * to write to on success, NULL on failure; sets "*err" to
an error code, or 0 for a short write, on failure */
FILE *
libpcap_fdopen(int fd, int linktype, int snaplen, long *bytes_written,
int *err)
{
FILE *fp;
struct pcap_hdr file_hdr;
size_t nwritten;
fp = fdopen(fd, "wb");
if (fp == NULL) {
*err = errno;
return NULL;
}
file_hdr.magic = PCAP_MAGIC;
/* current "libpcap" format is 2.4 */
file_hdr.version_major = 2;
file_hdr.version_minor = 4;
file_hdr.thiszone = 0; /* XXX - current offset? */
file_hdr.sigfigs = 0; /* unknown, but also apparently unused */
file_hdr.snaplen = snaplen;
file_hdr.network = linktype;
nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, fp);
if (nwritten != sizeof file_hdr) {
if (nwritten == 0 && ferror(fp))
*err = errno;
else
*err = 0; /* short write */
fclose(fp);
return NULL;
}
*bytes_written = sizeof file_hdr;
return fp;
}
/* Write a record for a packet to a dump file.
Returns TRUE on success, FALSE on failure. */
gboolean
libpcap_write_packet(FILE *fp, const struct pcap_pkthdr *phdr, const u_char *pd,
long *bytes_written, int *err)
{
struct pcaprec_hdr rec_hdr;
size_t nwritten;
rec_hdr.ts_sec = phdr->ts.tv_sec;
rec_hdr.ts_usec = phdr->ts.tv_usec;
rec_hdr.incl_len = phdr->caplen;
rec_hdr.orig_len = phdr->len;
nwritten = fwrite(&rec_hdr, 1, sizeof rec_hdr, fp);
if (nwritten != sizeof rec_hdr) {
if (nwritten == 0 && ferror(fp))
*err = errno;
else
*err = 0; /* short write */
return FALSE;
}
*bytes_written += sizeof rec_hdr;
nwritten = fwrite(pd, 1, phdr->caplen, fp);
if (nwritten != phdr->caplen) {
if (nwritten == 0 && ferror(fp))
*err = errno;
else
*err = 0; /* short write */
return FALSE;
}
*bytes_written += phdr->caplen;
return TRUE;
}
gboolean
libpcap_dump_flush(FILE *pd, int *err)
{
if (fflush(pd) == EOF) {
if (err != NULL)
*err = errno;
return FALSE;
}
return TRUE;
}
gboolean
libpcap_dump_close(FILE *pd, int *err)
{
if (fclose(pd) == EOF) {
if (err != NULL)
*err = errno;
return FALSE;
}
return TRUE;
}

44
pcapio.h Normal file
View File

@ -0,0 +1,44 @@
/* pcapio.h
* Declarations of our own routins for writing libpcap files.
*
* $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
*
* Derived from code in the Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Returns a FILE * to write to on success, NULL on failure; sets "*err" to
an error code, or 0 for a short write, on failure */
extern FILE *
libpcap_fdopen(int fd, int linktype, int snaplen, long *bytes_written,
int *err);
/* Write a record for a packet to a dump file.
Returns TRUE on success, FALSE on failure. */
extern gboolean
libpcap_write_packet(FILE *fp, const struct pcap_pkthdr *phdr, const u_char *pd,
long *bytes_written, int *err);
extern gboolean
libpcap_dump_flush(FILE *pd, int *err);
extern gboolean
libpcap_dump_close(FILE *pd, int *err);

View File

@ -61,7 +61,11 @@
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <wiretap/wtap.h> #include <pcap.h>
#include <glib.h>
#include "pcapio.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "file_util.h" #include "file_util.h"
@ -79,12 +83,12 @@ typedef struct _ringbuf_data {
gchar *fprefix; /* Filename prefix */ gchar *fprefix; /* Filename prefix */
gchar *fsuffix; /* Filename suffix */ gchar *fsuffix; /* Filename suffix */
gboolean unlimited; /* TRUE if unlimited number of files */ gboolean unlimited; /* TRUE if unlimited number of files */
int filetype;
int linktype; int linktype;
int snaplen; int snaplen;
int fd; /* Current ringbuffer file descriptor */ int fd; /* Current ringbuffer file descriptor */
wtap_dumper *pdh; FILE *pdh;
long bytes_written; /* Bytes written to the current file */
} ringbuf_data; } ringbuf_data;
static ringbuf_data rb_data; static ringbuf_data rb_data;
@ -224,18 +228,17 @@ const gchar *ringbuf_current_filename(void)
} }
/* /*
* Calls wtap_dump_fdopen() for the current ringbuffer file * Calls libpcap_fdopen() for the current ringbuffer file
*/ */
wtap_dumper* FILE *
ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, int snaplen, int *err) ringbuf_init_libpcap_fdopen(int linktype, int snaplen, int *err)
{ {
rb_data.filetype = filetype;
rb_data.linktype = linktype; rb_data.linktype = linktype;
rb_data.snaplen = snaplen; rb_data.snaplen = snaplen;
rb_data.pdh = wtap_dump_fdopen(rb_data.fd, filetype, linktype, snaplen, FALSE /* compressed */, err); rb_data.pdh = libpcap_fdopen(rb_data.fd, linktype, snaplen,
&rb_data.bytes_written, err);
return rb_data.pdh; return rb_data.pdh;
} }
@ -243,14 +246,14 @@ ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, int snaplen, int *err)
* Switches to the next ringbuffer file * Switches to the next ringbuffer file
*/ */
gboolean gboolean
ringbuf_switch_file(wtap_dumper **pdh, gchar **save_file, int *save_file_fd, int *err) ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, int *err)
{ {
int next_file_num; int next_file_num;
rb_file *next_rfile = NULL; rb_file *next_rfile = NULL;
/* close current file */ /* close current file */
if (!wtap_dump_close(rb_data.pdh, err)) { if (!libpcap_dump_close(rb_data.pdh, err)) {
eth_close(rb_data.fd); /* XXX - the above should have closed this already */ eth_close(rb_data.fd); /* XXX - the above should have closed this already */
rb_data.pdh = NULL; /* it's still closed, we just got an error while closing */ rb_data.pdh = NULL; /* it's still closed, we just got an error while closing */
rb_data.fd = -1; rb_data.fd = -1;
@ -270,8 +273,8 @@ ringbuf_switch_file(wtap_dumper **pdh, gchar **save_file, int *save_file_fd, int
return FALSE; return FALSE;
} }
if (ringbuf_init_wtap_dump_fdopen(rb_data.filetype, rb_data.linktype, if (ringbuf_init_libpcap_fdopen(rb_data.linktype, rb_data.snaplen,
rb_data.snaplen, err) == NULL) { err) == NULL) {
return FALSE; return FALSE;
} }
@ -284,16 +287,16 @@ ringbuf_switch_file(wtap_dumper **pdh, gchar **save_file, int *save_file_fd, int
} }
/* /*
* Calls wtap_dump_close() for the current ringbuffer file * Calls libpcap_dump_close() for the current ringbuffer file
*/ */
gboolean gboolean
ringbuf_wtap_dump_close(gchar **save_file, int *err) ringbuf_libpcap_dump_close(gchar **save_file, int *err)
{ {
gboolean ret_val = TRUE; gboolean ret_val = TRUE;
/* close current file, if it's open */ /* close current file, if it's open */
if (rb_data.pdh != NULL) { if (rb_data.pdh != NULL) {
if (!wtap_dump_close(rb_data.pdh, err)) { if (!libpcap_dump_close(rb_data.pdh, err)) {
eth_close(rb_data.fd); eth_close(rb_data.fd);
ret_val = FALSE; ret_val = FALSE;
} }
@ -345,14 +348,14 @@ ringbuf_error_cleanup(void)
/* try to close via wtap */ /* try to close via wtap */
if (rb_data.pdh != NULL) { if (rb_data.pdh != NULL) {
if (wtap_dump_close(rb_data.pdh, NULL)) { if (libpcap_dump_close(rb_data.pdh, NULL)) {
rb_data.fd = -1; rb_data.fd = -1;
} }
rb_data.pdh = NULL; rb_data.pdh = NULL;
} }
/* close directly if still open */ /* close directly if still open */
/* XXX - it shouldn't still be open; "wtap_dump_close()" should leave the /* XXX - it shouldn't still be open; "libpcap_dump_close()" should leave the
file closed even if it fails */ file closed even if it fails */
if (rb_data.fd != -1) { if (rb_data.fd != -1) {
eth_close(rb_data.fd); eth_close(rb_data.fd);

View File

@ -40,10 +40,9 @@
int ringbuf_init(const char *capture_name, guint num_files); int ringbuf_init(const char *capture_name, guint num_files);
const gchar *ringbuf_current_filename(void); const gchar *ringbuf_current_filename(void);
wtap_dumper* ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, FILE *ringbuf_init_libpcap_fdopen(int linktype, int snaplen, int *err);
int snaplen, int *err); gboolean ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, int *err);
gboolean ringbuf_switch_file(wtap_dumper **pdh, gchar **save_file, int *save_file_fd, int *err); gboolean ringbuf_libpcap_dump_close(gchar **save_file, int *err);
gboolean ringbuf_wtap_dump_close(gchar **save_file, int *err);
void ringbuf_free(void); void ringbuf_free(void);
void ringbuf_error_cleanup(void); void ringbuf_error_cleanup(void);

View File

@ -95,6 +95,7 @@
#include <pcap.h> #include <pcap.h>
#include <setjmp.h> #include <setjmp.h>
#include "capture-pcap-util.h" #include "capture-pcap-util.h"
#include "pcapio.h"
#include <wiretap/wtap-capture.h> #include <wiretap/wtap-capture.h>
#ifdef _WIN32 #ifdef _WIN32
#include "capture-wpcap.h" #include "capture-wpcap.h"
@ -170,9 +171,9 @@ static void report_counts_siginfo(int);
#endif /* HAVE_LIBPCAP */ #endif /* HAVE_LIBPCAP */
static int load_cap_file(capture_file *, char *, int); static int load_cap_file(capture_file *, char *, int);
static gboolean process_packet(capture_file *cf, wtap_dumper *pdh, long offset, static gboolean process_packet(capture_file *cf, long offset,
const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header, const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header,
const guchar *pd, int *err); const guchar *pd);
static void show_capture_file_io_error(const char *, int, gboolean); static void show_capture_file_io_error(const char *, int, gboolean);
static void show_print_file_io_error(int err); static void show_print_file_io_error(int err);
static gboolean write_preamble(capture_file *cf); static gboolean write_preamble(capture_file *cf);
@ -1449,10 +1450,16 @@ main(int argc, char *argv[])
exit(status); exit(status);
} }
if (!quiet) { if (!print_packet_info && !quiet) {
/* /*
* The user didn't ask us not to print a count of packets as * We're not printing information for each packet, and the user
* they arrive, so do so. * didn't ask us not to print a count of packets as they arrive,
* so print that count so the user knows that packets are arriving.
*
* XXX - what if the user wants to do a live capture, doesn't want
* to save it to a file, doesn't want information printed for each
* packet, does want some "-z" statistic, and wants packet counts
* so they know whether they're seeing any packets?
*/ */
print_packet_counts = TRUE; print_packet_counts = TRUE;
} }
@ -1509,7 +1516,7 @@ capture(void)
init_dissection(); init_dissection();
ld.wtap_linktype = WTAP_ENCAP_UNKNOWN; ld.wtap_linktype = WTAP_ENCAP_UNKNOWN;
ld.wtap_pdh = NULL; ld.pdh = NULL;
ld.packet_cb = capture_pcap_cb; ld.packet_cb = capture_pcap_cb;
@ -1545,12 +1552,14 @@ capture(void)
goto error; goto error;
} }
/* open the wiretap part of the output file (the output file is already open) */ /* set up to write to the already-opened capture output file/files */
if(!capture_loop_init_wiretap_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg)) if(!capture_loop_init_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg))
{ {
goto error; goto error;
} }
ld.wtap_linktype = wtap_pcap_encap_to_wtap_encap(ld.linktype);
/* Save the capture file name. */ /* Save the capture file name. */
ld.save_file = capture_opts.save_file; ld.save_file = capture_opts.save_file;
@ -1679,13 +1688,12 @@ capture(void)
in effect. */ in effect. */
ld.go = FALSE; ld.go = FALSE;
} else if (cnd_autostop_size != NULL && } else if (cnd_autostop_size != NULL &&
cnd_eval(cnd_autostop_size, cnd_eval(cnd_autostop_size, (guint32)ld.bytes_written)) {
(guint32)wtap_get_bytes_dumped(ld.wtap_pdh))) {
/* We're saving the capture to a file, and the capture file reached /* We're saving the capture to a file, and the capture file reached
its maximum size. */ its maximum size. */
if (capture_opts.multi_files_on) { if (capture_opts.multi_files_on) {
/* Switch to the next ringbuffer file */ /* Switch to the next ringbuffer file */
if (ringbuf_switch_file(&ld.wtap_pdh, &capture_opts.save_file, &save_file_fd, &loop_err)) { if (ringbuf_switch_file(&ld.pdh, &capture_opts.save_file, &save_file_fd, &loop_err)) {
/* File switch succeeded: reset the condition */ /* File switch succeeded: reset the condition */
cnd_reset(cnd_autostop_size); cnd_reset(cnd_autostop_size);
if (cnd_file_duration) { if (cnd_file_duration) {
@ -1703,7 +1711,7 @@ capture(void)
} }
if (capture_opts.output_to_pipe) { if (capture_opts.output_to_pipe) {
if (ld.packet_count > packet_count_prev) { if (ld.packet_count > packet_count_prev) {
wtap_dump_flush(ld.wtap_pdh); libpcap_dump_flush(ld.pdh, NULL);
packet_count_prev = ld.packet_count; packet_count_prev = ld.packet_count;
} }
} }
@ -1806,18 +1814,12 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
{ {
struct wtap_pkthdr whdr; struct wtap_pkthdr whdr;
union wtap_pseudo_header pseudo_header; union wtap_pseudo_header pseudo_header;
const guchar *wtap_pd;
loop_data *ld = (loop_data *) user; loop_data *ld = (loop_data *) user;
int loop_err; int loop_err;
int err; int err;
int save_file_fd; int save_file_fd;
gboolean packet_accepted;
/* Convert from libpcap to Wiretap format.
If that fails, ignore the packet (wtap_process_pcap_packet has
written an error message). */
pd = wtap_process_pcap_packet(ld->wtap_linktype, phdr, pd, &pseudo_header,
&whdr, &err);
if (pd == NULL)
return;
#ifdef SIGINFO #ifdef SIGINFO
/* /*
@ -1835,7 +1837,7 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
*/ */
if (cnd_file_duration != NULL && cnd_eval(cnd_file_duration)) { if (cnd_file_duration != NULL && cnd_eval(cnd_file_duration)) {
/* time elapsed for this ring file, switch to the next */ /* time elapsed for this ring file, switch to the next */
if (ringbuf_switch_file(&ld->wtap_pdh, &ld->save_file, &save_file_fd, &loop_err)) { if (ringbuf_switch_file(&ld->pdh, &ld->save_file, &save_file_fd, &loop_err)) {
/* File switch succeeded: reset the condition */ /* File switch succeeded: reset the condition */
cnd_reset(cnd_file_duration); cnd_reset(cnd_file_duration);
} else { } else {
@ -1845,17 +1847,51 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
} }
} }
if (!process_packet(&cfile, ld->wtap_pdh, 0, &whdr, &pseudo_header, pd, &err)) { if (do_dissection) {
/* Error writing to a capture file */ /* We're goint to print packet information, run a read filter, or
if (print_packet_counts) { process taps. Use process_packet() to handle that; in order
/* We're printing counts of packets captured; move to the line after to do that, we need to convert from libpcap to Wiretap format.
the count. */ If that fails, ignore the packet (wtap_process_pcap_packet has
fprintf(stderr, "\n"); written an error message). */
wtap_pd = wtap_process_pcap_packet(ld->wtap_linktype, phdr, pd,
&pseudo_header, &whdr, &err);
if (wtap_pd == NULL)
return;
packet_accepted = process_packet(&cfile, 0, &whdr, &pseudo_header, wtap_pd);
} else {
/* We're just writing out packets. */
packet_accepted = TRUE;
}
if (packet_accepted) {
/* Count this packet. */
#ifdef HAVE_LIBPCAP
ld->packet_count++;
#endif
if (ld->pdh != NULL) {
if (!libpcap_write_packet(ld->pdh, phdr, pd, &ld->bytes_written, &err)) {
/* Error writing to a capture file */
if (print_packet_counts) {
/* We're printing counts of packets captured; move to the line after
the count. */
fprintf(stderr, "\n");
}
show_capture_file_io_error(ld->save_file, err, FALSE);
pcap_close(ld->pcap_h);
libpcap_dump_close(ld->pdh, &err);
exit(2);
}
}
if (print_packet_counts) {
/* We're printing packet counts. */
if (ld->packet_count != 0) {
fprintf(stderr, "\r%u ", ld->packet_count);
/* stderr could be line buffered */
fflush(stderr);
}
} }
show_capture_file_io_error(ld->save_file, err, FALSE);
pcap_close(ld->pcap_h);
wtap_dump_close(ld->wtap_pdh, &err);
exit(2);
} }
#ifdef SIGINFO #ifdef SIGINFO
@ -2017,13 +2053,21 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type)
pdh = NULL; pdh = NULL;
} }
while (wtap_read(cf->wth, &err, &err_info, &data_offset)) { while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
if (!process_packet(cf, pdh, data_offset, wtap_phdr(cf->wth), if (process_packet(cf, data_offset, wtap_phdr(cf->wth),
wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth), wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth))) {
&err)) { /* Either there's no read filtering or this packet passed the
/* Error writing to a capture file */ filter, so, if we're writing to a capture file, write
show_capture_file_io_error(save_file, err, FALSE); this packet out. */
wtap_dump_close(pdh, &err); if (pdh != NULL) {
exit(2); if (!wtap_dump(pdh, wtap_phdr(cf->wth),
wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
&err)) {
/* Error writing to a capture file */
show_capture_file_io_error(save_file, err, FALSE);
wtap_dump_close(pdh, &err);
exit(2);
}
}
} }
} }
if (err != 0) { if (err != 0) {
@ -2148,10 +2192,8 @@ clear_fdata(frame_data *fdata)
} }
static gboolean static gboolean
process_packet(capture_file *cf, wtap_dumper *pdh, long offset, process_packet(capture_file *cf, long offset, const struct wtap_pkthdr *whdr,
const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header, const guchar *pd)
union wtap_pseudo_header *pseudo_header, const guchar *pd,
int *err)
{ {
frame_data fdata; frame_data fdata;
gboolean create_proto_tree; gboolean create_proto_tree;
@ -2215,27 +2257,7 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
} }
if (passed) { if (passed) {
/* Count this packet. */
#ifdef HAVE_LIBPCAP
ld.packet_count++;
#endif
/* Process this packet. */ /* Process this packet. */
if (pdh != NULL) {
/* We're writing to a capture file; write this packet. */
if (!wtap_dump(pdh, whdr, pseudo_header, pd, err))
return FALSE;
#ifdef HAVE_LIBPCAP
if (print_packet_counts) {
/* We're printing packet counts. */
if (ld.packet_count != 0) {
fprintf(stderr, "\r%u ", ld.packet_count);
/* stderr could be line buffered */
fflush(stderr);
}
}
#endif
}
if (print_packet_info) { if (print_packet_info) {
/* We're printing packet information; print the information for /* We're printing packet information; print the information for
this packet. */ this packet. */
@ -2275,7 +2297,7 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
epan_dissect_free(edt); epan_dissect_free(edt);
clear_fdata(&fdata); clear_fdata(&fdata);
} }
return TRUE; return passed;
} }
static void static void