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.
45 #ifdef _WIN32 /* Needed for console I/O */
49 #include "ringbuffer.h"
50 #include "clopts_common.h"
51 #include "cmdarg_err.h"
52 #include "version_info.h"
55 #include "capture-pcap-util.h"
58 #include "capture-wpcap.h"
59 /*#include "capture_wpcap_packet.h"*/
63 #include "capture_loop.h"
64 #include "capture_sync.h"
66 #include "simple_dialog.h"
69 #include "file_util.h"
73 /* Win32 console handling */
75 static gboolean has_console = TRUE; /* TRUE if app has console */
76 static void create_console(void);
77 static void destroy_console(void);
80 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
81 const char *message, gpointer user_data _U_);
83 /* capture related options */
84 capture_options global_capture_opts;
85 capture_options *capture_opts = &global_capture_opts;
88 void exit_main(int err) __attribute__ ((noreturn));
90 void exit_main(int err);
96 print_usage(gboolean print_ver) {
107 "Dumpcap " VERSION "%s\n"
108 "Capture network packets and dump them into a libpcap file.\n"
109 "See http://www.ethereal.com for more information.\n",
114 fprintf(output, "\nUsage: dumpcap [options] ...\n");
115 fprintf(output, "\n");
116 fprintf(output, "Capture interface:\n");
117 fprintf(output, " -i <interface> name or idx of interface (def: first none loopback)\n");
118 fprintf(output, " -f <capture filter> packet filter in libpcap filter syntax\n");
119 fprintf(output, " -s <snaplen> packet snapshot length (def: 65535)\n");
120 fprintf(output, " -p don't capture in promiscuous mode\n");
122 fprintf(output, " -B <buffer size> size of kernel buffer (def: 1MB)\n");
124 fprintf(output, " -y <link type> link layer type (def: first appropriate)\n");
125 fprintf(output, " -D print list of interfaces and exit\n");
126 fprintf(output, " -L print list of link-layer types of iface and exit\n");
127 fprintf(output, "\n");
128 fprintf(output, "Stop conditions:\n");
129 fprintf(output, " -c <packet count> stop after n packets (def: infinite)\n");
130 fprintf(output, " -a <autostop cond.> ... duration:NUM - stop after NUM seconds\n");
131 fprintf(output, " filesize:NUM - stop this file after NUM KB\n");
132 fprintf(output, " files:NUM - stop after NUM files\n");
133 /*fprintf(output, "\n");*/
134 fprintf(output, "Output (files):\n");
135 fprintf(output, " -w <filename> name of file to save (def: tempfile)\n");
136 fprintf(output, " -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
137 fprintf(output, " filesize:NUM - switch to next file after NUM KB\n");
138 fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n");
139 /*fprintf(output, "\n");*/
140 fprintf(output, "Miscellaneous:\n");
141 fprintf(output, " -v print version information and exit\n");
142 fprintf(output, " -h display this help and exit\n");
143 fprintf(output, "\n");
144 fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcap\n");
145 fprintf(output, "\"Capture network packets from interface eth0 until 60s passed into output.pcap\"\n");
146 fprintf(output, "\n");
147 fprintf(output, "Use Ctrl-C to stop capturing at any time.\n");
151 show_version(GString *comp_info_str, GString *runtime_info_str)
158 "Dumpcap " VERSION "%s\n"
163 "See http://www.ethereal.com for more information.\n",
164 svnversion, get_copyright_info() ,comp_info_str->str, runtime_info_str->str);
168 * Report an error in command-line arguments.
169 * Creates a console on Windows.
170 * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
171 * terminal isn't the standard error?
174 cmdarg_err(const char *fmt, ...)
182 fprintf(stderr, "dumpcap: ");
183 vfprintf(stderr, fmt, ap);
184 fprintf(stderr, "\n");
189 * Report additional information for an error in command-line arguments.
190 * Creates a console on Windows.
191 * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
192 * terminal isn't the standard error?
195 cmdarg_err_cont(const char *fmt, ...)
203 vfprintf(stderr, fmt, ap);
204 fprintf(stderr, "\n");
210 BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
212 /*printf("Event: %u", dwCtrlType);*/
219 void exit_main(int err)
222 /* Shutdown windows sockets */
232 /* And now our feature presentation... [ fade to music ] */
234 main(int argc, char *argv[])
238 gboolean arg_error = FALSE;
239 GString *comp_info_str;
240 GString *runtime_info_str;
246 gboolean start_capture = TRUE;
247 gboolean stats_known;
248 struct pcap_stat stats;
249 GLogLevelFlags log_flags;
250 gboolean list_link_layer_types = FALSE;
252 #define OPTSTRING_INIT "a:b:c:Df:hi:Lps:vw:y:"
255 #define OPTSTRING_WIN32 "B:Z:"
257 #define OPTSTRING_WIN32 ""
260 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
261 OPTSTRING_INIT OPTSTRING_WIN32;
266 /* Load wpcap if possible. Do this before collecting the run-time version information */
269 /* ... and also load the packet.dll from wpcap */
270 /* XXX - currently not required, may change later. */
271 /*wpcap_packet_load();*/
273 /* Start windows sockets */
274 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
276 /* Set handler for Ctrl+C key */
277 SetConsoleCtrlHandler(&ConsoleCtrlHandlerRoutine, TRUE);
280 /* Assemble the compile-time version information string */
281 comp_info_str = g_string_new("Compiled ");
282 g_string_append(comp_info_str, "with ");
283 get_compiled_version_info(comp_info_str);
285 /* Assemble the run-time version information string */
286 runtime_info_str = g_string_new("Running ");
287 get_runtime_version_info(runtime_info_str);
289 /* Arrange that if we have no console window, and a GLib message logging
290 routine is called to log a message, we pop up a console window.
292 We do that by inserting our own handler for all messages logged
293 to the default domain; that handler pops up a console if necessary,
294 and then calls the default handler. */
296 /* We might want to have component specific log levels later ... */
298 /* the default_log_handler will use stdout, which makes trouble with the */
299 /* capture child, as it uses stdout for it's sync_pipe */
300 /* so do the filtering in the console_log_handler and not here */
303 G_LOG_LEVEL_CRITICAL|
308 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
310 g_log_set_handler(NULL,
312 console_log_handler, NULL /* user_data */);
313 g_log_set_handler(LOG_DOMAIN_MAIN,
315 console_log_handler, NULL /* user_data */);
316 g_log_set_handler(LOG_DOMAIN_CAPTURE,
318 console_log_handler, NULL /* user_data */);
319 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
321 console_log_handler, NULL /* user_data */);
323 /* Set the initial values in the capture_opts. This might be overwritten
324 by the command line parameters. */
325 capture_opts_init(capture_opts, NULL);
327 capture_opts->snaplen = MIN_PACKET_SIZE;
328 capture_opts->has_ring_num_files = TRUE;
330 /* Now get our args */
331 while ((opt = getopt(argc, argv, optstring)) != -1) {
333 case 'h': /* Print help and exit */
337 case 'v': /* Show version and exit */
338 show_version(comp_info_str, runtime_info_str);
341 /*** capture option specific ***/
342 case 'a': /* autostop criteria */
343 case 'b': /* Ringbuffer option */
344 case 'c': /* Capture x packets */
345 case 'f': /* capture filter */
346 case 'i': /* Use interface x */
347 case 'p': /* Don't capture in promiscuous mode */
348 case 's': /* Set the snapshot (capture) length */
349 case 'w': /* Write to capture file x */
350 case 'y': /* Set the pcap data link type */
352 case 'B': /* Buffer size */
353 /* Hidden option supporting Sync mode */
354 case 'Z': /* Write to pipe FD x */
356 capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
359 /*** all non capture option specific ***/
360 case 'D': /* Print a list of capture devices and exit */
361 capture_opts_list_interfaces();
364 case 'L': /* Print list of link-layer types and exit */
365 list_link_layer_types = TRUE;
368 case '?': /* Bad flag - print usage message */
369 cmdarg_err("Invalid Option: %s", argv[optind-1]);
377 /* user specified file name as regular command-line argument */
378 /* XXX - use it as the capture file name (or something else)? */
385 * Extra command line arguments were specified; complain.
387 cmdarg_err("Invalid argument: %s", argv[0]);
396 if (list_link_layer_types) {
397 /* We're supposed to list the link-layer types for an interface;
398 did the user also specify a capture file to be read? */
399 /* No - did they specify a ring buffer option? */
400 if (capture_opts->multi_files_on) {
401 cmdarg_err("Ring buffer requested, but a capture isn't being done.");
405 /* No - was the ring buffer option specified and, if so, does it make
407 if (capture_opts->multi_files_on) {
408 /* Ring buffer works only under certain conditions:
409 a) ring buffer does not work with temporary files;
410 b) it makes no sense to enable the ring buffer if the maximum
411 file size is set to "infinite". */
412 if (capture_opts->save_file == NULL) {
413 cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
414 capture_opts->multi_files_on = FALSE;
416 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
417 cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
418 /* XXX - this must be redesigned as the conditions changed */
419 /* capture_opts->multi_files_on = FALSE;*/
424 if (capture_opts_trim_iface(capture_opts, NULL) == FALSE) {
425 cmdarg_err("No capture interfaces available (maybe lack of privileges?).");
429 /* Let the user know what interface was chosen. */
430 /* descr = get_interface_descriptive_name(capture_opts.iface);
431 fprintf(stderr, "Capturing on %s\n", descr);
433 fprintf(stderr, "Capturing on %s\n", capture_opts->iface);
436 if (list_link_layer_types) {
437 capture_opts_list_link_layer_types(capture_opts);
441 capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
442 capture_opts_trim_ring_num_files(capture_opts);
444 /* Now start the capture. */
446 /* XXX - hand the stats to the parent process */
447 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
458 /* We build this as a GUI subsystem application on Win32, so
459 "WinMain()", not "main()", gets called.
461 Hack shamelessly stolen from the Win32 port of the GIMP. */
463 #define _stdcall __attribute__((stdcall))
467 WinMain (struct HINSTANCE__ *hInstance,
468 struct HINSTANCE__ *hPrevInstance,
473 return main (__argc, __argv);
477 * If this application has no console window to which its standard output
478 * would go, create one.
484 /* We have no console to which to print the version string, so
485 create one and make it the standard input, output, and error. */
487 return; /* couldn't create console */
488 eth_freopen("CONIN$", "r", stdin);
489 eth_freopen("CONOUT$", "w", stdout);
490 eth_freopen("CONOUT$", "w", stderr);
492 /* Well, we have a console now. */
495 /* Now register "destroy_console()" as a routine to be called just
496 before the application exits, so that we can destroy the console
497 after the user has typed a key (so that the console doesn't just
498 disappear out from under them, giving the user no chance to see
499 the message(s) we put in there). */
500 atexit(destroy_console);
502 SetConsoleTitle("Dumpcap Console");
507 destroy_console(void)
510 /* XXX - doesn't make sense while we're linked as a console application */
511 /* printf("\n\nPress any key to exit\n");
519 /* This routine should not be necessary, at least as I read the GLib
520 source code, as it looks as if GLib is, on Win32, *supposed* to
521 create a console window into which to display its output.
523 That doesn't happen, however. I suspect there's something completely
524 broken about that code in GLib-for-Win32, and that it may be related
525 to the breakage that forces us to just call "printf()" on the message
526 rather than passing the message on to "g_log_default_handler()"
527 (which is the routine that does the aforementioned non-functional
528 console window creation). */
530 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
531 const char *message, gpointer user_data _U_)
538 /* ignore log message, if log_level isn't interesting */
539 if( !(log_level & G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG|G_LOG_LEVEL_INFO) /*prefs.console_log_level*/)) {
543 /* create a "timestamp" */
545 today = localtime(&curr);
548 /* if (prefs.gui_console_open != console_open_never) {*/
552 /* For some unknown reason, the above doesn't appear to actually cause
553 anything to be sent to the standard output, so we'll just splat the
554 message out directly, just to make sure it gets out. */
556 switch(log_level & G_LOG_LEVEL_MASK) {
557 case G_LOG_LEVEL_ERROR:
560 case G_LOG_LEVEL_CRITICAL:
563 case G_LOG_LEVEL_WARNING:
566 case G_LOG_LEVEL_MESSAGE:
569 case G_LOG_LEVEL_INFO:
572 case G_LOG_LEVEL_DEBUG:
576 fprintf(stderr, "unknown log_level %u\n", log_level);
578 g_assert_not_reached();
581 /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
582 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
583 today->tm_hour, today->tm_min, today->tm_sec,
584 log_domain != NULL ? log_domain : "",
588 g_log_default_handler(log_domain, log_level, message, user_data);
593 /****************************************************************************************************************/
594 /* sync_pipe stubs */
597 * Maximum length of sync pipe message data. Must be < 2^24, as the
598 * message length is 3 bytes.
599 * XXX - this must be large enough to handle a Really Big Filter
600 * Expression, as the error message for an incorrect filter expression
601 * is a bit larger than the filter expression.
603 #define SP_MAX_MSG_LEN 4096
606 /* write a message to the recipient pipe in the standard format
607 (3 digit message length (excluding length and indicator field),
608 1 byte message indicator and the rest is the message) */
610 pipe_write_block(int pipe, char indicator, int len, const char *msg)
612 guchar header[3+1]; /* indicator + 3-byte len */
615 /*g_warning("write %d enter", pipe);*/
617 /* XXX - find a suitable way to switch between pipe and console output */
620 g_assert(indicator < '0' || indicator > '9');
621 g_assert(len <= SP_MAX_MSG_LEN);
623 /* write header (indicator + 3-byte len) */
624 header[0] = indicator;
625 header[1] = (len >> 16) & 0xFF;
626 header[2] = (len >> 8) & 0xFF;
627 header[3] = (len >> 0) & 0xFF;
629 ret = write(pipe, header, sizeof header);
634 /* write value (if we have one) */
636 /*g_warning("write %d indicator: %c value len: %u msg: %s", pipe, indicator, len, msg);*/
637 ret = write(pipe, msg, len);
642 /*g_warning("write %d indicator: %c no value", pipe, indicator);*/
645 /*g_warning("write %d leave", pipe);*/
652 sync_pipe_packet_count_to_parent(int packet_count)
654 char tmp[SP_DECISIZE+1+1];
657 count += packet_count;
658 fprintf(stderr, "\r%u", count);
659 /* stderr could be line buffered */
663 g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
665 /*g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_packet_count_to_parent: %s", tmp);*/
667 pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp);
671 sync_pipe_filename_to_parent(const char *filename)
673 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "File: %s", filename);
675 pipe_write_block(1, SP_FILE, strlen(filename)+1, filename);
679 sync_pipe_errmsg_to_parent(const char *errmsg)
681 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", errmsg);
683 pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
687 sync_pipe_drops_to_parent(int drops)
689 char tmp[SP_DECISIZE+1+1];
692 g_snprintf(tmp, sizeof(tmp), "%d", drops);
694 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_drops_to_parent: %s", tmp);
696 pipe_write_block(1, SP_DROPS, strlen(tmp)+1, tmp);
701 /****************************************************************************************************************/
702 /* simple_dialog stubs */
705 char *simple_dialog_primary_start(void)
710 char *simple_dialog_primary_end(void)
716 simple_dialog_format_message(const char *msg)
721 #if GTK_MAJOR_VERSION < 2
724 str = xml_escape(msg);
732 /****************************************************************************************************************/
736 const char *netsnmp_get_version(void) { return ""; }
738 gboolean dfilter_compile(const gchar *text, dfilter_t **dfp) { (void)text; (void)dfp; return FALSE; }
740 void dfilter_free(dfilter_t *df) { (void)df; }
744 * Find out whether a hostname resolves to an ip or ipv6 address
745 * Return "ip6" if it is IPv6, "ip" otherwise (including the case
746 * that we don't know)
748 const char* host_ip_af(const char *host
749 #ifndef HAVE_GETHOSTBYNAME2
754 #ifdef HAVE_GETHOSTBYNAME2
756 return (h = gethostbyname2(host, AF_INET6)) && h->h_addrtype == AF_INET6 ? "ip6" : "ip";