3 * $Id: tethereal.c,v 1.84 2001/06/05 07:38:33 guy Exp $
5 * Ethereal - Network traffic analyzer
6 * By Gerald Combs <gerald@ethereal.com>
7 * Copyright 1998 Gerald Combs
9 * Text-mode variant, by Gilbert Ramirez <gram@xiexie.org>.
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43 #ifdef HAVE_SYS_TYPES_H
44 #include <sys/types.h>
47 #ifdef HAVE_SYS_STAT_H
61 #ifdef NEED_SNPRINTF_H
62 # include "snprintf.h"
65 #if defined(HAVE_UCD_SNMP_SNMP_H)
66 #ifdef HAVE_UCD_SNMP_VERSION_H
67 #include <ucd-snmp/version.h>
68 #endif /* HAVE_UCD_SNMP_VERSION_H */
69 #elif defined(HAVE_SNMP_SNMP_H)
70 #ifdef HAVE_SNMP_VERSION_H
71 #include <snmp/version.h>
72 #endif /* HAVE_SNMP_VERSION_H */
75 #ifdef NEED_STRERROR_H
87 #include "timestamp.h"
95 #include "conversation.h"
100 #include "capture-wpcap.h"
103 static guint32 firstsec, firstusec;
104 static guint32 prevsec, prevusec;
105 static GString *comp_info_str;
106 static gboolean verbose;
107 static gboolean print_hex;
108 static gboolean line_buffered;
111 typedef struct _loop_data {
119 static int capture(int, int);
120 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
122 static void capture_cleanup(int);
130 static int load_cap_file(capture_file *, int);
131 static void wtap_dispatch_cb_write(u_char *, const struct wtap_pkthdr *, int,
132 union wtap_pseudo_header *, const u_char *);
133 static void show_capture_file_io_error(const char *, int, gboolean);
134 static void wtap_dispatch_cb_print(u_char *, const struct wtap_pkthdr *, int,
135 union wtap_pseudo_header *, const u_char *);
139 FILE *data_out_file = NULL;
140 ts_type timestamp_type = RELATIVE;
142 static int promisc_mode = TRUE;
150 fprintf(stderr, "This is GNU t%s %s, compiled %s\n", PACKAGE, VERSION,
153 fprintf(stderr, "t%s [ -DvVhlp ] [ -c <count> ] [ -f <capture filter> ]\n", PACKAGE);
154 fprintf(stderr, "\t[ -F <capture file type> ] [ -i <interface> ] [ -n ] [ -N <resolving> ]\n");
155 fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r <infile> ] [ -R <read filter> ]\n");
156 fprintf(stderr, "\t[ -s <snaplen> ] [ -t <time stamp format> ] [ -w <savefile> ] [ -x ]\n");
158 fprintf(stderr, "t%s [ -vVhl ] [ -F <capture file type> ] [ -n ] [ -N <resolving> ]\n", PACKAGE);
159 fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r <infile> ] [ -R <read filter> ]\n");
160 fprintf(stderr, "\t[ -t <time stamp format> ] [ -w <savefile> ] [ -x ]\n");
162 fprintf(stderr, "Valid file type arguments to the \"-F\" flag:\n");
163 for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
164 if (wtap_dump_can_open(i))
165 fprintf(stderr, "\t%s - %s\n",
166 wtap_file_type_short_string(i), wtap_file_type_string(i));
168 fprintf(stderr, "\tdefault is libpcap\n");
172 get_positive_int(const char *string, const char *name)
177 number = strtol(string, &p, 10);
178 if (p == string || *p != '\0') {
179 fprintf(stderr, "tethereal: The specified %s \"%s\" is not a decimal number\n",
184 fprintf(stderr, "tethereal: The specified %s \"%s\" is a negative number\n",
188 if (number > INT_MAX) {
189 fprintf(stderr, "tethereal: The specified %s \"%s\" is too large (greater than %d)\n",
190 name, string, INT_MAX);
197 main(int argc, char *argv[])
201 gboolean arg_error = FALSE;
204 char pcap_version[] = WPCAP_STRING;
206 extern char pcap_version[];
214 char *gpf_path, *pf_path;
215 int gpf_open_errno, pf_open_errno;
218 gboolean capture_filter_specified = FALSE;
219 int packet_count = 0;
220 GList *if_list, *if_entry;
221 gchar err_str[PCAP_ERRBUF_SIZE];
223 gboolean capture_option_specified = FALSE;
225 int out_file_type = WTAP_FILE_PCAP;
226 gchar *cf_name = NULL, *rfilter = NULL;
227 dfilter_t *rfcode = NULL;
231 /* Register all dissectors; we must do this before checking for the
232 "-G" flag, as the "-G" flag dumps a list of fields registered
233 by the dissectors, and we must do it before we read the preferences,
234 in case any dissectors register preferences. */
235 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
237 /* Now register the preferences for any non-dissector modules.
238 We must do that before we read the preferences as well. */
239 prefs_register_modules();
241 /* If invoked with the "-G" flag, we dump out a glossary of
242 display filter symbols.
244 We do this here to mirror what happens in the GTK+ version, although
245 it's not necessary here. */
246 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
247 proto_registrar_dump();
251 /* Set the C-language locale to the native environment. */
252 setlocale(LC_ALL, "");
254 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
255 if (gpf_path != NULL) {
256 fprintf(stderr, "Can't open global preferences file \"%s\": %s.\n", pf_path,
257 strerror(gpf_open_errno));
259 if (pf_path != NULL) {
260 fprintf(stderr, "Can't open your preferences file \"%s\": %s.\n", pf_path,
261 strerror(pf_open_errno));
265 /* Load Wpcap, if possible */
269 /* Initialize the capture file struct */
271 cfile.plist_end = NULL;
273 cfile.filename = NULL;
274 cfile.user_saved = FALSE;
275 cfile.is_tempfile = FALSE;
277 cfile.dfilter = NULL;
280 cfile.cfilter = g_strdup("");
283 cfile.save_file = NULL;
284 cfile.save_file_fd = -1;
285 cfile.snap = WTAP_MAX_PACKET_SIZE;
287 col_init(&cfile.cinfo, prefs->num_cols);
289 /* Assemble the compile-time options */
290 comp_info_str = g_string_new("");
292 g_string_append(comp_info_str, "with ");
293 g_string_sprintfa(comp_info_str,
294 #ifdef GLIB_MAJOR_VERSION
295 "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
298 "GLib (version unknown)");
302 g_string_append(comp_info_str, ", with libpcap ");
303 g_string_append(comp_info_str, pcap_version);
305 g_string_append(comp_info_str, ", without libpcap");
309 g_string_append(comp_info_str, ", with libz ");
311 g_string_append(comp_info_str, ZLIB_VERSION);
312 #else /* ZLIB_VERSION */
313 g_string_append(comp_info_str, "(version unknown)");
314 #endif /* ZLIB_VERSION */
315 #else /* HAVE_LIBZ */
316 g_string_append(comp_info_str, ", without libz");
317 #endif /* HAVE_LIBZ */
319 /* Oh, this is pretty */
320 #if defined(HAVE_UCD_SNMP_SNMP_H)
321 g_string_append(comp_info_str, ", with UCD SNMP ");
322 #ifdef HAVE_UCD_SNMP_VERSION_H
323 g_string_append(comp_info_str, VersionInfo);
324 #else /* HAVE_UCD_SNMP_VERSION_H */
325 g_string_append(comp_info_str, "(version unknown)");
326 #endif /* HAVE_UCD_SNMP_VERSION_H */
327 #elif defined(HAVE_SNMP_SNMP_H)
328 g_string_append(comp_info_str, ", with CMU SNMP ");
329 #ifdef HAVE_SNMP_VERSION_H
330 g_string_append(comp_info_str, snmp_Version());
331 #else /* HAVE_SNMP_VERSION_H */
332 g_string_append(comp_info_str, "(version unknown)");
333 #endif /* HAVE_SNMP_VERSION_H */
335 g_string_append(comp_info_str, ", without SNMP");
338 /* Now get our args */
339 while ((opt = getopt(argc, argv, "c:Df:F:hi:lnN:o:pr:R:s:t:vw:Vx")) != EOF) {
341 case 'c': /* Capture xxx packets */
343 packet_count = get_positive_int(optarg, "packet count");
345 capture_option_specified = TRUE;
349 case 'D': /* Print a list of capture devices */
351 if_list = get_interface_list(&err, err_str);
352 if (if_list == NULL) {
355 case CANT_GET_INTERFACE_LIST:
356 fprintf(stderr, "tethereal: Can't get list of interfaces: %s\n",
360 case NO_INTERFACES_FOUND:
361 fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
366 for (if_entry = g_list_first(if_list); if_entry != NULL;
367 if_entry = g_list_next(if_entry))
368 printf("%s\n", (char *)if_entry->data);
369 free_interface_list(if_list);
372 capture_option_specified = TRUE;
378 capture_filter_specified = TRUE;
379 cfile.cfilter = g_strdup(optarg);
381 capture_option_specified = TRUE;
386 out_file_type = wtap_short_string_to_file_type(optarg);
387 if (out_file_type < 0) {
388 fprintf(stderr, "tethereal: \"%s\" is not a valid capture file type\n",
393 case 'h': /* Print help and exit */
397 case 'i': /* Use interface xxx */
399 cfile.iface = g_strdup(optarg);
401 capture_option_specified = TRUE;
405 case 'l': /* "Line-buffer" standard output */
406 /* This isn't line-buffering, strictly speaking, it's just
407 flushing the standard output after the information for
408 each packet is printed; however, that should be good
409 enough for all the purposes to which "-l" is put.
411 See the comment in "wtap_dispatch_cb_print()" for an
412 explanation of why we do that, and why we don't just
413 use "setvbuf()" to make the standard output line-buffered
414 (short version: in Windows, "line-buffered" is the same
415 as "fully-buffered", and the output buffer is only flushed
416 when it fills up). */
417 line_buffered = TRUE;
419 case 'n': /* No name resolution */
420 prefs->name_resolve = PREFS_RESOLV_NONE;
422 case 'N': /* Select what types of addresses/port #s to resolve */
423 if (prefs->name_resolve == PREFS_RESOLV_ALL)
424 prefs->name_resolve = PREFS_RESOLV_NONE;
425 badopt = string_to_name_resolve(optarg, &prefs->name_resolve);
426 if (badopt != '\0') {
427 fprintf(stderr, "tethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
432 case 'o': /* Override preference from command line */
433 switch (prefs_set_pref(optarg)) {
435 case PREFS_SET_SYNTAX_ERR:
436 fprintf(stderr, "tethereal: Invalid -o flag \"%s\"\n", optarg);
440 case PREFS_SET_NO_SUCH_PREF:
441 fprintf(stderr, "tethereal: -o flag \"%s\" specifies unknown preference\n",
447 case 'p': /* Don't capture in promiscuous mode */
451 capture_option_specified = TRUE;
455 case 'r': /* Read capture file xxx */
456 cf_name = g_strdup(optarg);
458 case 'R': /* Read file filter */
461 case 's': /* Set the snapshot (capture) length */
463 cfile.snap = get_positive_int(optarg, "snapshot length");
465 capture_option_specified = TRUE;
469 case 't': /* Time stamp type */
470 if (strcmp(optarg, "r") == 0)
471 timestamp_type = RELATIVE;
472 else if (strcmp(optarg, "a") == 0)
473 timestamp_type = ABSOLUTE;
474 else if (strcmp(optarg, "ad") == 0)
475 timestamp_type = ABSOLUTE_WITH_DATE;
476 else if (strcmp(optarg, "d") == 0)
477 timestamp_type = DELTA;
479 fprintf(stderr, "tethereal: Invalid time stamp type \"%s\"\n",
481 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
482 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
486 case 'v': /* Show version and exit */
487 printf("t%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
490 case 'w': /* Write to capture file xxx */
491 cfile.save_file = g_strdup(optarg);
493 case 'V': /* Verbose */
496 case 'x': /* Print packet data in hex (and ASCII) */
502 /* If no capture filter or read filter has been specified, and there are
503 still command-line arguments, treat them as the tokens of a capture
504 filter (if no "-r" flag was specified) or a read filter (if a "-r"
505 flag was specified. */
507 if (cf_name != NULL) {
508 if (rfilter != NULL) {
510 "tethereal: Read filters were specified both with \"-R\" and with additional command-line arguments\n");
513 rfilter = get_args_as_string(argc, argv, optind);
516 if (capture_filter_specified) {
518 "tethereal: Capture filters were specified both with \"-f\" and with additional command-line arguments\n");
521 cfile.cfilter = get_args_as_string(argc, argv, optind);
523 capture_option_specified = TRUE;
529 /* Start windows sockets */
530 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
533 /* Notify all registered modules that have had any of their preferences
534 changed either from one of the preferences file or from the command
535 line that its preferences have changed. */
539 if (capture_option_specified)
540 fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
545 /* Build the column format array */
546 for (i = 0; i < cfile.cinfo.num_cols; i++) {
547 cfile.cinfo.col_fmt[i] = get_column_format(i);
548 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
549 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
551 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
552 cfile.cinfo.col_data[i] = NULL;
553 if (cfile.cinfo.col_fmt[i] == COL_INFO)
554 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
556 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
560 cfile.snap = WTAP_MAX_PACKET_SIZE;
561 else if (cfile.snap < MIN_PACKET_SIZE)
562 cfile.snap = MIN_PACKET_SIZE;
564 if (rfilter != NULL) {
565 if (!dfilter_compile(rfilter, &rfcode)) {
566 fprintf(stderr, "tethereal: %s\n", dfilter_error_msg);
571 cfile.rfcode = rfcode;
573 err = open_cap_file(cf_name, FALSE, &cfile);
578 err = load_cap_file(&cfile, out_file_type);
585 /* No capture file specified, so we're supposed to do a live capture;
586 do we have support for live captures? */
591 fprintf(stderr, "tethereal: Could not load wpcap.dll.\n");
596 /* Yes; did the user specify an interface to use? */
597 if (cfile.iface == NULL) {
598 /* No - pick the first one from the list of interfaces. */
599 if_list = get_interface_list(&err, err_str);
600 if (if_list == NULL) {
603 case CANT_GET_INTERFACE_LIST:
604 fprintf(stderr, "tethereal: Can't get list of interfaces: %s\n",
608 case NO_INTERFACES_FOUND:
609 fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
614 cfile.iface = g_strdup(if_list->data); /* first interface */
615 free_interface_list(if_list);
617 capture(packet_count, out_file_type);
620 fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
631 /* Do the low-level work of a capture.
632 Returns TRUE if it succeeds, FALSE otherwise. */
634 capture(int packet_count, int out_file_type)
636 gchar err_str[PCAP_ERRBUF_SIZE];
637 bpf_u_int32 netnum, netmask;
638 struct bpf_program fcode;
639 void (*oldhandler)(int);
643 static const char ppamsg[] = "can't find PPA for ";
646 struct pcap_stat stats;
648 /* Initialize the table of conversations. */
649 epan_conversation_init();
651 /* Initialize protocol-specific variables */
652 init_all_protocols();
654 ld.linktype = WTAP_ENCAP_UNKNOWN;
657 /* Open the network interface to capture from it. */
658 ld.pch = pcap_open_live(cfile.iface, cfile.snap, promisc_mode, 1000, err_str);
660 if (ld.pch == NULL) {
661 /* Well, we couldn't start the capture. */
663 /* On Win32 OSes, the capture devices are probably available to all
664 users; don't warn about permissions problems.
666 Do, however, warn that Token Ring and PPP devices aren't supported. */
667 snprintf(errmsg, sizeof errmsg,
668 "The capture session could not be initiated (%s).\n"
669 "Please check that you have the proper interface specified.\n"
671 "Note that the driver Tethereal uses for packet capture on Windows\n"
672 "doesn't support capturing on Token Ring interfaces, and doesn't\n"
673 "support capturing on PPP/WAN interfaces in Windows NT/2000.\n",
676 /* If we got a "can't find PPA for XXX" message, warn the user (who
677 is running Ethereal on HP-UX) that they don't have a version
678 of libpcap that properly handles HP-UX (libpcap 0.6.x and later
679 versions, which properly handle HP-UX, say "can't find /dev/dlpi
680 PPA for XXX" rather than "can't find PPA for XXX"). */
681 if (strncmp(err_str, ppamsg, sizeof ppamsg - 1) == 0)
684 "You are running Tethereal with a version of the libpcap library\n"
685 "that doesn't handle HP-UX network devices well; this means that\n"
686 "Tethereal may not be able to capture packets.\n"
688 "To fix this, you should install libpcap 0.6.2, or a later version\n"
689 "of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n"
690 "packaged binary form from the Software Porting And Archive Centre\n"
691 "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
692 "at the URL lists a number of mirror sites.";
695 snprintf(errmsg, sizeof errmsg,
696 "The capture session could not be initiated (%s).\n"
697 "Please check to make sure you have sufficient permissions, and that\n"
698 "you have the proper interface specified.%s", err_str, libpcap_warn);
704 /* A capture filter was specified; set it up. */
705 if (pcap_lookupnet (cfile.iface, &netnum, &netmask, err_str) < 0) {
707 * Well, we can't get the netmask for this interface; it's used
708 * only for filters that check for broadcast IP addresses, so
709 * we just warn the user, and punt and use 0.
712 "Warning: Couldn't obtain netmask info (%s)\n.", err_str);
715 if (pcap_compile(ld.pch, &fcode, cfile.cfilter, 1, netmask) < 0) {
716 snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
717 pcap_geterr(ld.pch));
720 if (pcap_setfilter(ld.pch, &fcode) < 0) {
721 snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
722 pcap_geterr(ld.pch));
727 ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(ld.pch));
728 if (cfile.save_file != NULL) {
729 /* Set up to write to the capture file. */
730 if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
731 strcpy(errmsg, "The network you're capturing from is of a type"
732 " that Tethereal doesn't support.");
735 ld.pdh = wtap_dump_open(cfile.save_file, out_file_type,
736 ld.linktype, pcap_snapshot(ld.pch), &err);
738 if (ld.pdh == NULL) {
739 snprintf(errmsg, sizeof errmsg, file_open_error_message(errno, TRUE),
745 /* Catch SIGINT and SIGTERM and, if we get either of them, clean up
747 XXX - deal with signal semantics on various platforms. Or just
748 use "sigaction()" and be done with it? */
749 signal(SIGTERM, capture_cleanup);
750 signal(SIGINT, capture_cleanup);
752 if ((oldhandler = signal(SIGHUP, capture_cleanup)) != SIG_DFL)
753 signal(SIGHUP, oldhandler);
756 /* Let the user know what interface was chosen. */
757 fprintf(stderr, "Capturing on %s\n", cfile.iface);
760 inpkts = pcap_loop(ld.pch, packet_count, capture_pcap_cb, (u_char *) &ld);
762 if (cfile.save_file != NULL) {
763 /* We're saving to a file, which means we're printing packet counts
764 to the standard output. Send a newline so that we move to the
765 line after the packet count. */
766 fprintf(stderr, "\n");
769 /* If we got an error while capturing, report it. */
771 fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
772 pcap_geterr(ld.pch));
775 /* Get the capture statistics, and, if any packets were dropped, report
777 if (pcap_stats(ld.pch, &stats) >= 0) {
778 if (stats.ps_drop != 0) {
779 fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
782 fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
783 pcap_geterr(ld.pch));
790 g_free(cfile.save_file);
791 cfile.save_file = NULL;
792 fprintf(stderr, "tethereal: %s\n", errmsg);
800 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
803 struct wtap_pkthdr whdr;
804 loop_data *ld = (loop_data *) user;
807 whdr.ts.tv_sec = phdr->ts.tv_sec;
808 whdr.ts.tv_usec = phdr->ts.tv_usec;
809 whdr.caplen = phdr->caplen;
810 whdr.len = phdr->len;
811 whdr.pkt_encap = ld->linktype;
816 wtap_dispatch_cb_write((u_char *)&args, &whdr, 0, NULL, pd);
817 fprintf(stderr, "\r%u ", cfile.count);
820 wtap_dispatch_cb_print((u_char *)&args, &whdr, 0, NULL, pd);
825 capture_cleanup(int signum)
829 fprintf(stderr, "\n");
831 if (ld.pdh != NULL) {
832 if (!wtap_dump_close(ld.pdh, &err)) {
833 show_capture_file_io_error(cfile.save_file, err, TRUE);
839 #endif /* HAVE_LIBPCAP */
842 load_cap_file(capture_file *cf, int out_file_type)
850 linktype = wtap_file_encap(cf->wth);
851 if (cf->save_file != NULL) {
852 /* Set up to write to the capture file. */
853 pdh = wtap_dump_open(cf->save_file, out_file_type,
854 linktype, wtap_snapshot_length(cf->wth), &err);
857 /* We couldn't set up to write to the capture file. */
860 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
862 "tethereal: Capture files can't be written in that format.\n");
865 case WTAP_ERR_UNSUPPORTED_ENCAP:
866 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
868 "tethereal: The capture file being read cannot be written in that format.\n");
871 case WTAP_ERR_CANT_OPEN:
873 "tethereal: The file \"%s\" couldn't be created for some unknown reason.\n",
877 case WTAP_ERR_SHORT_WRITE:
879 "tethereal: A full header couldn't be written to the file \"%s\".\n",
886 "tethereal: The file \"%s\" could not be opened: Error %d.\n",
890 "tethereal: The file \"%s\" could not be opened: %s\n.",
891 cf->save_file, strerror(err));
899 success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_write, (u_char *) &args,
904 success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_print, (u_char *) &args,
908 /* Print up a message box noting that the read failed somewhere along
912 case WTAP_ERR_UNSUPPORTED_ENCAP:
914 "tethereal: \"%s\" is a capture file is for a network type that Tethereal doesn't support.\n",
918 case WTAP_ERR_CANT_READ:
920 "tethereal: An attempt to read from \"%s\" failed for some unknown reason.\n",
924 case WTAP_ERR_SHORT_READ:
926 "tethereal: \"%s\" appears to have been cut short in the middle of a packet.\n",
930 case WTAP_ERR_BAD_RECORD:
932 "tethereal: \"%s\" appears to be damaged or corrupt.\n",
938 "tethereal: An error occurred while reading \"%s\": %s.\n",
939 cf->filename, wtap_strerror(err));
952 fill_in_fdata(frame_data *fdata, capture_file *cf,
953 const struct wtap_pkthdr *phdr,
954 const union wtap_pseudo_header *pseudo_header, int offset)
961 fdata->data_src = NULL;
962 fdata->num = cf->count;
963 fdata->pkt_len = phdr->len;
964 fdata->cap_len = phdr->caplen;
965 fdata->file_off = offset;
967 fdata->lnk_t = phdr->pkt_encap;
968 fdata->abs_secs = phdr->ts.tv_sec;
969 fdata->abs_usecs = phdr->ts.tv_usec;
970 fdata->flags.passed_dfilter = 0;
971 fdata->flags.encoding = CHAR_ASCII;
972 fdata->flags.visited = 0;
973 fdata->flags.marked = 0;
975 /* If we don't have the time stamp of the first packet in the
976 capture, it's because this is the first packet. Save the time
977 stamp of this packet as the time stamp of the first packet. */
978 if (!firstsec && !firstusec) {
979 firstsec = fdata->abs_secs;
980 firstusec = fdata->abs_usecs;
983 /* If we don't have the time stamp of the previous displayed packet,
984 it's because this is the first displayed packet. Save the time
985 stamp of this packet as the time stamp of the previous displayed
987 if (!prevsec && !prevusec) {
988 prevsec = fdata->abs_secs;
989 prevusec = fdata->abs_usecs;
992 /* Get the time elapsed between the first packet and this packet. */
993 compute_timestamp_diff(&fdata->rel_secs, &fdata->rel_usecs,
994 fdata->abs_secs, fdata->abs_usecs, firstsec, firstusec);
996 /* If it's greater than the current elapsed time, set the elapsed time
997 to it (we check for "greater than" so as not to be confused by
998 time moving backwards). */
999 if (cf->esec < fdata->rel_secs
1000 || (cf->esec == fdata->rel_secs && cf->eusec < fdata->rel_usecs)) {
1001 cf->esec = fdata->rel_secs;
1002 cf->eusec = fdata->rel_usecs;
1005 /* Get the time elapsed between the previous displayed packet and
1007 compute_timestamp_diff(&fdata->del_secs, &fdata->del_usecs,
1008 fdata->abs_secs, fdata->abs_usecs, prevsec, prevusec);
1009 prevsec = fdata->abs_secs;
1010 prevusec = fdata->abs_usecs;
1012 fdata->cinfo = &cf->cinfo;
1013 for (i = 0; i < fdata->cinfo->num_cols; i++) {
1014 fdata->cinfo->col_buf[i][0] = '\0';
1015 fdata->cinfo->col_data[i] = fdata->cinfo->col_buf[i];
1019 /* Free up all data attached to a "frame_data" structure. */
1021 clear_fdata(frame_data *fdata)
1024 g_slist_free(fdata->pfd);
1025 if (fdata->data_src)
1026 g_slist_free(fdata->data_src);
1030 wtap_dispatch_cb_write(u_char *user, const struct wtap_pkthdr *phdr, int offset,
1031 union wtap_pseudo_header *pseudo_header, const u_char *buf)
1033 cb_args_t *args = (cb_args_t *) user;
1034 capture_file *cf = args->cf;
1035 wtap_dumper *pdh = args->pdh;
1037 proto_tree *protocol_tree;
1040 epan_dissect_t *edt;
1044 fill_in_fdata(&fdata, cf, phdr, pseudo_header, offset);
1045 protocol_tree = proto_tree_create_root();
1046 edt = epan_dissect_new(pseudo_header, buf, &fdata, protocol_tree);
1047 passed = dfilter_apply_edt(cf->rfcode, edt);
1049 protocol_tree = NULL;
1054 if (!wtap_dump(pdh, phdr, pseudo_header, buf, &err)) {
1056 if (ld.pch != NULL) {
1057 /* We're capturing packets, so we're printing a count of packets
1058 captured; move to the line after the count. */
1059 fprintf(stderr, "\n");
1062 show_capture_file_io_error(cf->save_file, err, FALSE);
1067 wtap_dump_close(pdh, &err);
1071 if (protocol_tree != NULL)
1072 proto_tree_free(protocol_tree);
1074 epan_dissect_free(edt);
1076 clear_fdata(&fdata);
1080 show_capture_file_io_error(const char *fname, int err, gboolean is_close)
1086 "tethereal: Not all the packets could be written to \"%s\" because there is "
1087 "no space left on the file system.\n",
1094 "tethereal: Not all the packets could be written to \"%s\" because you are "
1095 "too close to, or over your disk quota.\n",
1100 case WTAP_ERR_CANT_CLOSE:
1102 "tethereal: \"%s\" couldn't be closed for some unknown reason.\n",
1106 case WTAP_ERR_SHORT_WRITE:
1108 "tethereal: Not all the packets could be written to \"%s\".\n",
1115 "tethereal: \"%s\" could not be closed: %s.\n",
1116 fname, wtap_strerror(err));
1119 "tethereal: An error occurred while writing to \"%s\": %s.\n",
1120 fname, wtap_strerror(err));
1127 wtap_dispatch_cb_print(u_char *user, const struct wtap_pkthdr *phdr, int offset,
1128 union wtap_pseudo_header *pseudo_header, const u_char *buf)
1130 cb_args_t *args = (cb_args_t *) user;
1131 capture_file *cf = args->cf;
1133 proto_tree *protocol_tree;
1135 print_args_t print_args;
1136 epan_dissect_t *edt;
1141 /* The protocol tree will be "visible", i.e., printed, only if we're
1142 not printing a summary. */
1143 proto_tree_is_visible = verbose;
1145 fill_in_fdata(&fdata, cf, phdr, pseudo_header, offset);
1148 if (cf->rfcode || verbose)
1149 protocol_tree = proto_tree_create_root();
1151 protocol_tree = NULL;
1152 edt = epan_dissect_new(pseudo_header, buf, &fdata, protocol_tree);
1154 passed = dfilter_apply_edt(cf->rfcode, edt);
1156 /* The packet passed the read filter. */
1158 /* Print the information in the protocol tree. */
1159 print_args.to_file = TRUE;
1160 print_args.format = PR_FMT_TEXT;
1161 print_args.print_summary = FALSE;
1162 print_args.print_hex = print_hex;
1163 print_args.expand_all = TRUE;
1164 proto_tree_print(FALSE, &print_args, (GNode *)protocol_tree,
1165 buf, &fdata, stdout);
1167 /* "print_hex_data()" will put out a leading blank line, as well
1168 as a trailing one; print one here, to separate the packets,
1169 only if "print_hex_data()" won't be called. */
1173 /* Just fill in the columns. */
1174 fill_in_columns(&fdata);
1176 /* Now print them. */
1177 for (i = 0; i < cf->cinfo.num_cols; i++) {
1178 switch (cf->cinfo.col_fmt[i]) {
1181 * Don't print this if we're doing a live capture from a network
1182 * interface - if we're doing a live capture, you won't be
1183 * able to look at the capture in the future (it's not being
1184 * saved anywhere), so the frame numbers are unlikely to be
1187 * (XXX - it might be nice to be able to save and print at
1188 * the same time, sort of like an "Update list of packets
1189 * in real time" capture in Ethereal.)
1191 if (cf->iface != NULL)
1193 printf("%3s", cf->cinfo.col_data[i]);
1199 case COL_ABS_DATE_TIME: /* XXX - wider */
1200 printf("%10s", cf->cinfo.col_data[i]);
1206 case COL_DEF_DL_SRC:
1207 case COL_RES_DL_SRC:
1208 case COL_UNRES_DL_SRC:
1209 case COL_DEF_NET_SRC:
1210 case COL_RES_NET_SRC:
1211 case COL_UNRES_NET_SRC:
1212 printf("%12s", cf->cinfo.col_data[i]);
1218 case COL_DEF_DL_DST:
1219 case COL_RES_DL_DST:
1220 case COL_UNRES_DL_DST:
1221 case COL_DEF_NET_DST:
1222 case COL_RES_NET_DST:
1223 case COL_UNRES_NET_DST:
1224 printf("%-12s", cf->cinfo.col_data[i]);
1228 printf("%s", cf->cinfo.col_data[i]);
1231 if (i != cf->cinfo.num_cols - 1) {
1233 * This isn't the last column, so we need to print a
1234 * separator between this column and the next.
1236 * If we printed a network source and are printing a
1237 * network destination of the same type next, separate
1238 * them with "->"; if we printed a network destination
1239 * and are printing a network source of the same type
1240 * next, separate them with "<-"; otherwise separate them
1243 switch (cf->cinfo.col_fmt[i]) {
1248 switch (cf->cinfo.col_fmt[i + 1]) {
1262 case COL_DEF_DL_SRC:
1263 case COL_RES_DL_SRC:
1264 case COL_UNRES_DL_SRC:
1265 switch (cf->cinfo.col_fmt[i + 1]) {
1267 case COL_DEF_DL_DST:
1268 case COL_RES_DL_DST:
1269 case COL_UNRES_DL_DST:
1279 case COL_DEF_NET_SRC:
1280 case COL_RES_NET_SRC:
1281 case COL_UNRES_NET_SRC:
1282 switch (cf->cinfo.col_fmt[i + 1]) {
1284 case COL_DEF_NET_DST:
1285 case COL_RES_NET_DST:
1286 case COL_UNRES_NET_DST:
1299 switch (cf->cinfo.col_fmt[i + 1]) {
1313 case COL_DEF_DL_DST:
1314 case COL_RES_DL_DST:
1315 case COL_UNRES_DL_DST:
1316 switch (cf->cinfo.col_fmt[i + 1]) {
1318 case COL_DEF_DL_SRC:
1319 case COL_RES_DL_SRC:
1320 case COL_UNRES_DL_SRC:
1330 case COL_DEF_NET_DST:
1331 case COL_RES_NET_DST:
1332 case COL_UNRES_NET_DST:
1333 switch (cf->cinfo.col_fmt[i + 1]) {
1335 case COL_DEF_NET_SRC:
1336 case COL_RES_NET_SRC:
1337 case COL_UNRES_NET_SRC:
1356 print_hex_data(stdout, print_args.format, &fdata);
1362 /* The ANSI C standard does not appear to *require* that a line-buffered
1363 stream be flushed to the host environment whenever a newline is
1364 written, it just says that, on such a stream, characters "are
1365 intended to be transmitted to or from the host environment as a
1366 block when a new-line character is encountered".
1368 The Visual C++ 6.0 C implementation doesn't do what is intended;
1369 even if you set a stream to be line-buffered, it still doesn't
1370 flush the buffer at the end of every line.
1372 So, if the "-l" flag was specified, we flush the standard output
1373 at the end of a packet. This will do the right thing if we're
1374 printing packet summary lines, and, as we print the entire protocol
1375 tree for a single packet without waiting for anything to happen,
1376 it should be as good as line-buffered mode if we're printing
1377 protocol trees. (The whole reason for the "-l" flag in either
1378 tcpdump or Tethereal is to allow the output of a live capture to
1379 be piped to a program or script and to have that script see the
1380 information for the packet as soon as it's printed, rather than
1381 having to wait until a standard I/O buffer fills up. */
1384 if (protocol_tree != NULL)
1385 proto_tree_free(protocol_tree);
1387 epan_dissect_free(edt);
1389 clear_fdata(&fdata);
1391 proto_tree_is_visible = FALSE;
1395 file_open_error_message(int err, gboolean for_writing)
1398 static char errmsg_errno[1024+1];
1402 case WTAP_ERR_NOT_REGULAR_FILE:
1403 errmsg = "The file \"%s\" is a \"special file\" or socket or other non-regular file.";
1406 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
1407 case WTAP_ERR_UNSUPPORTED:
1408 /* Seen only when opening a capture file for reading. */
1409 errmsg = "The file \"%s\" is not a capture file in a format Tethereal understands.";
1412 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
1413 /* Seen only when opening a capture file for writing. */
1414 errmsg = "Tethereal does not support writing capture files in that format.";
1417 case WTAP_ERR_UNSUPPORTED_ENCAP:
1418 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
1420 errmsg = "Tethereal cannot save this capture in that format.";
1422 errmsg = "The file \"%s\" is a capture for a network type that Tethereal doesn't support.";
1425 case WTAP_ERR_BAD_RECORD:
1426 errmsg = "The file \"%s\" appears to be damaged or corrupt.";
1429 case WTAP_ERR_CANT_OPEN:
1431 errmsg = "The file \"%s\" could not be created for some unknown reason.";
1433 errmsg = "The file \"%s\" could not be opened for some unknown reason.";
1436 case WTAP_ERR_SHORT_READ:
1437 errmsg = "The file \"%s\" appears to have been cut short"
1438 " in the middle of a packet.";
1441 case WTAP_ERR_SHORT_WRITE:
1442 errmsg = "A full header couldn't be written to the file \"%s\".";
1447 errmsg = "The path to the file \"%s\" does not exist.";
1449 errmsg = "The file \"%s\" does not exist.";
1454 errmsg = "You do not have permission to create or write to the file \"%s\".";
1456 errmsg = "You do not have permission to read the file \"%s\".";
1460 errmsg = "\"%s\" is a directory (folder), not a file.";
1464 snprintf(errmsg_errno, sizeof(errmsg_errno),
1465 "The file \"%%s\" could not be opened: %s.",
1466 wtap_strerror(err));
1467 errmsg = errmsg_errno;
1474 open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
1480 struct stat cf_stat;
1481 char err_msg[2048+1];
1483 wth = wtap_open_offline(fname, &err, FALSE);
1487 /* Find the size of the file. */
1488 fh = wtap_file(wth);
1490 if (fstat(fd, &cf_stat) < 0) {
1496 /* The open succeeded. Fill in the information for this file. */
1498 /* Initialize the table of conversations. */
1499 epan_conversation_init();
1501 /* Initialize protocol-specific variables */
1502 init_all_protocols();
1506 cf->f_len = cf_stat.st_size;
1508 /* Set the file name because we need it to set the follow stream filter.
1509 XXX - is that still true? We need it for other reasons, though,
1511 cf->filename = g_strdup(fname);
1513 /* Indicate whether it's a permanent or temporary file. */
1514 cf->is_tempfile = is_tempfile;
1516 /* If it's a temporary capture buffer file, mark it as not saved. */
1517 cf->user_saved = !is_tempfile;
1519 cf->cd_t = wtap_file_type(cf->wth);
1521 cf->drops_known = FALSE;
1525 cf->snap = wtap_snapshot_length(cf->wth);
1526 cf->progbar_quantum = 0;
1527 cf->progbar_nextstep = 0;
1528 firstsec = 0, firstusec = 0;
1529 prevsec = 0, prevusec = 0;
1534 snprintf(err_msg, sizeof err_msg, file_open_error_message(err, FALSE), fname);
1535 fprintf(stderr, "tethereal: %s\n", err_msg);