Allow "-w" and/or "-R" to be specified either when doing a live capture

or when reading a saved capture file; if "-w" is specified, the packets
captured or read from the file are written to the specified file rather
than being dissected and printed, and if "-R" is specified, only packets
that pass the specified read filter are dissected and printed or
written.

svn path=/trunk/; revision=1523
This commit is contained in:
Guy Harris 2000-01-22 07:19:34 +00:00
parent 3e067b812c
commit 287efcbbe7
2 changed files with 249 additions and 138 deletions

View File

@ -24,49 +24,59 @@ S<[ B<-x> ]>
=head1 DESCRIPTION =head1 DESCRIPTION
B<Tethereal> is a network protocol analyzer. It lets you capture packet B<Tethereal> is a network protocol analyzer. It lets you capture packet
data from a live network, either printing a decoded form of those data from a live network, or read packets from a previously saved
packets to the standard output or saving the captured packets to a file, capture file, either printing a decoded form of those packets to the
and lets you print a decoded form of packets from a previously saved standard output or writing the packets to a file. B<Tethereal> knows
capture file. B<Tethereal> knows how to read B<libpcap> capture files, how to read B<libpcap> capture files, including those of B<tcpdump>. In
including those of B<tcpdump>. In addition, B<Tethereal> can read addition, B<Tethereal> can read capture files from B<snoop> (including
capture files from B<snoop> (including B<Shomiti>) and B<atmsnoop>, B<Shomiti>) and B<atmsnoop>, B<LanAlyzer>, uncompressed B<Sniffer>,
B<LanAlyzer>, uncompressed B<Sniffer>, Microsoft B<Network Monitor>, Microsoft B<Network Monitor>, AIX's B<iptrace>, B<NetXray>, B<Sniffer
AIX's B<iptrace>, B<NetXray>, B<Sniffer Pro>, B<RADCOM>'s WAN/LAN Pro>, B<RADCOM>'s WAN/LAN analyzer, B<Lucent/Ascend> router debug
analyzer, B<Lucent/Ascend> router debug output, HP-UX's B<nettl>, the output, HP-UX's B<nettl>, the dump output from B<Toshiba's> ISDN
dump output from B<Toshiba's> ISDN routers, and B<i4btrace> from the routers, and B<i4btrace> from the ISDN4BSD project. There is no need to
ISDN4BSD project. There is no need to tell B<Tethereal> what type of tell B<Tethereal> what type of file you are reading; it will determine
file you are reading; it will determine the file type by itself. the file type by itself. B<Tethereal> is also capable of reading any of
B<Tethereal> is also capable of reading any of these file formats if these file formats if they are compressed using gzip. B<Tethereal>
they are compressed using gzip. B<Tethereal> recognizes this directly recognizes this directly from the file; the '.gz' extension is not
from the file; the '.gz' extension is not required for this purpose. required for this purpose.
By default, when writing a capture file, B<Tethereal> writes capture If the B<-w> flag is not specified, B<Tethereal> prints a decoded form
file in B<libpcap> format, and writes all of the packets in the capture of the packets it captures or reads; otherwise, it writes those packets
file to the output file. The B<-F> flag can be used to specify the to the file specified by that flag.
format in which to write the capture file; it can write the file in
B<libpcap> format (standard B<libpcap> format, a modified format used by
some patched versions of B<libpcap>, or the format used by Red Hat Linux
6.1), B<snoop> format, uncompressed B<Sniffer> format, Microsoft
B<Network Monitor> 1.x format, and the format used by Windows-based
versions of the B<Sniffer> software.
By default, when printing a decoded form of packets, B<Tethereal> prints When printing a decoded form of packets, B<Tethereal> prints, by
a summary line giving a time stamp for the packet, the source and default, a summary line giving a time stamp for the packet, the source
destination address for the packet, the top-level protocol for the and destination address for the packet, the top-level protocol for the
packet that B<Tethereal> understands, and a summary of the packet's packet that B<Tethereal> understands, and a summary of the packet's
contents for that protocol. It can also print a protocol tree, showing contents for that protocol. If the B<-V> flag is specified, it prints
all the fields of all protocols in the packet. intead a protocol tree, showing all the fields of all protocols in the
packet.
When writing packets to a file, B<Tethereal>, by default, writes the
file in B<libpcap> format, and writes all of the packets it sees to the
output file. The B<-F> flag can be used to specify the format in which
to write the file; it can write the file in B<libpcap> format (standard
B<libpcap> format, a modified format used by some patched versions of
B<libpcap>, or the format used by Red Hat Linux 6.1), B<snoop> format,
uncompressed B<Sniffer> format, Microsoft B<Network Monitor> 1.x format,
and the format used by Windows-based versions of the B<Sniffer>
software.
Read filters in B<Tethereal>, which allow you to select which packets Read filters in B<Tethereal>, which allow you to select which packets
are to be decoded when reading a saved capture file, are very powerful; are to be decoded or written to a file, are very powerful; more fields
more fields are filterable in B<Tethereal> than in other protocol are filterable in B<Tethereal> than in other protocol analyzers, and the
analyzers, and the syntax you can use to create your filters is richer. syntax you can use to create your filters is richer. As B<Tethereal>
As B<Tethereal> progresses, expect more and more protocol fields to be progresses, expect more and more protocol fields to be allowed in read
allowed in read filters. filters.
Packet capturing is performed with the pcap library. The capture filter Packet capturing is performed with the pcap library. The capture filter
syntax follows the rules of the pcap library. This syntax is different syntax follows the rules of the pcap library. This syntax is different
from the read filter syntax. from the read filter syntax. A read filter can also be specified when
capturing, and only packets that pass the read filter will be displayed
or saved to the output file; note, however, that capture filers are much
more efficient than read filters, and it may be more difficult for
B<Tethereal> to keep up with a busy network if a read filter is
specified for a live capture.
Compressed file support uses (and therefore requires) the zlib library. Compressed file support uses (and therefore requires) the zlib library.
If the zlib library is not present, B<Tethereal> will compile, but will If the zlib library is not present, B<Tethereal> will compile, but will
@ -115,9 +125,9 @@ Reads packet data from I<file>.
=item -R =item -R
Causes the specified filter (which uses the syntax of read filters, Causes the specified filter (which uses the syntax of read filters,
rather than that of capture filters) to be applied, when a capture file rather than that of capture filters) to be applied before printing a
is read, to all packets read from the capture file; packets not matching decoded form of packets or writing packets to a file; packets not
the filter are discarded. matching the filter are discarded rather than being printed or written.
=item -s =item -s
@ -145,7 +155,7 @@ a one-line summary of the packet.
=item -w =item -w
Sets the default capture file name. Writes packet data to I<savefile>.
=item -x =item -x

View File

@ -1,6 +1,6 @@
/* tethereal.c /* tethereal.c
* *
* $Id: tethereal.c,v 1.11 2000/01/22 06:22:19 guy Exp $ * $Id: tethereal.c,v 1.12 2000/01/22 07:19:26 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org> * By Gerald Combs <gerald@zing.org>
@ -100,8 +100,15 @@ static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
static void capture_cleanup(int); static void capture_cleanup(int);
#endif #endif
static int load_cap_file(capture_file *); typedef struct {
static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int, capture_file *cf;
wtap_dumper *pdh;
} cb_args_t;
static int load_cap_file(capture_file *, int);
static void wtap_dispatch_cb_write(u_char *, const struct wtap_pkthdr *, int,
const u_char *);
static void wtap_dispatch_cb_print(u_char *, const struct wtap_pkthdr *, int,
const u_char *); const u_char *);
static gchar *col_info(frame_data *, gint); static gchar *col_info(frame_data *, gint);
@ -334,12 +341,7 @@ main(int argc, char *argv[])
exit(0); exit(0);
break; break;
case 'w': /* Write to capture file xxx */ case 'w': /* Write to capture file xxx */
#ifdef HAVE_LIBPCAP
cf.save_file = g_strdup(optarg); cf.save_file = g_strdup(optarg);
#else
capture_option_specified = TRUE;
arg_error = TRUE;
#endif
break; break;
case 'V': /* Verbose */ case 'V': /* Verbose */
verbose = TRUE; verbose = TRUE;
@ -377,7 +379,6 @@ main(int argc, char *argv[])
ethereal_proto_init(); /* Init anything that needs initializing */ ethereal_proto_init(); /* Init anything that needs initializing */
if (cf_name) {
if (rfilter != NULL) { if (rfilter != NULL) {
if (dfilter_compile(rfilter, &rfcode) != 0) { if (dfilter_compile(rfilter, &rfcode) != 0) {
fprintf(stderr, "tethereal: %s\n", dfilter_error_msg); fprintf(stderr, "tethereal: %s\n", dfilter_error_msg);
@ -385,13 +386,14 @@ main(int argc, char *argv[])
exit(2); exit(2);
} }
} }
cf.rfcode = rfcode;
if (cf_name) {
err = open_cap_file(cf_name, FALSE, &cf); err = open_cap_file(cf_name, FALSE, &cf);
if (err != 0) { if (err != 0) {
ethereal_proto_cleanup(); ethereal_proto_cleanup();
exit(2); exit(2);
} }
cf.rfcode = rfcode; err = load_cap_file(&cf, out_file_type);
err = load_cap_file(&cf);
if (err != 0) { if (err != 0) {
ethereal_proto_cleanup(); ethereal_proto_cleanup();
exit(2); exit(2);
@ -568,21 +570,22 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
{ {
struct wtap_pkthdr whdr; struct wtap_pkthdr whdr;
loop_data *ld = (loop_data *) user; loop_data *ld = (loop_data *) user;
int err; cb_args_t args;
whdr.ts = phdr->ts; whdr.ts = phdr->ts;
whdr.caplen = phdr->caplen; whdr.caplen = phdr->caplen;
whdr.len = phdr->len; whdr.len = phdr->len;
whdr.pkt_encap = ld->linktype; whdr.pkt_encap = ld->linktype;
args.cf = &cf;
args.pdh = ld->pdh;
if (ld->pdh) { if (ld->pdh) {
/* XXX - do something if this fails */ wtap_dispatch_cb_write((u_char *)&args, &whdr, 0, pd);
wtap_dump(ld->pdh, &whdr, pd, &err);
cf.count++; cf.count++;
printf("\r%u ", cf.count); printf("\r%u ", cf.count);
fflush(stdout); fflush(stdout);
} else { } else {
wtap_dispatch_cb((u_char *)&cf, &whdr, 0, pd); wtap_dispatch_cb_print((u_char *)&args, &whdr, 0, pd);
} }
} }
@ -601,41 +604,100 @@ capture_cleanup(int signum)
#endif /* HAVE_LIBPCAP */ #endif /* HAVE_LIBPCAP */
static int static int
load_cap_file(capture_file *cf) load_cap_file(capture_file *cf, int out_file_type)
{ {
gint linktype;
wtap_dumper *pdh;
int err; int err;
int success; int success;
char *errmsg; cb_args_t args;
char errmsg_errno[1024+1];
success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err); linktype = wtap_file_encap(cf->wth);
if (cf->save_file != NULL) {
/* Set up to write to the capture file. */
pdh = wtap_dump_open(cf->save_file, out_file_type,
linktype, wtap_snapshot_length(cf->wth), &err);
if (pdh == NULL) {
/* We couldn't set up to write to the capture file. */
switch (err) {
case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
fprintf(stderr,
"tethereal: Capture files can't be written in that format.\n");
break;
case WTAP_ERR_UNSUPPORTED_ENCAP:
case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
fprintf(stderr,
"tethereal: The capture file being read cannot be written in that format.\n");
break;
case WTAP_ERR_CANT_OPEN:
fprintf(stderr,
"tethereal: The file \"%s\" couldn't be created for some unknown reason.\n",
cf->save_file);
break;
case WTAP_ERR_SHORT_WRITE:
fprintf(stderr,
"tethereal: A full header couldn't be written to the file \"%s\".\n",
cf->save_file);
break;
default:
if (err < 0) {
fprintf(stderr,
"tethereal: The file \"%s\" could not be opened: Error %d.\n",
cf->save_file, err);
} else {
fprintf(stderr,
"tethereal: The file \"%s\" could not be opened: %s\n.",
cf->save_file, strerror(err));
}
break;
}
goto out;
}
args.cf = cf;
args.pdh = pdh;
success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_write, (u_char *) &args,
&err);
} else {
args.cf = cf;
args.pdh = NULL;
success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_print, (u_char *) &args,
&err);
}
if (!success) { if (!success) {
/* Print up a message box noting that the read failed somewhere along /* Print up a message box noting that the read failed somewhere along
the line. */ the line. */
switch (err) { switch (err) {
case WTAP_ERR_CANT_READ: case WTAP_ERR_CANT_READ:
errmsg = "An attempt to read from the file failed for" fprintf(stderr,
" some unknown reason."; "tethereal: An attempt to read from the file failed for some unknown reason.\n");
break; break;
case WTAP_ERR_SHORT_READ: case WTAP_ERR_SHORT_READ:
errmsg = "The capture file appears to have been cut short" fprintf(stderr,
" in the middle of a packet."; "tethereal: The capture file appears to have been cut short in the middle of a packet.\n");
break; break;
case WTAP_ERR_BAD_RECORD: case WTAP_ERR_BAD_RECORD:
errmsg = "The capture file appears to be damaged or corrupt."; fprintf(stderr,
"tethereal: The capture file appears to be damaged or corrupt.\n");
break; break;
default: default:
sprintf(errmsg_errno, "An error occurred while reading the" fprintf(stderr,
" capture file: %s.", wtap_strerror(err)); "tethereal: An error occurred while reading the capture file: %s.\n",
errmsg = errmsg_errno; wtap_strerror(err));
break; break;
} }
fprintf(stderr, "tethereal: %s\n", errmsg);
} }
out:
wtap_close(cf->wth); wtap_close(cf->wth);
cf->wth = NULL; cf->wth = NULL;
@ -643,78 +705,117 @@ load_cap_file(capture_file *cf)
} }
static void static void
wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset, fill_in_fdata(frame_data *fdata, capture_file *cf,
const u_char *buf) const struct wtap_pkthdr *phdr, int offset)
{ {
frame_data fdata; int i;
gint i;
capture_file *cf = (capture_file *) user;
proto_tree *protocol_tree;
gboolean passed;
print_args_t print_args;
cf->count++; fdata->next = NULL;
fdata->prev = NULL;
fdata->pkt_len = phdr->len;
fdata->cap_len = phdr->caplen;
fdata->file_off = offset;
fdata->lnk_t = phdr->pkt_encap;
fdata->abs_secs = phdr->ts.tv_sec;
fdata->abs_usecs = phdr->ts.tv_usec;
fdata->encoding = CHAR_ASCII;
fdata->pseudo_header = phdr->pseudo_header;
fdata->cinfo = NULL;
fdata.next = NULL; fdata->num = cf->count;
fdata.prev = NULL;
fdata.pkt_len = phdr->len;
fdata.cap_len = phdr->caplen;
fdata.file_off = offset;
fdata.lnk_t = phdr->pkt_encap;
fdata.abs_secs = phdr->ts.tv_sec;
fdata.abs_usecs = phdr->ts.tv_usec;
fdata.encoding = CHAR_ASCII;
fdata.pseudo_header = phdr->pseudo_header;
fdata.cinfo = NULL;
fdata.num = cf->count;
/* If we don't have the time stamp of the first packet in the /* If we don't have the time stamp of the first packet in the
capture, it's because this is the first packet. Save the time capture, it's because this is the first packet. Save the time
stamp of this packet as the time stamp of the first packet. */ stamp of this packet as the time stamp of the first packet. */
if (!firstsec && !firstusec) { if (!firstsec && !firstusec) {
firstsec = fdata.abs_secs; firstsec = fdata->abs_secs;
firstusec = fdata.abs_usecs; firstusec = fdata->abs_usecs;
} }
/* Get the time elapsed between the first packet and this packet. */ /* Get the time elapsed between the first packet and this packet. */
cf->esec = fdata.abs_secs - firstsec; cf->esec = fdata->abs_secs - firstsec;
if (firstusec <= fdata.abs_usecs) { if (firstusec <= fdata->abs_usecs) {
cf->eusec = fdata.abs_usecs - firstusec; cf->eusec = fdata->abs_usecs - firstusec;
} else { } else {
cf->eusec = (fdata.abs_usecs + 1000000) - firstusec; cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
cf->esec--; cf->esec--;
} }
fdata.cinfo = &cf->cinfo;
for (i = 0; i < fdata.cinfo->num_cols; i++) {
fdata.cinfo->col_data[i][0] = '\0';
}
/* If we don't have the time stamp of the previous displayed packet, /* If we don't have the time stamp of the previous displayed packet,
it's because this is the first displayed packet. Save the time it's because this is the first displayed packet. Save the time
stamp of this packet as the time stamp of the previous displayed stamp of this packet as the time stamp of the previous displayed
packet. */ packet. */
if (!prevsec && !prevusec) { if (!prevsec && !prevusec) {
prevsec = fdata.abs_secs; prevsec = fdata->abs_secs;
prevusec = fdata.abs_usecs; prevusec = fdata->abs_usecs;
} }
/* Get the time elapsed between the first packet and this packet. */ /* Get the time elapsed between the first packet and this packet. */
fdata.rel_secs = cf->esec; fdata->rel_secs = cf->esec;
fdata.rel_usecs = cf->eusec; fdata->rel_usecs = cf->eusec;
/* Get the time elapsed between the previous displayed packet and /* Get the time elapsed between the previous displayed packet and
this packet. */ this packet. */
fdata.del_secs = fdata.abs_secs - prevsec; fdata->del_secs = fdata->abs_secs - prevsec;
if (prevusec <= fdata.abs_usecs) { if (prevusec <= fdata->abs_usecs) {
fdata.del_usecs = fdata.abs_usecs - prevusec; fdata->del_usecs = fdata->abs_usecs - prevusec;
} else { } else {
fdata.del_usecs = (fdata.abs_usecs + 1000000) - prevusec; fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
fdata.del_secs--; fdata->del_secs--;
} }
prevsec = fdata.abs_secs; prevsec = fdata->abs_secs;
prevusec = fdata.abs_usecs; prevusec = fdata->abs_usecs;
fdata->cinfo = &cf->cinfo;
for (i = 0; i < fdata->cinfo->num_cols; i++) {
fdata->cinfo->col_data[i][0] = '\0';
}
}
static void
wtap_dispatch_cb_write(u_char *user, const struct wtap_pkthdr *phdr, int offset,
const u_char *buf)
{
cb_args_t *args = (cb_args_t *) user;
capture_file *cf = args->cf;
wtap_dumper *pdh = args->pdh;
frame_data fdata;
proto_tree *protocol_tree;
int err;
gboolean passed;
cf->count++;
if (cf->rfcode) {
fill_in_fdata(&fdata, cf, phdr, offset);
protocol_tree = proto_tree_create_root();
dissect_packet(buf, &fdata, protocol_tree);
passed = dfilter_apply(cf->rfcode, protocol_tree, buf);
} else {
protocol_tree = NULL;
passed = TRUE;
}
if (passed) {
/* XXX - do something if this fails */
wtap_dump(pdh, phdr, buf, &err);
}
if (protocol_tree != NULL)
proto_tree_free(protocol_tree);
}
static void
wtap_dispatch_cb_print(u_char *user, const struct wtap_pkthdr *phdr, int offset,
const u_char *buf)
{
cb_args_t *args = (cb_args_t *) user;
capture_file *cf = args->cf;
frame_data fdata;
proto_tree *protocol_tree;
gboolean passed;
print_args_t print_args;
cf->count++;
fill_in_fdata(&fdata, cf, phdr, offset);
passed = TRUE; passed = TRUE;
if (cf->rfcode || verbose) if (cf->rfcode || verbose)