From e6886d90ce0ff33ee80acf3c2ea570333d8d5a23 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Sat, 4 Mar 2006 22:33:04 +0000 Subject: [PATCH] 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 --- Makefile.common | 3 + capture_loop.c | 79 ++++++++------------ capture_loop.h | 8 ++- pcapio.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++ pcapio.h | 44 ++++++++++++ ringbuffer.c | 39 +++++----- ringbuffer.h | 7 +- tethereal.c | 148 ++++++++++++++++++++++---------------- 8 files changed, 376 insertions(+), 138 deletions(-) create mode 100644 pcapio.c create mode 100644 pcapio.h diff --git a/Makefile.common b/Makefile.common index eb21e63005..f27e41f4e8 100644 --- a/Makefile.common +++ b/Makefile.common @@ -58,6 +58,7 @@ ETHEREAL_COMMON_SRC = \ packet-range.c \ print.c \ ps.c \ + pcapio.c \ ringbuffer.c \ timestats.c \ util.c \ @@ -81,6 +82,7 @@ ETHEREAL_COMMON_INCLUDES = \ fileset.h \ isprint.h \ packet-range.h \ + pcapio.h \ print.h \ ps.h \ register.h \ @@ -221,6 +223,7 @@ dumpcap_SOURCES = \ clopts_common.c \ conditions.c \ dumpcap.c \ + pcapio.c \ ringbuffer.c \ tempfile.c \ version_info.c diff --git a/capture_loop.c b/capture_loop.c index 986f8974d2..dc4eb74c51 100644 --- a/capture_loop.c +++ b/capture_loop.c @@ -68,8 +68,7 @@ #include -#include "wiretap/wtap.h" -#include "wiretap/wtap-capture.h" +#include "pcapio.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) { 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 */ -gboolean capture_loop_init_wiretap_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len) { +/* set up to write to the already-opened capture output file/files */ +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 file_snaplen; 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 */ #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. */ - ld->wtap_linktype = wtap_pcap_encap_to_wtap_encap(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; - } + ld->linktype = pcap_encap; if (capture_opts->multi_files_on) { - ld->wtap_pdh = ringbuf_init_wtap_dump_fdopen(WTAP_FILE_PCAP, ld->wtap_linktype, - file_snaplen, &err); + ld->pdh = ringbuf_init_libpcap_fdopen(ld->linktype, file_snaplen, &err); } else { - ld->wtap_pdh = wtap_dump_fdopen(save_file_fd, WTAP_FILE_PCAP, - ld->wtap_linktype, file_snaplen, FALSE /* compressed */, &err); + ld->pdh = libpcap_fdopen(save_file_fd, ld->linktype, file_snaplen, + &ld->bytes_written, &err); } - if (ld->wtap_pdh == NULL) { + if (ld->pdh == NULL) { /* We couldn't set up to write to the capture file. */ /* XXX - use cf_open_error_message from tethereal instead? */ 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"); 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 { - 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.pcap_err = FALSE; ld.from_cap_pipe = FALSE; - ld.wtap_pdh = NULL; + ld.pdh = NULL; #ifndef _WIN32 ld.cap_pipe_fd = -1; #endif @@ -1168,8 +1160,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct goto error; } - /* open the wiretap part of the output file (the output file is already open) */ - if (!capture_loop_init_wiretap_output(capture_opts, save_file_fd, &ld, errmsg, sizeof(errmsg))) { + /* set up to write to the already-opened capture output file/files */ + if (!capture_loop_init_output(capture_opts, save_file_fd, &ld, errmsg, sizeof(errmsg))) { 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 update its windows to indicate that we have a live capture in progress. */ - wtap_dump_flush(ld.wtap_pdh); + libpcap_dump_flush(ld.pdh, NULL); sync_pipe_filename_to_parent(capture_opts->save_file); /* 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 */ 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? */ if (capture_opts->multi_files_on) { 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 */ - 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 */ cnd_reset(cnd_autostop_size); if (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); - inpkts_to_sync_pipe = 0; + inpkts_to_sync_pipe = 0; sync_pipe_filename_to_parent(capture_opts->save_file); } else { /* File switch failed: stop here */ @@ -1265,7 +1257,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct } } /* cnd_autostop_size */ if (capture_opts->output_to_pipe) { - wtap_dump_flush(ld.wtap_pdh); + libpcap_dump_flush(ld.pdh, NULL); } } /* inpkts */ @@ -1285,10 +1277,10 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct /* Let the parent process know. */ if (inpkts_to_sync_pipe) { /* 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" - packets to the capture file. */ + /* Send our parent a message saying we've written out "inpkts_to_sync_pipe" + packets to the capture file. */ sync_pipe_packet_count_to_parent(inpkts_to_sync_pipe); 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 */ - 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 */ cnd_reset(cnd_file_duration); if(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); - inpkts_to_sync_pipe = 0; + inpkts_to_sync_pipe = 0; sync_pipe_filename_to_parent(capture_opts->save_file); } else { /* File switch failed: stop here */ @@ -1517,8 +1509,6 @@ static void capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, const u_char *pd) { - struct wtap_pkthdr whdr; - union wtap_pseudo_header pseudo_header; loop_data *ld = (loop_data *) user; int err; @@ -1529,22 +1519,11 @@ capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, ld->go = FALSE; } - /* Convert from libpcap to Wiretap format. - 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) { + if (ld->pdh) { /* 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 "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->err = err; } diff --git a/capture_loop.h b/capture_loop.h index defb31110b..bfdf734388 100644 --- a/capture_loop.h +++ b/capture_loop.h @@ -118,9 +118,11 @@ typedef struct _loop_data { enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err; #endif - /* wiretap (output file) */ - wtap_dumper *wtap_pdh; + /* output file */ + FILE *pdh; + int linktype; gint wtap_linktype; + long bytes_written; } 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); 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 capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err_close); diff --git a/pcapio.c b/pcapio.c new file mode 100644 index 0000000000..ad8f057a33 --- /dev/null +++ b/pcapio.c @@ -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 + * Copyright 1998 Gerald Combs + * + * Derived from code in the Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * 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 +#include +#include + +#include + +#include + +#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; +} diff --git a/pcapio.h b/pcapio.h new file mode 100644 index 0000000000..801a563e49 --- /dev/null +++ b/pcapio.h @@ -0,0 +1,44 @@ +/* pcapio.h + * Declarations of our own routins for writing libpcap files. + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * Derived from code in the Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez + * + * 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); diff --git a/ringbuffer.c b/ringbuffer.c index 0c1e7f4b75..7d1e00af66 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -61,7 +61,11 @@ #include #include -#include +#include + +#include + +#include "pcapio.h" #include "ringbuffer.h" #include "file_util.h" @@ -79,12 +83,12 @@ typedef struct _ringbuf_data { gchar *fprefix; /* Filename prefix */ gchar *fsuffix; /* Filename suffix */ gboolean unlimited; /* TRUE if unlimited number of files */ - int filetype; int linktype; int snaplen; int fd; /* Current ringbuffer file descriptor */ - wtap_dumper *pdh; + FILE *pdh; + long bytes_written; /* Bytes written to the current file */ } ringbuf_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* -ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, int snaplen, int *err) +FILE * +ringbuf_init_libpcap_fdopen(int linktype, int snaplen, int *err) { - rb_data.filetype = filetype; rb_data.linktype = linktype; 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; } @@ -243,14 +246,14 @@ ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, int snaplen, int *err) * Switches to the next ringbuffer file */ 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; rb_file *next_rfile = NULL; /* 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 */ rb_data.pdh = NULL; /* it's still closed, we just got an error while closing */ rb_data.fd = -1; @@ -270,8 +273,8 @@ ringbuf_switch_file(wtap_dumper **pdh, gchar **save_file, int *save_file_fd, int return FALSE; } - if (ringbuf_init_wtap_dump_fdopen(rb_data.filetype, rb_data.linktype, - rb_data.snaplen, err) == NULL) { + if (ringbuf_init_libpcap_fdopen(rb_data.linktype, rb_data.snaplen, + err) == NULL) { 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 -ringbuf_wtap_dump_close(gchar **save_file, int *err) +ringbuf_libpcap_dump_close(gchar **save_file, int *err) { gboolean ret_val = TRUE; /* close current file, if it's open */ 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); ret_val = FALSE; } @@ -345,14 +348,14 @@ ringbuf_error_cleanup(void) /* try to close via wtap */ 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.pdh = NULL; } /* 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 */ if (rb_data.fd != -1) { eth_close(rb_data.fd); diff --git a/ringbuffer.h b/ringbuffer.h index 396963b7bf..8989f5c4aa 100644 --- a/ringbuffer.h +++ b/ringbuffer.h @@ -40,10 +40,9 @@ int ringbuf_init(const char *capture_name, guint num_files); const gchar *ringbuf_current_filename(void); -wtap_dumper* ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, - int snaplen, int *err); -gboolean ringbuf_switch_file(wtap_dumper **pdh, gchar **save_file, int *save_file_fd, int *err); -gboolean ringbuf_wtap_dump_close(gchar **save_file, int *err); +FILE *ringbuf_init_libpcap_fdopen(int linktype, int snaplen, int *err); +gboolean ringbuf_switch_file(FILE **pdh, gchar **save_file, int *save_file_fd, int *err); +gboolean ringbuf_libpcap_dump_close(gchar **save_file, int *err); void ringbuf_free(void); void ringbuf_error_cleanup(void); diff --git a/tethereal.c b/tethereal.c index aad2172a22..b0775b0625 100644 --- a/tethereal.c +++ b/tethereal.c @@ -95,6 +95,7 @@ #include #include #include "capture-pcap-util.h" +#include "pcapio.h" #include #ifdef _WIN32 #include "capture-wpcap.h" @@ -170,9 +171,9 @@ static void report_counts_siginfo(int); #endif /* HAVE_LIBPCAP */ 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 guchar *pd, int *err); + const guchar *pd); static void show_capture_file_io_error(const char *, int, gboolean); static void show_print_file_io_error(int err); static gboolean write_preamble(capture_file *cf); @@ -1449,10 +1450,16 @@ main(int argc, char *argv[]) exit(status); } - if (!quiet) { + if (!print_packet_info && !quiet) { /* - * The user didn't ask us not to print a count of packets as - * they arrive, so do so. + * We're not printing information for each packet, and the user + * 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; } @@ -1509,7 +1516,7 @@ capture(void) init_dissection(); ld.wtap_linktype = WTAP_ENCAP_UNKNOWN; - ld.wtap_pdh = NULL; + ld.pdh = NULL; ld.packet_cb = capture_pcap_cb; @@ -1545,12 +1552,14 @@ capture(void) goto error; } - /* open the wiretap part of the output file (the output file is already open) */ - if(!capture_loop_init_wiretap_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg)) + /* set up to write to the already-opened capture output file/files */ + if(!capture_loop_init_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg)) { goto error; } + ld.wtap_linktype = wtap_pcap_encap_to_wtap_encap(ld.linktype); + /* Save the capture file name. */ ld.save_file = capture_opts.save_file; @@ -1679,13 +1688,12 @@ capture(void) in effect. */ ld.go = FALSE; } else if (cnd_autostop_size != NULL && - cnd_eval(cnd_autostop_size, - (guint32)wtap_get_bytes_dumped(ld.wtap_pdh))) { + cnd_eval(cnd_autostop_size, (guint32)ld.bytes_written)) { /* We're saving the capture to a file, and the capture file reached its maximum size. */ if (capture_opts.multi_files_on) { /* 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 */ cnd_reset(cnd_autostop_size); if (cnd_file_duration) { @@ -1703,7 +1711,7 @@ capture(void) } if (capture_opts.output_to_pipe) { 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; } } @@ -1806,18 +1814,12 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr, { struct wtap_pkthdr whdr; union wtap_pseudo_header pseudo_header; + const guchar *wtap_pd; loop_data *ld = (loop_data *) user; int loop_err; int err; int save_file_fd; - - /* 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; + gboolean packet_accepted; #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)) { /* 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 */ cnd_reset(cnd_file_duration); } 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)) { - /* 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"); + if (do_dissection) { + /* We're goint to print packet information, run a read filter, or + process taps. Use process_packet() to handle that; in order + to do that, we need to convert from libpcap to Wiretap format. + If that fails, ignore the packet (wtap_process_pcap_packet has + 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 @@ -2017,13 +2053,21 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type) pdh = NULL; } while (wtap_read(cf->wth, &err, &err_info, &data_offset)) { - if (!process_packet(cf, pdh, data_offset, 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 (process_packet(cf, data_offset, wtap_phdr(cf->wth), + wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth))) { + /* Either there's no read filtering or this packet passed the + filter, so, if we're writing to a capture file, write + this packet out. */ + if (pdh != NULL) { + 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) { @@ -2148,10 +2192,8 @@ clear_fdata(frame_data *fdata) } static gboolean -process_packet(capture_file *cf, wtap_dumper *pdh, long offset, - const struct wtap_pkthdr *whdr, - union wtap_pseudo_header *pseudo_header, const guchar *pd, - int *err) +process_packet(capture_file *cf, long offset, const struct wtap_pkthdr *whdr, + union wtap_pseudo_header *pseudo_header, const guchar *pd) { frame_data fdata; gboolean create_proto_tree; @@ -2215,27 +2257,7 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset, } if (passed) { - /* Count this packet. */ -#ifdef HAVE_LIBPCAP - ld.packet_count++; -#endif - /* 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) { /* We're printing packet information; print the information for this packet. */ @@ -2275,7 +2297,7 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset, epan_dissect_free(edt); clear_fdata(&fdata); } - return TRUE; + return passed; } static void