/* tethereal.c
*
- * $Id: tethereal.c,v 1.162 2002/10/23 03:49:10 guy Exp $
+ * $Id: tethereal.c,v 1.176 2003/01/01 03:51:02 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include <setjmp.h>
#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
#ifdef HAVE_LIBZ
#include <zlib.h> /* to get the libz version number */
#endif
# include "snprintf.h"
#endif
-#ifdef HAVE_UCD_SNMP_VERSION_H
+#ifdef HAVE_SOME_SNMP
+
+#ifdef HAVE_NET_SNMP
+#include <net-snmp/version.h>
+#endif /* HAVE_NET_SNMP */
+
+#ifdef HAVE_UCD_SNMP
#include <ucd-snmp/version.h>
-#endif /* HAVE_UCD_SNMP_VERSION_H */
+#endif /* HAVE_UCD_SNMP */
+
+#endif /* HAVE_SOME_SNMP */
#ifdef NEED_STRERROR_H
#include "strerror.h"
#include "ringbuffer.h"
#include <epan/epan_dissect.h>
#include "tap.h"
-#include "tap-rpcstat.h"
-#include "tap-rpcprogs.h"
-#include "packet-dcerpc.h"
-#include "tap-dcerpcstat.h"
#ifdef HAVE_LIBPCAP
#include <wiretap/wtap-capture.h>
+#include <wiretap/libpcap.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include "capture-wpcap.h"
#endif
typedef struct _loop_data {
gboolean go; /* TRUE as long as we're supposed to keep capturing */
gint linktype;
+ gboolean from_pipe; /* TRUE if we are capturing data from a pipe */
pcap_t *pch;
wtap_dumper *pdh;
jmp_buf stopenv;
gboolean output_to_pipe;
int packet_count;
+#ifndef _WIN32
+ gboolean modified; /* TRUE if data in the pipe uses modified pcap headers */
+ gboolean byte_swapped; /* TRUE if data in the pipe is byte swapped */
+ unsigned int bytes_to_read, bytes_read; /* Used by pipe_dispatch */
+ enum {
+ STATE_EXPECT_REC_HDR, STATE_READ_REC_HDR,
+ STATE_EXPECT_DATA, STATE_READ_DATA
+ } pipe_state;
+
+ enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } pipe_err;
+#endif
} loop_data;
static loop_data ld;
static int capture(int);
static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *,
const guchar *);
+static void report_counts(void);
#ifdef _WIN32
static BOOL WINAPI capture_cleanup(DWORD);
#else /* _WIN32 */
static void capture_cleanup(int);
+#ifdef SIGINFO
+static void report_counts_siginfo(int);
+#endif /* SIGINFO */
#endif /* _WIN32 */
#endif /* HAVE_LIBPCAP */
static void show_capture_file_io_error(const char *, int, gboolean);
static void wtap_dispatch_cb_print(guchar *, const struct wtap_pkthdr *, long,
union wtap_pseudo_header *, const guchar *);
+#ifndef _WIN32
+static void adjust_header(loop_data *, struct pcap_hdr *, struct pcaprec_hdr *);
+static int pipe_open_live(char *, struct pcap_hdr *, loop_data *, char *, int);
+static int pipe_dispatch(int, loop_data *, struct pcap_hdr *, \
+ struct pcaprec_modified_hdr *, guchar *, char *, int);
+#endif
capture_file cfile;
ts_type timestamp_type = RELATIVE;
RINGBUFFER_MIN_NUM_FILES /* default number of ring buffer
files */
};
-#endif
+
+#ifdef SIGINFO
+static gboolean infodelay; /* if TRUE, don't print capture info in SIGINFO handler */
+static gboolean infoprint; /* if TRUE, print capture info after clearing infodelay */
+#endif /* SIGINFO */
+#endif /* HAVE_LIBPCAP */
static void
print_usage(gboolean print_ver)
}
#endif
+/* structure to keep track of what tap listeners have been registered.
+ */
+typedef struct _ethereal_tap_list {
+ struct _ethereal_tap_list *next;
+ char *cmd;
+ void (*func)(char *arg);
+} ethereal_tap_list;
+static ethereal_tap_list *tap_list=NULL;
+
+void
+register_ethereal_tap(char *cmd, void (*func)(char *arg), char *dummy _U_, void (*dummy2)(void) _U_)
+{
+ ethereal_tap_list *newtl;
+
+ newtl=malloc(sizeof(ethereal_tap_list));
+ newtl->next=tap_list;
+ tap_list=newtl;
+ newtl->cmd=cmd;
+ newtl->func=func;
+
+}
+
int
main(int argc, char *argv[])
{
#endif /* HAVE_PCAP_VERSION */
#endif /* HAVE_LIBPCAP */
-#ifdef WIN32
+#ifdef _WIN32
WSADATA wsaData;
-
-# ifdef HAVE_UCD_SNMP
- char *mib_path;
-# define MIB_PATH_APPEND "\\snmp\\mibs"
-# endif /* HAVE_UCD_SNMP */
-#endif /* WIN32 */
+#endif /* _WIN32 */
char *gpf_path;
char *pf_path;
dfilter_t *rfcode = NULL;
e_prefs *prefs;
char badopt;
+ ethereal_tap_list *tli;
/* Register all dissectors; we must do this before checking for the
"-G" flag, as the "-G" flag dumps information registered by the
dissectors, and we must do it before we read the preferences, in
case any dissectors register preferences. */
epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
+ register_all_tap_listeners();
/* Now register the preferences for any non-dissector modules.
We must do that before we read the preferences as well. */
/* Set the name resolution code's flags from the preferences. */
g_resolv_flags = prefs->name_resolve;
-#ifdef WIN32
+#ifdef _WIN32
/* Load Wpcap, if possible */
load_wpcap();
#endif
g_string_append(comp_info_str, ", without libz");
#endif /* HAVE_LIBZ */
-/* Oh, this is pretty */
+/* Oh, this is pretty. */
+/* Oh, ha. you think that was pretty. Try this:! --Wes */
+#ifdef HAVE_SOME_SNMP
+
#ifdef HAVE_UCD_SNMP
- g_string_append(comp_info_str, ", with UCD SNMP ");
-#ifdef HAVE_UCD_SNMP_VERSION_H
+ g_string_append(comp_info_str, ", with UCD-SNMP ");
g_string_append(comp_info_str, VersionInfo);
-#else /* HAVE_UCD_SNMP_VERSION_H */
- g_string_append(comp_info_str, "(version unknown)");
-#endif /* HAVE_UCD_SNMP_VERSION_H */
+#endif /* HAVE_UCD_SNMP */
+
+#ifdef HAVE_NET_SNMP
+ g_string_append(comp_info_str, ", with Net-SNMP ");
+ g_string_append(comp_info_str, netsnmp_get_version());
+#endif /* HAVE_NET_SNMP */
+
#else /* no SNMP library */
- g_string_append(comp_info_str, ", without UCD SNMP");
-#endif
+ g_string_append(comp_info_str, ", without UCD-SNMP or Net-SNMP");
+#endif /* HAVE_SOME_SNMP */
/* Now get our args */
while ((opt = getopt(argc, argv, "a:b:c:Df:F:hi:lnN:o:pqr:R:s:St:vw:Vxz:")) != -1) {
print_hex = TRUE;
break;
case 'z':
- if(!strncmp(optarg,"rpc,",4)){
- if(!strncmp(optarg,"rpc,rtt,",8)){
- int rpcprogram, rpcversion;
- int pos=0;
- if(sscanf(optarg,"rpc,rtt,%d,%d,%n",&rpcprogram,&rpcversion,&pos)==2){
- if(pos){
- rpcstat_init(rpcprogram,rpcversion,optarg+pos);
- } else {
- rpcstat_init(rpcprogram,rpcversion,NULL);
- }
- } else {
- fprintf(stderr, "tethereal: invalid \"-z rpc,rtt,<program>,<version>[,<filter>]\" argument\n");
- exit(1);
- }
- } else if(!strncmp(optarg,"rpc,programs",12)){
- rpcprogs_init();
- } else {
- fprintf(stderr, "tethereal: invalid -z argument. Argument must be one of:\n");
- fprintf(stderr, " \"-z rpc,rtt,<program>,<version>[,<filter>]\"\n");
- fprintf(stderr, " \"-z rpc,programs\"\n");
- exit(1);
+ for(tli=tap_list;tli;tli=tli->next){
+ if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
+ (*tli->func)(optarg);
+ break;
}
- } else if(!strncmp(optarg,"dcerpc,",7)){
- if(!strncmp(optarg,"dcerpc,rtt,",11)){
- e_uuid_t uuid;
- int d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
- int major, minor;
- int pos=0;
- if(sscanf(optarg,"dcerpc,rtt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n", &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos)==13){
- uuid.Data1=d1;
- uuid.Data2=d2;
- uuid.Data3=d3;
- uuid.Data4[0]=d40;
- uuid.Data4[1]=d41;
- uuid.Data4[2]=d42;
- uuid.Data4[3]=d43;
- uuid.Data4[4]=d44;
- uuid.Data4[5]=d45;
- uuid.Data4[6]=d46;
- uuid.Data4[7]=d47;
- if(pos){
- dcerpcstat_init(&uuid,major,minor,optarg+pos);
- } else {
- dcerpcstat_init(&uuid,major,minor,NULL);
- }
- } else {
- fprintf(stderr, "tethereal: invalid \"-z dcerpc,rtt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
- exit(1);
- }
- } else {
- fprintf(stderr, "tethereal: invalid -z argument. Argument must be one of:\n");
- fprintf(stderr, " \"-z dcerpc,rtt,<uuid>,<major version>.<minor version>[,<filter>]\"\n");
- exit(1);
+ }
+ if(!tli){
+ fprintf(stderr,"tethereal: invalid -z argument.\n");
+ fprintf(stderr," -z argument must be one of :\n");
+ for(tli=tap_list;tli;tli=tli->next){
+ fprintf(stderr," %s\n",tli->cmd);
}
- } else {
- fprintf(stderr, "tethereal: invalid -z argument. Argument must be one of:\n");
- fprintf(stderr, " \"-z rpc,...\"\n");
- fprintf(stderr, " \"-z dcerpc,...\"\n");
exit(1);
}
break;
ld.output_to_pipe = FALSE;
#endif
if (cfile.save_file != NULL) {
- if (!strcmp(cfile.save_file, "-")) {
+ if (strcmp(cfile.save_file, "-") == 0) {
/* stdout */
g_free(cfile.save_file);
cfile.save_file = g_strdup("");
}
#endif
-#ifdef WIN32
+#ifdef _WIN32
/* Start windows sockets */
WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
-
-# ifdef HAVE_UCD_SNMP
- /* Set MIBDIRS so that the SNMP library can find its mibs. */
- /* XXX - Should we set MIBS or MIBFILES as well? */
-
- mib_path = g_malloc (strlen(get_datafile_dir()) + strlen(MIB_PATH_APPEND) + 20);
- sprintf (mib_path, "MIBDIRS=%s\\%s", get_datafile_dir(), MIB_PATH_APPEND);
- /* Amazingly enough, Windows does not provide setenv(). */
- if (getenv("MIBDIRS") == NULL)
- _putenv(mib_path);
- g_free(mib_path);
-
-# endif /* HAVE_UCD_SNMP */
-#endif /* WIN32 */
+#endif /* _WIN32 */
/* Notify all registered modules that have had any of their preferences
changed either from one of the preferences file or from the command
static int
capture(int out_file_type)
{
+ int pcap_encap;
+ int file_snaplen;
gchar open_err_str[PCAP_ERRBUF_SIZE];
gchar lookup_net_err_str[PCAP_ERRBUF_SIZE];
bpf_u_int32 netnum, netmask;
#ifndef _WIN32
static const char ppamsg[] = "can't find PPA for ";
char *libpcap_warn;
+ volatile int pipe_fd = -1;
+ struct pcap_hdr hdr;
+ struct pcaprec_modified_hdr rechdr;
+ guchar pcap_data[WTAP_MAX_PACKET_SIZE];
#endif
struct pcap_stat stats;
gboolean write_err;
capture_opts.promisc_mode, 1000, open_err_str);
if (ld.pch == NULL) {
- /* Well, we couldn't start the capture. */
+ /* We couldn't open "cfile.iface" as a network device. */
#ifdef _WIN32
+ /* On Windows, we don't support capturing on pipes, so we give up. */
+
/* On Win32 OSes, the capture devices are probably available to all
users; don't warn about permissions problems.
- Do, however, warn that Token Ring and PPP devices aren't supported. */
+ Do, however, warn that WAN devices aren't supported. */
snprintf(errmsg, sizeof errmsg,
"The capture session could not be initiated (%s).\n"
"Please check that you have the proper interface specified.\n"
"\n"
- "Note that the driver Tethereal uses for packet capture on Windows\n"
- "doesn't support capturing on Token Ring interfaces, and doesn't\n"
- "support capturing on PPP/WAN interfaces in Windows NT/2000.\n",
+ "Note that the driver Tethereal uses for packet capture on Windows doesn't\n"
+ "support capturing on PPP/WAN interfaces in Windows NT/2000/XP/.NET Server.\n",
open_err_str);
+ goto error;
#else
- /* If we got a "can't find PPA for XXX" message, warn the user (who
- is running Ethereal on HP-UX) that they don't have a version
- of libpcap that properly handles HP-UX (libpcap 0.6.x and later
- versions, which properly handle HP-UX, say "can't find /dev/dlpi
- PPA for XXX" rather than "can't find PPA for XXX"). */
- if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
- libpcap_warn =
- "\n\n"
- "You are running Tethereal with a version of the libpcap library\n"
- "that doesn't handle HP-UX network devices well; this means that\n"
- "Tethereal may not be able to capture packets.\n"
- "\n"
- "To fix this, you should install libpcap 0.6.2, or a later version\n"
- "of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n"
- "packaged binary form from the Software Porting And Archive Centre\n"
- "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
- "at the URL lists a number of mirror sites.";
- else
- libpcap_warn = "";
- snprintf(errmsg, sizeof errmsg,
- "The capture session could not be initiated (%s).\n"
- "Please check to make sure you have sufficient permissions, and that\n"
- "you have the proper interface specified.%s", open_err_str, libpcap_warn);
+ /* try to open cfile.iface as a pipe */
+ pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld, errmsg, sizeof errmsg);
+
+ if (pipe_fd == -1) {
+
+ if (ld.pipe_err == PIPNEXIST) {
+ /* Pipe doesn't exist, so output message for interface */
+
+ /* If we got a "can't find PPA for XXX" message, warn the user (who
+ is running Tethereal on HP-UX) that they don't have a version
+ of libpcap that properly handles HP-UX (libpcap 0.6.x and later
+ versions, which properly handle HP-UX, say "can't find /dev/dlpi
+ PPA for XXX" rather than "can't find PPA for XXX"). */
+ if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
+ libpcap_warn =
+ "\n\n"
+ "You are running Tethereal with a version of the libpcap library\n"
+ "that doesn't handle HP-UX network devices well; this means that\n"
+ "Tethereal may not be able to capture packets.\n"
+ "\n"
+ "To fix this, you should install libpcap 0.6.2, or a later version\n"
+ "of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n"
+ "packaged binary form from the Software Porting And Archive Centre\n"
+ "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
+ "at the URL lists a number of mirror sites.";
+ else
+ libpcap_warn = "";
+ snprintf(errmsg, sizeof errmsg,
+ "The capture session could not be initiated (%s).\n"
+ "Please check to make sure you have sufficient permissions, and that\n"
+ "you have the proper interface or pipe specified.%s", open_err_str,
+ libpcap_warn);
+ }
+ /*
+ * Else pipe (or file) does exist and pipe_open_live() has
+ * filled in errmsg
+ */
+ goto error;
+ } else
+ /* pipe_open_live() succeeded; don't want
+ error message from pcap_open_live() */
+ open_err_str[0] = '\0';
#endif
- goto error;
}
- if (cfile.cfilter) {
+ if (cfile.cfilter && !ld.from_pipe) {
/* A capture filter was specified; set it up. */
if (pcap_lookupnet(cfile.iface, &netnum, &netmask, lookup_net_err_str) < 0) {
/*
}
}
- ld.linktype = wtap_pcap_encap_to_wtap_encap(get_pcap_linktype(ld.pch,
- cfile.iface));
+ /* Set up to write to the capture file. */
+#ifndef _WIN32
+ if (ld.from_pipe) {
+ pcap_encap = hdr.network;
+ file_snaplen = hdr.snaplen;
+ } else
+#endif
+ {
+ pcap_encap = get_pcap_linktype(ld.pch, cfile.iface);
+ file_snaplen = pcap_snapshot(ld.pch);
+ }
+ ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap);
if (cfile.save_file != NULL) {
/* Set up to write to the capture file. */
if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
signal(SIGINT, capture_cleanup);
if ((oldhandler = signal(SIGHUP, capture_cleanup)) != SIG_DFL)
signal(SIGHUP, oldhandler);
+
+#ifdef SIGINFO
+ /* Catch SIGINFO and, if we get it and we're capturing to a file in
+ quiet mode, report the number of packets we've captured. */
+ signal(SIGINFO, report_counts_siginfo);
+#endif /* SIGINFO */
#endif /* _WIN32 */
/* Let the user know what interface was chosen. */
init_capture_stop_conditions();
/* create stop conditions */
if (capture_opts.has_autostop_filesize)
- cnd_stop_capturesize = cnd_new((char*)CND_CLASS_CAPTURESIZE,
+ cnd_stop_capturesize = cnd_new((const char*)CND_CLASS_CAPTURESIZE,
(long)capture_opts.autostop_filesize * 1000);
if (capture_opts.has_autostop_duration)
- cnd_stop_timeout = cnd_new((char*)CND_CLASS_TIMEOUT,
+ cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT,
(gint32)capture_opts.autostop_duration);
- if (!setjmp(ld.stopenv))
+ if (!setjmp(ld.stopenv)) {
ld.go = TRUE;
- else
+ ld.packet_count = 0;
+ } else
ld.go = FALSE;
- ld.packet_count = 0;
while (ld.go) {
/* We need to be careful with automatic variables defined in the
outer scope which are changed inside the loop. Most compilers
each packet. */
pcap_cnt = 1;
}
- inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (guchar *) &ld);
+#ifndef _WIN32
+ if (ld.from_pipe) {
+ inpkts = pipe_dispatch(pipe_fd, &ld, &hdr, &rechdr, pcap_data,
+ errmsg, sizeof errmsg);
+ } else
+#endif
+ inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (guchar *) &ld);
if (inpkts < 0) {
- /* Error from "pcap_dispatch()". */
+ /* Error from "pcap_dispatch()", or error or "no more packets" from
+ "pipe_dispatch(). */
ld.go = FALSE;
} else if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
/* The specified capture time has elapsed; stop the capture. */
/* If we got an error while capturing, report it. */
if (inpkts < 0) {
- fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
- pcap_geterr(ld.pch));
+#ifndef _WIN32
+ if (ld.from_pipe) {
+ if (ld.pipe_err == PIPERR) {
+ fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
+ errmsg);
+ }
+ } else
+#endif
+ {
+ fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
+ pcap_geterr(ld.pch));
+ }
}
if (volatile_err == 0)
show_capture_file_io_error(cfile.save_file, err, TRUE);
}
- /* Get the capture statistics, and, if any packets were dropped, report
- that. */
- if (pcap_stats(ld.pch, &stats) >= 0) {
- if (stats.ps_drop != 0) {
- fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
+#ifndef _WIN32
+ if (ld.from_pipe && pipe_fd >= 0)
+ close(pipe_fd);
+ else
+#endif
+ {
+ /* Get the capture statistics, and, if any packets were dropped, report
+ that. */
+ if (pcap_stats(ld.pch, &stats) >= 0) {
+ if (stats.ps_drop != 0) {
+ fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
+ }
+ } else {
+ fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
+ pcap_geterr(ld.pch));
}
- } else {
- fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
- pcap_geterr(ld.pch));
+ pcap_close(ld.pch);
}
+
/* Report the number of captured packets if not reported during capture
and we are saving to a file. */
- if (quiet && (cfile.save_file != NULL)) {
- fprintf(stderr, "%u packets captured\n", ld.packet_count);
- }
-
- pcap_close(ld.pch);
+ report_counts();
return TRUE;
g_free(cfile.save_file);
cfile.save_file = NULL;
fprintf(stderr, "tethereal: %s\n", errmsg);
+#ifndef _WIN32
+ if (ld.from_pipe) {
+ if (pipe_fd >= 0)
+ close(pipe_fd);
+ } else
+#endif
+ {
if (ld.pch != NULL)
pcap_close(ld.pch);
+ }
return FALSE;
}
longjmp(ld.stopenv, 1);
}
#endif /* _WIN32 */
+
+static void
+report_counts(void)
+{
+#ifdef SIGINFO
+ /* XXX - if we use sigaction, this doesn't have to be done.
+ (Yes, this isn't necessary on BSD, but just in case a system
+ where "signal()" has AT&T semantics adopts SIGINFO....) */
+ signal(SIGINFO, report_counts_siginfo);
+#endif /* SIGINFO */
+
+ if (cfile.save_file != NULL && quiet) {
+ /* Report the count only if we're capturing to a file (rather
+ than printing captured packet information out) and aren't
+ updating a count as packets arrive. */
+ fprintf(stderr, "%u packets captured\n", ld.packet_count);
+ }
+#ifdef SIGINFO
+ infoprint = FALSE; /* we just reported it */
+#endif /* SIGINFO */
+}
+
+#ifdef SIGINFO
+static void
+report_counts_siginfo(int signum _U_)
+{
+ /* If we've been told to delay printing, just set a flag asking
+ that we print counts (if we're supposed to), otherwise print
+ the count of packets captured (if we're supposed to). */
+ if (infodelay)
+ infoprint = TRUE;
+ else
+ report_counts();
+}
+#endif /* SIGINFO */
#endif /* HAVE_LIBPCAP */
static int
gboolean passed;
epan_dissect_t *edt;
+#ifdef SIGINFO
+ /*
+ * Prevent a SIGINFO handler from writing to stdout while we're
+ * doing so; instead, have it just set a flag telling us to print
+ * that information when we're done.
+ */
+ infodelay = TRUE;
+#endif /* SIGINFO */
+
cf->count++;
if (cf->rfcode) {
fill_in_fdata(&fdata, cf, phdr, offset);
epan_dissect_free(edt);
if (cf->rfcode)
clear_fdata(&fdata);
+
+#ifdef SIGINFO
+ /*
+ * Allow SIGINFO handlers to write.
+ */
+ infodelay = FALSE;
+
+ /*
+ * If a SIGINFO handler asked us to write out capture counts, do so.
+ */
+ if (infoprint)
+ report_counts();
+#endif /* SIGINFO */
}
static void
fill_in_fdata(&fdata, cf, phdr, offset);
passed = TRUE;
- if (cf->rfcode || verbose)
+ if (cf->rfcode || verbose || num_tap_filters!=0)
create_proto_tree = TRUE;
else
create_proto_tree = FALSE;
We only need the columns if we're *not* verbose; in verbose mode,
we print the protocol tree, not the protocol summary. */
+
edt = epan_dissect_new(create_proto_tree, verbose);
if (cf->rfcode) {
epan_dissect_prime_dfilter(edt, cf->rfcode);
fprintf(stderr, "tethereal: %s\n", err_msg);
return (err);
}
+
+#ifndef _WIN32
+/* Take care of byte order in the libpcap headers read from pipes.
+ * (function taken from wiretap/libpcap.c) */
+static void
+adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
+{
+ if (ld->byte_swapped) {
+ /* Byte-swap the record header fields. */
+ rechdr->ts_sec = BSWAP32(rechdr->ts_sec);
+ rechdr->ts_usec = BSWAP32(rechdr->ts_usec);
+ rechdr->incl_len = BSWAP32(rechdr->incl_len);
+ rechdr->orig_len = BSWAP32(rechdr->orig_len);
+ }
+
+ /* In file format version 2.3, the "incl_len" and "orig_len" fields were
+ swapped, in order to match the BPF header layout.
+
+ Unfortunately, some files were, according to a comment in the "libpcap"
+ source, written with version 2.3 in their headers but without the
+ interchanged fields, so if "incl_len" is greater than "orig_len" - which
+ would make no sense - we assume that we need to swap them. */
+ if (hdr->version_major == 2 &&
+ (hdr->version_minor < 3 ||
+ (hdr->version_minor == 3 && rechdr->incl_len > rechdr->orig_len))) {
+ guint32 temp;
+
+ temp = rechdr->orig_len;
+ rechdr->orig_len = rechdr->incl_len;
+ rechdr->incl_len = temp;
+ }
+}
+
+/* Mimic pcap_open_live() for pipe captures
+ * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the
+ * header.
+ * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3
+ * because we can't seek on pipes (see wiretap/libpcap.c for details) */
+static int
+pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
+ char *errmsg, int errmsgl)
+{
+ struct stat pipe_stat;
+ int fd;
+ guint32 magic;
+ int b;
+ unsigned int bytes_read;
+
+ /*
+ * XXX Tethereal blocks until we return
+ */
+ if (strcmp(pipename, "-") == 0)
+ fd = 0; /* read from stdin */
+ else {
+ if (stat(pipename, &pipe_stat) < 0) {
+ if (errno == ENOENT || errno == ENOTDIR)
+ ld->pipe_err = PIPNEXIST;
+ else {
+ snprintf(errmsg, errmsgl,
+ "The capture session could not be initiated "
+ "due to error on pipe: %s", strerror(errno));
+ ld->pipe_err = PIPERR;
+ }
+ return -1;
+ }
+ if (! S_ISFIFO(pipe_stat.st_mode)) {
+ if (S_ISCHR(pipe_stat.st_mode)) {
+ /*
+ * Assume the user specified an interface on a system where
+ * interfaces are in /dev. Pretend we haven't seen it.
+ */
+ ld->pipe_err = PIPNEXIST;
+ } else {
+ snprintf(errmsg, errmsgl,
+ "The capture session could not be initiated because\n"
+ "\"%s\" is neither an interface nor a pipe", pipename);
+ ld->pipe_err = PIPERR;
+ }
+ return -1;
+ }
+ fd = open(pipename, O_RDONLY);
+ if (fd == -1) {
+ snprintf(errmsg, errmsgl,
+ "The capture session could not be initiated "
+ "due to error on pipe open: %s", strerror(errno));
+ ld->pipe_err = PIPERR;
+ return -1;
+ }
+ }
+
+ ld->from_pipe = TRUE;
+
+ /* read the pcap header */
+ bytes_read = 0;
+ while (bytes_read < sizeof magic) {
+ b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read);
+ if (b <= 0) {
+ if (b == 0)
+ snprintf(errmsg, errmsgl, "End of file on pipe during open");
+ else
+ snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+ strerror(errno));
+ goto error;
+ }
+ bytes_read += b;
+ }
+
+ switch (magic) {
+ case PCAP_MAGIC:
+ /* Host that wrote it has our byte order, and was running
+ a program using either standard or ss990417 libpcap. */
+ ld->byte_swapped = FALSE;
+ ld->modified = FALSE;
+ break;
+ case PCAP_MODIFIED_MAGIC:
+ /* Host that wrote it has our byte order, but was running
+ a program using either ss990915 or ss991029 libpcap. */
+ ld->byte_swapped = FALSE;
+ ld->modified = TRUE;
+ break;
+ case PCAP_SWAPPED_MAGIC:
+ /* Host that wrote it has a byte order opposite to ours,
+ and was running a program using either standard or
+ ss990417 libpcap. */
+ ld->byte_swapped = TRUE;
+ ld->modified = FALSE;
+ break;
+ case PCAP_SWAPPED_MODIFIED_MAGIC:
+ /* Host that wrote it out has a byte order opposite to
+ ours, and was running a program using either ss990915
+ or ss991029 libpcap. */
+ ld->byte_swapped = TRUE;
+ ld->modified = TRUE;
+ break;
+ default:
+ /* Not a "libpcap" type we know about. */
+ snprintf(errmsg, errmsgl, "Unrecognized libpcap format");
+ goto error;
+ }
+
+ /* Read the rest of the header */
+ bytes_read = 0;
+ while (bytes_read < sizeof(struct pcap_hdr)) {
+ b = read(fd, ((char *)hdr)+bytes_read,
+ sizeof(struct pcap_hdr) - bytes_read);
+ if (b <= 0) {
+ if (b == 0)
+ snprintf(errmsg, errmsgl, "End of file on pipe during open");
+ else
+ snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+ strerror(errno));
+ goto error;
+ }
+ bytes_read += b;
+ }
+
+ if (ld->byte_swapped) {
+ /* Byte-swap the header fields about which we care. */
+ hdr->version_major = BSWAP16(hdr->version_major);
+ hdr->version_minor = BSWAP16(hdr->version_minor);
+ hdr->snaplen = BSWAP32(hdr->snaplen);
+ hdr->network = BSWAP32(hdr->network);
+ }
+
+ if (hdr->version_major < 2) {
+ snprintf(errmsg, errmsgl, "Unable to read old libpcap format");
+ goto error;
+ }
+
+ ld->pipe_state = STATE_EXPECT_REC_HDR;
+ ld->pipe_err = PIPOK;
+ return fd;
+
+error:
+ ld->pipe_err = PIPERR;
+ close(fd);
+ return -1;
+
+}
+/* We read one record from the pipe, take care of byte order in the record
+ * header, write the record in the capture file, and update capture statistics. */
+
+static int
+pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
+ struct pcaprec_modified_hdr *rechdr, guchar *data,
+ char *errmsg, int errmsgl)
+{
+ struct pcap_pkthdr phdr;
+ int b;
+ enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
+ PD_ERR } result;
+
+ switch (ld->pipe_state) {
+
+ case STATE_EXPECT_REC_HDR:
+ ld->bytes_to_read = ld->modified ?
+ sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
+ ld->bytes_read = 0;
+ ld->pipe_state = STATE_READ_REC_HDR;
+ /* Fall through */
+
+ case STATE_READ_REC_HDR:
+ b = read(fd, ((char *)rechdr)+ld->bytes_read,
+ ld->bytes_to_read - ld->bytes_read);
+ if (b <= 0) {
+ if (b == 0)
+ result = PD_PIPE_EOF;
+ else
+ result = PD_PIPE_ERR;
+ break;
+ }
+ if ((ld->bytes_read += b) < ld->bytes_to_read)
+ return 0;
+ result = PD_REC_HDR_READ;
+ break;
+
+ case STATE_EXPECT_DATA:
+ ld->bytes_read = 0;
+ ld->pipe_state = STATE_READ_DATA;
+ /* Fall through */
+
+ case STATE_READ_DATA:
+ b = read(fd, data+ld->bytes_read, rechdr->hdr.incl_len - ld->bytes_read);
+ if (b <= 0) {
+ if (b == 0)
+ result = PD_PIPE_EOF;
+ else
+ result = PD_PIPE_ERR;
+ break;
+ }
+ if ((ld->bytes_read += b) < rechdr->hdr.incl_len)
+ return 0;
+ result = PD_DATA_READ;
+ break;
+
+ default:
+ snprintf(errmsg, errmsgl, "pipe_dispatch: invalid state");
+ result = PD_ERR;
+
+ } /* switch (ld->pipe_state) */
+
+ /*
+ * We've now read as much data as we were expecting, so process it.
+ */
+ switch (result) {
+
+ case PD_REC_HDR_READ:
+ /* We've read the header. Take care of byte order. */
+ adjust_header(ld, hdr, &rechdr->hdr);
+ if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
+ snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
+ ld->packet_count+1, rechdr->hdr.incl_len);
+ break;
+ }
+ ld->pipe_state = STATE_EXPECT_DATA;
+ return 0;
+
+ case PD_DATA_READ:
+ /* Fill in a "struct pcap_pkthdr", and process the packet. */
+ phdr.ts.tv_sec = rechdr->hdr.ts_sec;
+ phdr.ts.tv_usec = rechdr->hdr.ts_usec;
+ phdr.caplen = rechdr->hdr.incl_len;
+ phdr.len = rechdr->hdr.orig_len;
+
+ capture_pcap_cb((guchar *)ld, &phdr, data);
+
+ ld->pipe_state = STATE_EXPECT_REC_HDR;
+ return 1;
+
+ case PD_PIPE_EOF:
+ ld->pipe_err = PIPEOF;
+ return -1;
+
+ case PD_PIPE_ERR:
+ snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
+ strerror(errno));
+ /* Fall through */
+ case PD_ERR:
+ break;
+ }
+
+ ld->pipe_err = PIPERR;
+ /* Return here rather than inside the switch to prevent GCC warning */
+ return -1;
+}
+#endif