summaryrefslogtreecommitdiff
path: root/tshark.c
diff options
context:
space:
mode:
Diffstat (limited to 'tshark.c')
-rw-r--r--tshark.c302
1 files changed, 277 insertions, 25 deletions
diff --git a/tshark.c b/tshark.c
index b43bdb7d67..0088b8ae84 100644
--- a/tshark.c
+++ b/tshark.c
@@ -112,6 +112,8 @@ static nstime_t prev_cap_ts;
static gboolean print_packet_info; /* TRUE if we're to print packet information */
+static gboolean perform_two_pass_analysis;
+
/*
* The way the packet decode is to be written.
*/
@@ -764,7 +766,7 @@ main(int argc, char *argv[])
GLogLevelFlags log_flags;
int optind_initial;
-#define OPTSTRING_INIT "a:b:c:C:d:De:E:f:F:G:hi:K:lLnN:o:pqr:R:s:St:T:vVw:xX:y:z:"
+#define OPTSTRING_INIT "a:b:c:C:d:De:E:f:F:G:hi:K:lLnN:o:pPqr:R:s:St:T:vVw:xX:y:z:"
#ifdef HAVE_LIBPCAP
#ifdef _WIN32
#define OPTSTRING_WIN32 "B:"
@@ -1081,6 +1083,11 @@ main(int argc, char *argv[])
arg_error = TRUE;
#endif
break;
+#if GLIB_CHECK_VERSION(2,10,0)
+ case 'P': /* Perform two pass analysis */
+ perform_two_pass_analysis = TRUE;
+ break;
+#endif
case 'n': /* No name resolution */
g_resolv_flags = RESOLV_NONE;
break;
@@ -1622,6 +1629,11 @@ main(int argc, char *argv[])
#endif
}
+#if GLIB_CHECK_VERSION(2,10,0)
+ if (cfile.plist_start != NULL)
+ g_slice_free_chain(frame_data, cfile.plist_start, next);
+#endif
+
draw_tap_listeners(TRUE);
funnel_dump_all_text_windows();
epan_cleanup();
@@ -2165,6 +2177,181 @@ capture_cleanup(int signum _U_)
#endif /* _WIN32 */
#endif /* HAVE_LIBPCAP */
+#if GLIB_CHECK_VERSION(2,10,0)
+static gboolean
+process_packet_first_pass(capture_file *cf,
+ gint64 offset, const struct wtap_pkthdr *whdr,
+ union wtap_pseudo_header *pseudo_header, const guchar *pd)
+{
+ frame_data *fdata = g_slice_new(frame_data);
+ epan_dissect_t edt;
+ gboolean passed;
+
+ /* Count this packet. */
+ cf->count++;
+
+ /* If we're not running a display filter and we're not printing any
+ packet information, we don't need to do a dissection. This means
+ that all packets can be marked as 'passed'. */
+ passed = TRUE;
+
+ frame_data_init(fdata, cf->count, whdr, offset, cum_bytes);
+
+ /* If we're going to print packet information, or we're going to
+ run a read filter, or we're going to process taps, set up to
+ do a dissection and do so. */
+ if (do_dissection) {
+ if (g_resolv_flags)
+ /* Grab any resolved addresses */
+ host_name_lookup_process(NULL);
+
+ /* The protocol tree will be "visible", i.e., printed, only if we're
+ printing packet details, which is true if we're printing stuff
+ ("print_packet_info" is true) and we're in verbose mode ("verbose"
+ is true). */
+ epan_dissect_init(&edt, FALSE, FALSE);
+
+ /* If we're running a read filter, prime the epan_dissect_t with that
+ filter. */
+ if (cf->rfcode)
+ epan_dissect_prime_dfilter(&edt, cf->rfcode);
+
+ frame_data_set_before_dissect(fdata, &cf->elapsed_time,
+ &first_ts, &prev_dis_ts, &prev_cap_ts);
+
+ epan_dissect_run(&edt, pseudo_header, pd, fdata, NULL);
+
+ /* Run the read filter if we have one. */
+ if (cf->rfcode)
+ passed = dfilter_apply_edt(cf->rfcode, &edt);
+ }
+
+ if (passed) {
+ frame_data_set_after_dissect(fdata, &cum_bytes, &prev_dis_ts);
+ cap_file_add_fdata(cf, fdata);
+ }
+ else
+ g_slice_free(frame_data, fdata);
+
+ if (do_dissection)
+ epan_dissect_cleanup(&edt);
+
+ return passed;
+}
+
+static gboolean
+process_packet_second_pass(capture_file *cf, frame_data *fdata,
+ gint64 offset, union wtap_pseudo_header *pseudo_header, const guchar *pd,
+ gboolean filtering_tap_listeners, guint tap_flags)
+{
+ gboolean create_proto_tree;
+ column_info *cinfo;
+ epan_dissect_t edt;
+ gboolean passed;
+
+ /* If we're not running a display filter and we're not printing any
+ packet information, we don't need to do a dissection. This means
+ that all packets can be marked as 'passed'. */
+ passed = TRUE;
+
+ /* If we're going to print packet information, or we're going to
+ run a read filter, or we're going to process taps, set up to
+ do a dissection and do so. */
+ if (do_dissection) {
+ if (g_resolv_flags)
+ /* Grab any resolved addresses */
+ host_name_lookup_process(NULL);
+
+ if (cf->rfcode || verbose || filtering_tap_listeners ||
+ (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo))
+ create_proto_tree = TRUE;
+ else
+ create_proto_tree = FALSE;
+
+ /* The protocol tree will be "visible", i.e., printed, only if we're
+ printing packet details, which is true if we're printing stuff
+ ("print_packet_info" is true) and we're in verbose mode ("verbose"
+ is true). */
+ epan_dissect_init(&edt, create_proto_tree, print_packet_info && verbose);
+
+ /* If we're running a read filter, prime the epan_dissect_t with that
+ filter. */
+ if (cf->rfcode)
+ epan_dissect_prime_dfilter(&edt, cf->rfcode);
+
+ col_custom_prime_edt(&edt, &cf->cinfo);
+
+ tap_queue_init(&edt);
+
+ /* We only need the columns if either
+
+ 1) some tap needs the columns
+
+ or
+
+ 2) we're printing packet info but we're *not* verbose; in verbose
+ mode, we print the protocol tree, not the protocol summary. */
+ if ((tap_flags & TL_REQUIRES_COLUMNS) || (print_packet_info && !verbose))
+ cinfo = &cf->cinfo;
+ else
+ cinfo = NULL;
+
+ epan_dissect_run(&edt, pseudo_header, pd, fdata, cinfo);
+
+ tap_push_tapped_queue(&edt);
+
+ /* Run the read filter if we have one. */
+ if (cf->rfcode)
+ passed = dfilter_apply_edt(cf->rfcode, &edt);
+ }
+
+ if (passed) {
+ /* Process this packet. */
+ if (print_packet_info) {
+ /* We're printing packet information; print the information for
+ this packet. */
+ if (do_dissection)
+ print_packet(cf, &edt);
+ else
+ print_packet(cf, NULL);
+
+ /* The ANSI C standard does not appear to *require* that a line-buffered
+ stream be flushed to the host environment whenever a newline is
+ written, it just says that, on such a stream, characters "are
+ intended to be transmitted to or from the host environment as a
+ block when a new-line character is encountered".
+
+ The Visual C++ 6.0 C implementation doesn't do what is intended;
+ even if you set a stream to be line-buffered, it still doesn't
+ flush the buffer at the end of every line.
+
+ So, if the "-l" flag was specified, we flush the standard output
+ at the end of a packet. This will do the right thing if we're
+ printing packet summary lines, and, as we print the entire protocol
+ tree for a single packet without waiting for anything to happen,
+ it should be as good as line-buffered mode if we're printing
+ protocol trees. (The whole reason for the "-l" flag in either
+ tcpdump or TShark is to allow the output of a live capture to
+ be piped to a program or script and to have that script see the
+ information for the packet as soon as it's printed, rather than
+ having to wait until a standard I/O buffer fills up. */
+ if (line_buffered)
+ fflush(stdout);
+
+ if (ferror(stdout)) {
+ show_print_file_io_error(errno);
+ exit(2);
+ }
+ }
+ }
+
+ if (do_dissection) {
+ epan_dissect_cleanup(&edt);
+ }
+ return passed;
+}
+#endif
+
static int
load_cap_file(capture_file *cf, char *save_file, int out_file_type,
int max_packet_count, gint64 max_byte_count)
@@ -2241,34 +2428,99 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
/* Get the union of the flags for all tap listeners. */
tap_flags = union_of_tap_listener_flags();
- while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
- if (process_packet(cf, data_offset, wtap_phdr(cf->wth),
- wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
- filtering_tap_listeners, tap_flags)) {
- /* 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 (perform_two_pass_analysis) {
+#if GLIB_CHECK_VERSION(2,10,0)
+ frame_data *fdata;
+ int old_max_packet_count = max_packet_count;
+
+ while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
+ if (process_packet_first_pass(cf, data_offset, wtap_phdr(cf->wth),
+ wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth))) {
+ /* Stop reading if we have the maximum number of packets;
+ * When the -c option has not been used, max_packet_count
+ * starts at 0, which practically means, never stop reading.
+ * (unless we roll over max_packet_count ?)
+ */
+ if( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
+ err = 0; /* This is not an error */
+ break;
}
}
- /* Stop reading if we have the maximum number of packets;
- * When the -c option has not been used, max_packet_count
- * starts at 0, which practically means, never stop reading.
- * (unless we roll over max_packet_count ?)
- */
- if( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
- err = 0; /* This is not an error */
- break;
+ }
+
+ /* Close the sequential I/O side, to free up memory it requires. */
+ wtap_sequential_close(cf->wth);
+
+ /* Allow the protocol dissectors to free up memory that they
+ * don't need after the sequential run-through of the packets. */
+ postseq_cleanup_all_protocols();
+
+ max_packet_count = old_max_packet_count;
+
+ for (fdata = cf->plist_start; err == 0 && fdata != NULL; fdata = fdata->next) {
+ if (wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
+ cf->pd, fdata->cap_len, &err, &err_info)) {
+ if (process_packet_second_pass(cf, fdata, fdata->file_off,
+ &cf->pseudo_header, cf->pd,
+ filtering_tap_listeners, tap_flags)) {
+ /* 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);
+ }
+ }
+ /* Stop reading if we have the maximum number of packets;
+ * When the -c option has not been used, max_packet_count
+ * starts at 0, which practically means, never stop reading.
+ * (unless we roll over max_packet_count ?)
+ */
+ if( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
+ err = 0; /* This is not an error */
+ break;
+ }
+ }
}
}
+#endif
}
+ else {
+ while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
+ if (process_packet(cf, data_offset, wtap_phdr(cf->wth),
+ wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
+ filtering_tap_listeners, tap_flags)) {
+ /* 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);
+ }
+ }
+ /* Stop reading if we have the maximum number of packets;
+ * When the -c option has not been used, max_packet_count
+ * starts at 0, which practically means, never stop reading.
+ * (unless we roll over max_packet_count ?)
+ */
+ if( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
+ err = 0; /* This is not an error */
+ break;
+ }
+ }
+ }
+ }
+
if (err != 0) {
/* Print a message noting that the read failed somewhere along the line. */
switch (err) {
@@ -3009,7 +3261,7 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
gchar *err_info;
char err_msg[2048+1];
- wth = wtap_open_offline(fname, err, &err_info, FALSE);
+ wth = wtap_open_offline(fname, err, &err_info, perform_two_pass_analysis);
if (wth == NULL)
goto fail;