5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
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.
28 #include <stdlib.h> /* for exit() */
46 #include "ringbuffer.h"
47 #include "clopts_common.h"
48 #include "cmdarg_err.h"
49 #include "version_info.h"
52 #include "capture-pcap-util.h"
55 #include "capture-wpcap.h"
58 #include "sync_pipe.h"
61 #include "capture_loop.h"
62 #include "capture_sync.h"
64 #include "simple_dialog.h"
67 #include "file_util.h"
70 /*#define DEBUG_DUMPCAP*/
72 gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */
75 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
76 const char *message, gpointer user_data _U_);
78 /* capture related options */
79 capture_options global_capture_opts;
80 capture_options *capture_opts = &global_capture_opts;
83 void exit_main(int err) __attribute__ ((noreturn));
85 void exit_main(int err);
90 print_usage(gboolean print_ver) {
98 "Dumpcap " VERSION "%s\n"
99 "Capture network packets and dump them into a libpcap file.\n"
100 "See http://www.wireshark.org for more information.\n",
101 wireshark_svnversion);
105 fprintf(output, "\nUsage: dumpcap [options] ...\n");
106 fprintf(output, "\n");
107 fprintf(output, "Capture interface:\n");
108 fprintf(output, " -i <interface> name or idx of interface (def: first none loopback)\n");
109 fprintf(output, " -f <capture filter> packet filter in libpcap filter syntax\n");
110 fprintf(output, " -s <snaplen> packet snapshot length (def: 65535)\n");
111 fprintf(output, " -p don't capture in promiscuous mode\n");
113 fprintf(output, " -B <buffer size> size of kernel buffer (def: 1MB)\n");
115 fprintf(output, " -y <link type> link layer type (def: first appropriate)\n");
116 fprintf(output, " -D print list of interfaces and exit\n");
117 fprintf(output, " -L print list of link-layer types of iface and exit\n");
118 fprintf(output, " -S print statistics for each interface once every second\n");
119 fprintf(output, " -M for -D, -L, and -S produce machine-readable output\n");
120 fprintf(output, "\n");
121 fprintf(output, "Stop conditions:\n");
122 fprintf(output, " -c <packet count> stop after n packets (def: infinite)\n");
123 fprintf(output, " -a <autostop cond.> ... duration:NUM - stop after NUM seconds\n");
124 fprintf(output, " filesize:NUM - stop this file after NUM KB\n");
125 fprintf(output, " files:NUM - stop after NUM files\n");
126 /*fprintf(output, "\n");*/
127 fprintf(output, "Output (files):\n");
128 fprintf(output, " -w <filename> name of file to save (def: tempfile)\n");
129 fprintf(output, " -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
130 fprintf(output, " filesize:NUM - switch to next file after NUM KB\n");
131 fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n");
132 /*fprintf(output, "\n");*/
133 fprintf(output, "Miscellaneous:\n");
134 fprintf(output, " -v print version information and exit\n");
135 fprintf(output, " -h display this help and exit\n");
136 fprintf(output, "\n");
137 fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcap\n");
138 fprintf(output, "\"Capture network packets from interface eth0 until 60s passed into output.pcap\"\n");
139 fprintf(output, "\n");
140 fprintf(output, "Use Ctrl-C to stop capturing at any time.\n");
144 show_version(GString *comp_info_str, GString *runtime_info_str)
148 "Dumpcap " VERSION "%s\n"
153 "See http://www.wireshark.org for more information.\n",
154 wireshark_svnversion, get_copyright_info() ,comp_info_str->str, runtime_info_str->str);
158 * Report an error in command-line arguments.
161 cmdarg_err(const char *fmt, ...)
166 /* Print a bare error */
168 vfprintf(stderr, fmt, ap);
172 fprintf(stderr, "dumpcap: ");
173 vfprintf(stderr, fmt, ap);
174 fprintf(stderr, "\n");
180 * Report additional information for an error in command-line arguments.
183 cmdarg_err_cont(const char *fmt, ...)
188 /* XXX - convert to g_log */
191 vfprintf(stderr, fmt, ap);
192 fprintf(stderr, "\n");
199 BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
201 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
202 "Console: Control signal");
203 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
204 "Console: Control signal, CtrlType: %u", dwCtrlType);
206 /* Keep capture running if we're a service and a user logs off */
207 if (capture_child || (dwCtrlType != CTRL_LOGOFF_EVENT)) {
216 void exit_main(int status)
219 /* Shutdown windows sockets */
222 /* can be helpful for debugging */
224 printf("Press any key\n");
234 /* And now our feature presentation... [ fade to music ] */
236 main(int argc, char *argv[])
240 gboolean arg_error = FALSE;
246 gboolean start_capture = TRUE;
247 gboolean stats_known;
248 struct pcap_stat stats;
249 GLogLevelFlags log_flags;
250 gboolean list_interfaces = FALSE;
251 gboolean list_link_layer_types = FALSE;
252 gboolean machine_readable = FALSE;
253 gboolean print_statistics = FALSE;
254 int status, run_once_args = 0;
256 #define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z"
259 #define OPTSTRING_WIN32 "B:"
261 #define OPTSTRING_WIN32 ""
264 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
265 OPTSTRING_INIT OPTSTRING_WIN32;
268 /* Load wpcap if possible. Do this before collecting the run-time version information */
271 /* ... and also load the packet.dll from wpcap */
272 /* XXX - currently not required, may change later. */
273 /*wpcap_packet_load();*/
275 /* Start windows sockets */
276 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
278 /* Set handler for Ctrl+C key */
279 SetConsoleCtrlHandler(&ConsoleCtrlHandlerRoutine, TRUE);
283 /* the default_log_handler will use stdout, which makes trouble in */
284 /* capture child mode, as it uses stdout for it's sync_pipe */
285 /* so do the filtering in the console_log_handler and not here */
288 G_LOG_LEVEL_CRITICAL|
293 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
295 g_log_set_handler(NULL,
297 console_log_handler, NULL /* user_data */);
298 g_log_set_handler(LOG_DOMAIN_MAIN,
300 console_log_handler, NULL /* user_data */);
301 g_log_set_handler(LOG_DOMAIN_CAPTURE,
303 console_log_handler, NULL /* user_data */);
304 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
306 console_log_handler, NULL /* user_data */);
308 /* Set the initial values in the capture_opts. This might be overwritten
309 by the command line parameters. */
310 capture_opts_init(capture_opts, NULL);
312 /* Default to capturing the entire packet. */
313 capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
315 /* We always save to a file - if no file was specified, we save to a
317 capture_opts->saving_to_file = TRUE;
318 capture_opts->has_ring_num_files = TRUE;
320 /* Now get our args */
321 while ((opt = getopt(argc, argv, optstring)) != -1) {
323 case 'h': /* Print help and exit */
327 case 'v': /* Show version and exit */
329 GString *comp_info_str;
330 GString *runtime_info_str;
331 /* Assemble the compile-time version information string */
332 comp_info_str = g_string_new("Compiled with ");
333 get_compiled_version_info(comp_info_str, NULL);
335 /* Assemble the run-time version information string */
336 runtime_info_str = g_string_new("Running ");
337 get_runtime_version_info(runtime_info_str, NULL);
338 show_version(comp_info_str, runtime_info_str);
339 g_string_free(comp_info_str, TRUE);
340 g_string_free(runtime_info_str, TRUE);
344 /*** capture option specific ***/
345 case 'a': /* autostop criteria */
346 case 'b': /* Ringbuffer option */
347 case 'c': /* Capture x packets */
348 case 'f': /* capture filter */
349 case 'i': /* Use interface x */
350 case 'p': /* Don't capture in promiscuous mode */
351 case 's': /* Set the snapshot (capture) length */
352 case 'w': /* Write to capture file x */
353 case 'y': /* Set the pcap data link type */
355 case 'B': /* Buffer size */
357 status = capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
362 /*** hidden option: Wireshark child mode (using binary output messages) ***/
364 capture_child = TRUE;
366 /* set output pipe to binary mode, to avoid ugly text conversions */
367 _setmode(1, O_BINARY);
371 /*** all non capture option specific ***/
372 case 'D': /* Print a list of capture devices and exit */
373 list_interfaces = TRUE;
376 case 'L': /* Print list of link-layer types and exit */
377 list_link_layer_types = TRUE;
380 case 'S': /* Print interface statistics once a second */
381 print_statistics = TRUE;
384 case 'M': /* For -D and -L, print machine-readable output */
385 machine_readable = TRUE;
388 case '?': /* Bad flag - print usage message */
389 cmdarg_err("Invalid Option: %s", argv[optind-1]);
397 /* user specified file name as regular command-line argument */
398 /* XXX - use it as the capture file name (or something else)? */
405 * Extra command line arguments were specified; complain.
406 * XXX - interpret as capture filter, as tcpdump and tshark do?
408 cmdarg_err("Invalid argument: %s", argv[0]);
417 if (run_once_args > 1) {
418 cmdarg_err("Only one of -D, -L, or -S may be supplied.");
420 } else if (list_link_layer_types) {
421 /* We're supposed to list the link-layer types for an interface;
422 did the user also specify a capture file to be read? */
423 /* No - did they specify a ring buffer option? */
424 if (capture_opts->multi_files_on) {
425 cmdarg_err("Ring buffer requested, but a capture isn't being done.");
429 /* No - was the ring buffer option specified and, if so, does it make
431 if (capture_opts->multi_files_on) {
432 /* Ring buffer works only under certain conditions:
433 a) ring buffer does not work with temporary files;
434 b) it makes no sense to enable the ring buffer if the maximum
435 file size is set to "infinite". */
436 if (capture_opts->save_file == NULL) {
437 cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
438 capture_opts->multi_files_on = FALSE;
440 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
441 cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
442 /* XXX - this must be redesigned as the conditions changed */
443 /* capture_opts->multi_files_on = FALSE;*/
448 if (capture_opts_trim_iface(capture_opts, NULL) == FALSE) {
449 cmdarg_err("No capture interfaces available (maybe lack of privileges?).");
453 /* Let the user know what interface was chosen. */
454 /* get_interface_descriptive_name() is not available! */
455 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Interface: %s\n", capture_opts->iface);
457 if (list_interfaces) {
458 status = capture_opts_list_interfaces(machine_readable);
460 } else if (list_link_layer_types) {
461 status = capture_opts_list_link_layer_types(capture_opts, machine_readable);
463 } else if (print_statistics) {
464 status = capture_opts_print_statistics(machine_readable);
468 capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
469 capture_opts_trim_ring_num_files(capture_opts);
471 /* Now start the capture. */
473 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
484 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
485 const char *message, gpointer user_data _U_)
492 /* ignore log message, if log_level isn't interesting */
493 if( !(log_level & G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG|G_LOG_LEVEL_INFO))) {
494 #ifndef DEBUG_DUMPCAP
499 /* create a "timestamp" */
501 today = localtime(&curr);
503 switch(log_level & G_LOG_LEVEL_MASK) {
504 case G_LOG_LEVEL_ERROR:
507 case G_LOG_LEVEL_CRITICAL:
510 case G_LOG_LEVEL_WARNING:
513 case G_LOG_LEVEL_MESSAGE:
516 case G_LOG_LEVEL_INFO:
519 case G_LOG_LEVEL_DEBUG:
523 fprintf(stderr, "unknown log_level %u\n", log_level);
525 g_assert_not_reached();
528 /* don't use printf (stdout), in child mode we're using stdout for the sync_pipe */
529 if(log_level & G_LOG_LEVEL_MESSAGE) {
530 /* normal user messages without additional infos */
531 fprintf(stderr, "%s\n", message);
534 /* info/debug messages with additional infos */
535 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
536 today->tm_hour, today->tm_min, today->tm_sec,
537 log_domain != NULL ? log_domain : "",
544 /****************************************************************************************************************/
545 /* indication report routines */
549 report_packet_count(int packet_count)
551 char tmp[SP_DECISIZE+1+1];
552 static int count = 0;
555 g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
556 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp);
557 pipe_write_block(1, SP_PACKET_COUNT, tmp);
559 count += packet_count;
560 fprintf(stderr, "\rPackets: %u ", count);
561 /* stderr could be line buffered */
567 report_new_capture_file(const char *filename)
570 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "File: %s", filename);
571 pipe_write_block(1, SP_FILE, filename);
573 fprintf(stderr, "File: %s\n", filename);
574 /* stderr could be line buffered */
580 report_cfilter_error(const char *cfilter, const char *errmsg)
583 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Capture filter error: %s", errmsg);
584 pipe_write_block(1, SP_BAD_FILTER, errmsg);
587 "Invalid capture filter: \"%s\"!\n"
589 "That string isn't a valid capture filter (%s).\n"
590 "See the User's Guide for a description of the capture filter syntax.\n",
596 report_capture_error(const char *error_msg, const char *secondary_error_msg)
599 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
600 "Primary Error: %s", error_msg);
601 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
602 "Secondary Error: %s", secondary_error_msg);
603 sync_pipe_errmsg_to_parent(error_msg, secondary_error_msg);
605 fprintf(stderr, "%s\n%s\n", error_msg, secondary_error_msg);
610 report_packet_drops(int drops)
612 char tmp[SP_DECISIZE+1+1];
614 g_snprintf(tmp, sizeof(tmp), "%d", drops);
617 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets dropped: %s", tmp);
618 pipe_write_block(1, SP_DROPS, tmp);
620 fprintf(stderr, "Packets dropped: %s\n", tmp);
621 /* stderr could be line buffered */
627 /****************************************************************************************************************/
628 /* signal_pipe handling */
633 signal_pipe_check_running(void)
635 /* any news from our parent (stdin)? -> just stop the capture */
641 /* if we are running standalone, no check required */
646 handle = (HANDLE) GetStdHandle(STD_INPUT_HANDLE);
647 result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
649 if(!result || avail > 0) {
650 /* peek failed or some bytes really available */
651 /* (if not piping from stdin this would fail) */
652 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
653 "Signal pipe: Stop capture");
654 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
655 "Signal pipe: handle: %x result: %u avail: %u", handle, result, avail);
658 /* pipe ok and no bytes available */