5 * Ethereal - Network traffic analyzer
6 * By Gerald Combs <gerald@ethereal.com>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 #ifdef _WIN32 /* Needed for console I/O */
45 #include "simple_dialog.h"
46 #include "ringbuffer.h"
48 #include "clopts_common.h"
49 #include "cmdarg_err.h"
50 #include "version_info.h"
53 #include "pcap-util.h"
58 #include "capture-wpcap.h"
59 #include "capture_wpcap_packet.h"
63 #include "file_util.h"
67 GString *comp_info_str, *runtime_info_str;
68 gchar *ethereal_path = NULL;
71 static gboolean has_console = TRUE; /* TRUE if app has console */
72 static void create_console(void);
73 static void destroy_console(void);
76 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
77 const char *message, gpointer user_data _U_);
79 capture_options global_capture_opts;
80 capture_options *capture_opts = &global_capture_opts;
85 print_usage(gboolean print_ver) {
95 fprintf(output, "This is "PACKAGE " " VERSION "%s"
96 "\n (C) 1998-2005 Gerald Combs <gerald@ethereal.com>"
98 svnversion, comp_info_str->str, runtime_info_str->str);
102 fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n", PACKAGE);
103 fprintf(output, "\t[ -b <capture ring buffer option> ] ...\n");
105 fprintf(output, "\t[ -B <capture buffer size> ]\n");
107 fprintf(output, "\t[ -c <capture packet count> ] [ -f <capture filter> ]\n");
108 fprintf(output, "\t[ -g <packet number> ] [ -i <capture interface> ] [ -m <font> ]\n");
109 fprintf(output, "\t[ -N <name resolving flags> ] [ -o <preference/recent setting> ] ...\n");
110 fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ] [ -s <capture snaplen> ]\n");
111 fprintf(output, "\t[ -t <time stamp format> ] [ -w <savefile> ] [ -y <capture link type> ]\n");
112 fprintf(output, "\t[ -z <statistics> ] [ <infile> ]\n");
118 printf(PACKAGE " " VERSION "%s\n\n%s\n\n%s\n",
119 svnversion, comp_info_str->str, runtime_info_str->str);
123 * Report an error in command-line arguments.
124 * Creates a console on Windows.
125 * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
126 * terminal isn't the standard error?
129 cmdarg_err(const char *fmt, ...)
137 fprintf(stderr, "dumpcap: ");
138 vfprintf(stderr, fmt, ap);
139 fprintf(stderr, "\n");
144 * Report additional information for an error in command-line arguments.
145 * Creates a console on Windows.
146 * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
147 * terminal isn't the standard error?
150 cmdarg_err_cont(const char *fmt, ...)
158 vfprintf(stderr, fmt, ap);
159 fprintf(stderr, "\n");
165 BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
167 /*printf("Event: %u", dwCtrlType);*/
174 /* And now our feature presentation... [ fade to music ] */
176 main(int argc, char *argv[])
180 gboolean arg_error = FALSE;
187 gboolean start_capture = TRUE;
190 GList *lt_list, *lt_entry;
191 data_link_info_t *data_link_info;
192 gchar err_str[PCAP_ERRBUF_SIZE];
193 gchar *cant_get_if_list_errstr;
194 gboolean stats_known;
195 struct pcap_stat stats;
196 GLogLevelFlags log_flags;
197 gboolean list_link_layer_types = FALSE;
199 #define OPTSTRING_INIT "a:b:c:f:Hhi:kLpQSs:W:w:vy:"
202 #define OPTSTRING_WIN32 "B:Z:"
204 #define OPTSTRING_WIN32 ""
207 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
208 OPTSTRING_INIT OPTSTRING_WIN32;
210 /*** create the compile and runtime version strings ***/
212 /* Load wpcap if possible. Do this before collecting the run-time version information */
215 /* ... and also load the packet.dll from wpcap */
218 /* Start windows sockets */
219 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
223 SetConsoleCtrlHandler(&ConsoleCtrlHandlerRoutine, TRUE);
226 /* Assemble the compile-time version information string */
227 comp_info_str = g_string_new("Compiled ");
228 g_string_append(comp_info_str, "with ");
229 get_compiled_version_info(comp_info_str);
231 /* Assemble the run-time version information string */
232 runtime_info_str = g_string_new("Running ");
233 get_runtime_version_info(runtime_info_str);
235 ethereal_path = argv[0];
237 /* Arrange that if we have no console window, and a GLib message logging
238 routine is called to log a message, we pop up a console window.
240 We do that by inserting our own handler for all messages logged
241 to the default domain; that handler pops up a console if necessary,
242 and then calls the default handler. */
244 /* We might want to have component specific log levels later ... */
246 /* the default_log_handler will use stdout, which makes trouble with the */
247 /* capture child, as it uses stdout for it's sync_pipe */
248 /* so do the filtering in the console_log_handler and not here */
251 G_LOG_LEVEL_CRITICAL|
256 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
258 g_log_set_handler(NULL,
260 console_log_handler, NULL /* user_data */);
261 g_log_set_handler(LOG_DOMAIN_MAIN,
263 console_log_handler, NULL /* user_data */);
264 g_log_set_handler(LOG_DOMAIN_CAPTURE,
266 console_log_handler, NULL /* user_data */);
267 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
269 console_log_handler, NULL /* user_data */);
271 /* Set the initial values in the capture_opts. This might be overwritten
272 by preference settings and then again by the command line parameters. */
273 capture_opts_init(capture_opts, NULL);
275 capture_opts->snaplen = MIN_PACKET_SIZE;
276 capture_opts->has_ring_num_files = TRUE;
278 /* Now get our args */
279 while ((opt = getopt(argc, argv, optstring)) != -1) {
281 case 'h': /* Print help and exit */
285 case 'v': /* Show version and exit */
289 /*** capture option specific ***/
290 case 'a': /* autostop criteria */
291 case 'b': /* Ringbuffer option */
292 case 'c': /* Capture xxx packets */
293 case 'f': /* capture filter */
294 case 'k': /* Start capture immediately */
295 case 'H': /* Hide capture info dialog box */
296 case 'i': /* Use interface xxx */
297 case 'p': /* Don't capture in promiscuous mode */
298 case 'Q': /* Quit after capture (just capture to file) */
299 case 's': /* Set the snapshot (capture) length */
300 case 'S': /* "Sync" mode: used for following file ala tail -f */
301 case 'w': /* Write to capture file xxx */
302 case 'y': /* Set the pcap data link type */
304 case 'B': /* Buffer size */
305 /* Hidden option supporting Sync mode */
306 case 'Z': /* Write to pipe FD XXX */
308 capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
310 /* This is a hidden option supporting Sync mode, so we don't set
311 * the error flags for the user in the non-libpcap case.
313 case 'W': /* Write to capture file FD xxx */
314 capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
317 /*** all non capture option specific ***/
318 case 'L': /* Print list of link-layer types and exit */
319 list_link_layer_types = TRUE;
322 case '?': /* Bad flag - print usage message */
330 /* user speficied file name as regular command-line argument */
331 /* XXX - use it as the capture file name (or somthing else)? */
340 * Extra command line arguments were specified; complain.
342 cmdarg_err("Invalid argument: %s", argv[0]);
351 if (list_link_layer_types) {
352 /* We're supposed to list the link-layer types for an interface;
353 did the user also specify a capture file to be read? */
354 /* No - did they specify a ring buffer option? */
355 if (capture_opts->multi_files_on) {
356 cmdarg_err("Ring buffer requested, but a capture isn't being done.");
360 /* No - was the ring buffer option specified and, if so, does it make
362 if (capture_opts->multi_files_on) {
363 /* Ring buffer works only under certain conditions:
364 a) ring buffer does not work with temporary files;
365 b) real_time_mode and multi_files_on are mutually exclusive -
366 real_time_mode takes precedence;
367 c) it makes no sense to enable the ring buffer if the maximum
368 file size is set to "infinite". */
369 if (capture_opts->save_file == NULL) {
370 cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
371 capture_opts->multi_files_on = FALSE;
373 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
374 cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
375 /* XXX - this must be redesigned as the conditions changed */
376 /* capture_opts->multi_files_on = FALSE;*/
381 /* Did the user specify an interface to use? */
382 if (capture_opts->iface == NULL) {
383 /* No - pick the first one from the list of interfaces. */
384 if_list = get_interface_list(&err, err_str);
385 if (if_list == NULL) {
388 case CANT_GET_INTERFACE_LIST:
389 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
390 cmdarg_err("%s", cant_get_if_list_errstr);
391 g_free(cant_get_if_list_errstr);
394 case NO_INTERFACES_FOUND:
395 cmdarg_err("There are no interfaces on which a capture can be done");
400 if_info = if_list->data; /* first interface */
401 capture_opts->iface = g_strdup(if_info->name);
402 free_interface_list(if_list);
405 if (list_link_layer_types) {
406 /* Get the list of link-layer types for the capture device. */
407 lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
408 if (lt_list == NULL) {
409 if (err_str[0] != '\0') {
410 cmdarg_err("The list of data link types for the capture device could not be obtained (%s)."
411 "Please check to make sure you have sufficient permissions, and that\n"
412 "you have the proper interface or pipe specified.\n", err_str);
414 cmdarg_err("The capture device has no data link types.");
417 g_warning("Data link types (use option -y to set):");
418 for (lt_entry = lt_list; lt_entry != NULL;
419 lt_entry = g_list_next(lt_entry)) {
420 data_link_info = lt_entry->data;
421 g_warning(" %s", data_link_info->name);
422 if (data_link_info->description != NULL)
423 g_warning(" (%s)", data_link_info->description);
425 g_warning(" (not supported)");
428 free_pcap_linktype_list(lt_list);
432 if (capture_opts->has_snaplen) {
433 if (capture_opts->snaplen < 1)
434 capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
435 else if (capture_opts->snaplen < MIN_PACKET_SIZE)
436 capture_opts->snaplen = MIN_PACKET_SIZE;
439 /* Check the value range of the ringbuffer_num_files parameter */
440 if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
441 capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
442 #if RINGBUFFER_MIN_NUM_FILES > 0
443 else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
444 capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
447 /* Now start the capture.
448 After the capture is done; there's nothing more for us to do. */
450 /* XXX - hand these stats to the parent process */
451 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
460 /* Shutdown windows sockets */
471 /* We build this as a GUI subsystem application on Win32, so
472 "WinMain()", not "main()", gets called.
474 Hack shamelessly stolen from the Win32 port of the GIMP. */
476 #define _stdcall __attribute__((stdcall))
480 WinMain (struct HINSTANCE__ *hInstance,
481 struct HINSTANCE__ *hPrevInstance,
486 return main (__argc, __argv);
490 * If this application has no console window to which its standard output
491 * would go, create one.
497 /* We have no console to which to print the version string, so
498 create one and make it the standard input, output, and error. */
500 return; /* couldn't create console */
501 eth_freopen("CONIN$", "r", stdin);
502 eth_freopen("CONOUT$", "w", stdout);
503 eth_freopen("CONOUT$", "w", stderr);
505 /* Well, we have a console now. */
508 /* Now register "destroy_console()" as a routine to be called just
509 before the application exits, so that we can destroy the console
510 after the user has typed a key (so that the console doesn't just
511 disappear out from under them, giving the user no chance to see
512 the message(s) we put in there). */
513 atexit(destroy_console);
515 SetConsoleTitle("Ethereal Capture Child Debug Console");
520 destroy_console(void)
523 printf("\n\nPress any key to exit\n");
531 /* This routine should not be necessary, at least as I read the GLib
532 source code, as it looks as if GLib is, on Win32, *supposed* to
533 create a console window into which to display its output.
535 That doesn't happen, however. I suspect there's something completely
536 broken about that code in GLib-for-Win32, and that it may be related
537 to the breakage that forces us to just call "printf()" on the message
538 rather than passing the message on to "g_log_default_handler()"
539 (which is the routine that does the aforementioned non-functional
540 console window creation). */
542 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
543 const char *message, gpointer user_data _U_)
550 /* ignore log message, if log_level isn't interesting */
551 if( !(log_level & G_LOG_LEVEL_MASK & ~G_LOG_LEVEL_DEBUG /*prefs.console_log_level*/)) {
555 /* create a "timestamp" */
557 today = localtime(&curr);
560 /* if (prefs.gui_console_open != console_open_never) {*/
564 /* For some unknown reason, the above doesn't appear to actually cause
565 anything to be sent to the standard output, so we'll just splat the
566 message out directly, just to make sure it gets out. */
568 switch(log_level & G_LOG_LEVEL_MASK) {
569 case G_LOG_LEVEL_ERROR:
572 case G_LOG_LEVEL_CRITICAL:
575 case G_LOG_LEVEL_WARNING:
578 case G_LOG_LEVEL_MESSAGE:
581 case G_LOG_LEVEL_INFO:
584 case G_LOG_LEVEL_DEBUG:
588 fprintf(stderr, "unknown log_level %u\n", log_level);
590 g_assert_not_reached();
593 /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
594 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
595 today->tm_hour, today->tm_min, today->tm_sec,
596 log_domain != NULL ? log_domain : "",
600 g_log_default_handler(log_domain, log_level, message, user_data);
606 /* Size of buffer to hold decimal representation of
607 signed/unsigned 64-bit int */
608 #define SP_DECISIZE 20
611 * Indications sent out on the sync pipe.
613 #define SP_FILE 'F' /* the name of the recently opened file */
614 #define SP_ERROR_MSG 'E' /* error message */
615 #define SP_PACKET_COUNT 'P' /* count of packets captured since last message */
616 #define SP_DROPS 'D' /* count of packets dropped in capture */
617 #define SP_QUIT 'Q' /* capture quit message (from parent to child) */
620 pipe_write_block(int pipe, char indicator, int len, const char *msg)
625 sync_pipe_packet_count_to_parent(int packet_count)
627 char tmp[SP_DECISIZE+1+1];
629 g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
631 /*g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_packet_count_to_parent: %s", tmp);*/
633 pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp);
637 sync_pipe_filename_to_parent(const char *filename)
639 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "File: %s", filename);
641 pipe_write_block(1, SP_FILE, strlen(filename)+1, filename);
645 sync_pipe_errmsg_to_parent(const char *errmsg)
647 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", errmsg);
649 pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
653 sync_pipe_drops_to_parent(int drops)
655 char tmp[SP_DECISIZE+1+1];
658 g_snprintf(tmp, sizeof(tmp), "%d", drops);
660 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_drops_to_parent: %s", tmp);
662 pipe_write_block(1, SP_DROPS, strlen(tmp)+1, tmp);
667 /****************************************************************************************************************/
671 void main_window_update(void) {}
675 void capture_info_create(capture_info *cinfo, gchar *iface) {}
677 void capture_info_update(capture_info *cinfo) {
678 printf("Packets: %u\r", cinfo->counts->total);
681 void capture_info_destroy(capture_info *cinfo) {}
685 display_simple_dialog(gint type, gint btn_mask, char *message)
687 printf("%s", message);
692 char *simple_dialog_primary_start(void)
697 char *simple_dialog_primary_end(void)
702 /* Simple dialog function - Displays a dialog box with the supplied message
706 * type : One of ESD_TYPE_*.
707 * btn_mask : The value passed in determines which buttons are displayed.
708 * msg_format : Sprintf-style format of the text displayed in the dialog.
709 * ... : Argument list for msg_format
713 vsimple_dialog(ESD_TYPE_E type, gint btn_mask, const gchar *msg_format, va_list ap)
718 #if GTK_MAJOR_VERSION >= 2
719 GdkWindowState state = 0;
722 /* Format the message. */
723 vmessage = g_strdup_vprintf(msg_format, ap);
725 #if GTK_MAJOR_VERSION >= 2
726 /* convert character encoding from locale to UTF8 (using iconv) */
727 message = g_locale_to_utf8(vmessage, -1, NULL, NULL, NULL);
733 win = display_simple_dialog(type, btn_mask, message);
741 simple_dialog(ESD_TYPE_E type, gint btn_mask, const gchar *msg_format, ...)
746 va_start(ap, msg_format);
747 ret = vsimple_dialog(type, btn_mask, msg_format, ap);
753 simple_dialog_format_message(const char *msg)
758 #if GTK_MAJOR_VERSION < 2
761 str = xml_escape(msg);
771 * Find out whether a hostname resolves to an ip or ipv6 address
772 * Return "ip6" if it is IPv6, "ip" otherwise (including the case
773 * that we don't know)
775 const char* host_ip_af(const char *host
776 #ifndef HAVE_GETHOSTBYNAME2
781 #ifdef HAVE_GETHOSTBYNAME2
783 return (h = gethostbyname2(host, AF_INET6)) && h->h_addrtype == AF_INET6 ? "ip6" : "ip";