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 #include "ringbuffer.h"
46 #include "clopts_common.h"
47 #include "cmdarg_err.h"
48 #include "version_info.h"
51 #include "capture-pcap-util.h"
54 #include "capture-wpcap.h"
58 #include "capture_loop.h"
59 #include "capture_sync.h"
61 #include "simple_dialog.h"
64 #include "file_util.h"
68 gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Ethereal capture child */
71 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
72 const char *message, gpointer user_data _U_);
74 /* capture related options */
75 capture_options global_capture_opts;
76 capture_options *capture_opts = &global_capture_opts;
79 void exit_main(int err) __attribute__ ((noreturn));
81 void exit_main(int err);
86 print_usage(gboolean print_ver) {
94 "Dumpcap " VERSION "%s\n"
95 "Capture network packets and dump them into a libpcap file.\n"
96 "See http://www.ethereal.com for more information.\n",
101 fprintf(output, "\nUsage: dumpcap [options] ...\n");
102 fprintf(output, "\n");
103 fprintf(output, "Capture interface:\n");
104 fprintf(output, " -i <interface> name or idx of interface (def: first none loopback)\n");
105 fprintf(output, " -f <capture filter> packet filter in libpcap filter syntax\n");
106 fprintf(output, " -s <snaplen> packet snapshot length (def: 65535)\n");
107 fprintf(output, " -p don't capture in promiscuous mode\n");
109 fprintf(output, " -B <buffer size> size of kernel buffer (def: 1MB)\n");
111 fprintf(output, " -y <link type> link layer type (def: first appropriate)\n");
112 fprintf(output, " -D print list of interfaces and exit\n");
113 fprintf(output, " -L print list of link-layer types of iface and exit\n");
114 fprintf(output, "\n");
115 fprintf(output, "Stop conditions:\n");
116 fprintf(output, " -c <packet count> stop after n packets (def: infinite)\n");
117 fprintf(output, " -a <autostop cond.> ... duration:NUM - stop after NUM seconds\n");
118 fprintf(output, " filesize:NUM - stop this file after NUM KB\n");
119 fprintf(output, " files:NUM - stop after NUM files\n");
120 /*fprintf(output, "\n");*/
121 fprintf(output, "Output (files):\n");
122 fprintf(output, " -w <filename> name of file to save (def: tempfile)\n");
123 fprintf(output, " -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
124 fprintf(output, " filesize:NUM - switch to next file after NUM KB\n");
125 fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n");
126 /*fprintf(output, "\n");*/
127 fprintf(output, "Miscellaneous:\n");
128 fprintf(output, " -v print version information and exit\n");
129 fprintf(output, " -h display this help and exit\n");
130 fprintf(output, "\n");
131 fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcap\n");
132 fprintf(output, "\"Capture network packets from interface eth0 until 60s passed into output.pcap\"\n");
133 fprintf(output, "\n");
134 fprintf(output, "Use Ctrl-C to stop capturing at any time.\n");
138 show_version(GString *comp_info_str, GString *runtime_info_str)
142 "Dumpcap " VERSION "%s\n"
147 "See http://www.ethereal.com for more information.\n",
148 svnversion, get_copyright_info() ,comp_info_str->str, runtime_info_str->str);
152 * Report an error in command-line arguments.
155 cmdarg_err(const char *fmt, ...)
160 /* XXX - convert to g_log */
163 fprintf(stderr, "dumpcap: ");
164 vfprintf(stderr, fmt, ap);
165 fprintf(stderr, "\n");
171 * Report additional information for an error in command-line arguments.
174 cmdarg_err_cont(const char *fmt, ...)
179 /* XXX - convert to g_log */
182 vfprintf(stderr, fmt, ap);
183 fprintf(stderr, "\n");
190 BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
192 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
194 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
195 "Console: Ctrl+C CtrlType: %u", dwCtrlType);
203 void exit_main(int status)
206 /* Shutdown windows sockets */
210 /* can be helpful for debugging */
212 printf("Press any key\n");
220 /* And now our feature presentation... [ fade to music ] */
222 main(int argc, char *argv[])
226 gboolean arg_error = FALSE;
227 GString *comp_info_str;
228 GString *runtime_info_str;
234 gboolean start_capture = TRUE;
235 gboolean stats_known;
236 struct pcap_stat stats;
237 GLogLevelFlags log_flags;
238 gboolean list_link_layer_types = FALSE;
241 #define OPTSTRING_INIT "a:b:c:Df:hi:Lps:vw:y:Z"
244 #define OPTSTRING_WIN32 "B:"
246 #define OPTSTRING_WIN32 ""
249 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
250 OPTSTRING_INIT OPTSTRING_WIN32;
253 /* Load wpcap if possible. Do this before collecting the run-time version information */
256 /* ... and also load the packet.dll from wpcap */
257 /* XXX - currently not required, may change later. */
258 /*wpcap_packet_load();*/
260 /* Start windows sockets */
261 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
263 /* Set handler for Ctrl+C key */
264 SetConsoleCtrlHandler(&ConsoleCtrlHandlerRoutine, TRUE);
267 /* Assemble the compile-time version information string */
268 comp_info_str = g_string_new("Compiled ");
269 g_string_append(comp_info_str, "with ");
270 get_compiled_version_info(comp_info_str);
272 /* Assemble the run-time version information string */
273 runtime_info_str = g_string_new("Running ");
274 get_runtime_version_info(runtime_info_str);
276 /* Arrange that if we have no console window, and a GLib message logging
277 routine is called to log a message, we pop up a console window.
279 We do that by inserting our own handler for all messages logged
280 to the default domain; that handler pops up a console if necessary,
281 and then calls the default handler. */
283 /* We might want to have component specific log levels later ... */
285 /* the default_log_handler will use stdout, which makes trouble with the */
286 /* capture child, as it uses stdout for it's sync_pipe */
287 /* so do the filtering in the console_log_handler and not here */
290 G_LOG_LEVEL_CRITICAL|
295 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
297 g_log_set_handler(NULL,
299 console_log_handler, NULL /* user_data */);
300 g_log_set_handler(LOG_DOMAIN_MAIN,
302 console_log_handler, NULL /* user_data */);
303 g_log_set_handler(LOG_DOMAIN_CAPTURE,
305 console_log_handler, NULL /* user_data */);
306 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
308 console_log_handler, NULL /* user_data */);
310 /* Set the initial values in the capture_opts. This might be overwritten
311 by the command line parameters. */
312 capture_opts_init(capture_opts, NULL);
314 capture_opts->snaplen = MIN_PACKET_SIZE;
315 capture_opts->has_ring_num_files = TRUE;
317 /* Now get our args */
318 while ((opt = getopt(argc, argv, optstring)) != -1) {
320 case 'h': /* Print help and exit */
324 case 'v': /* Show version and exit */
325 show_version(comp_info_str, runtime_info_str);
328 /*** capture option specific ***/
329 case 'a': /* autostop criteria */
330 case 'b': /* Ringbuffer option */
331 case 'c': /* Capture x packets */
332 case 'f': /* capture filter */
333 case 'i': /* Use interface x */
334 case 'p': /* Don't capture in promiscuous mode */
335 case 's': /* Set the snapshot (capture) length */
336 case 'w': /* Write to capture file x */
337 case 'y': /* Set the pcap data link type */
339 case 'B': /* Buffer size */
341 status = capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
346 /*** hidden option: Ethereal child mode (using binary output messages) ***/
348 capture_child = TRUE;
351 /*** all non capture option specific ***/
352 case 'D': /* Print a list of capture devices and exit */
353 status = capture_opts_list_interfaces();
356 case 'L': /* Print list of link-layer types and exit */
357 list_link_layer_types = TRUE;
360 case '?': /* Bad flag - print usage message */
361 cmdarg_err("Invalid Option: %s", argv[optind-1]);
369 /* user specified file name as regular command-line argument */
370 /* XXX - use it as the capture file name (or something else)? */
377 * Extra command line arguments were specified; complain.
379 cmdarg_err("Invalid argument: %s", argv[0]);
388 if (list_link_layer_types) {
389 /* We're supposed to list the link-layer types for an interface;
390 did the user also specify a capture file to be read? */
391 /* No - did they specify a ring buffer option? */
392 if (capture_opts->multi_files_on) {
393 cmdarg_err("Ring buffer requested, but a capture isn't being done.");
397 /* No - was the ring buffer option specified and, if so, does it make
399 if (capture_opts->multi_files_on) {
400 /* Ring buffer works only under certain conditions:
401 a) ring buffer does not work with temporary files;
402 b) it makes no sense to enable the ring buffer if the maximum
403 file size is set to "infinite". */
404 if (capture_opts->save_file == NULL) {
405 cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
406 capture_opts->multi_files_on = FALSE;
408 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
409 cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
410 /* XXX - this must be redesigned as the conditions changed */
411 /* capture_opts->multi_files_on = FALSE;*/
416 if (capture_opts_trim_iface(capture_opts, NULL) == FALSE) {
417 cmdarg_err("No capture interfaces available (maybe lack of privileges?).");
421 /* Let the user know what interface was chosen. */
422 /* get_interface_descriptive_name() is not available! */
423 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Interface: %s\n", capture_opts->iface);
425 if (list_link_layer_types) {
426 status = capture_opts_list_link_layer_types(capture_opts);
430 capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
431 capture_opts_trim_ring_num_files(capture_opts);
433 /* Now start the capture. */
435 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
445 /* This routine should not be necessary, at least as I read the GLib
446 source code, as it looks as if GLib is, on Win32, *supposed* to
447 create a console window into which to display its output.
449 That doesn't happen, however. I suspect there's something completely
450 broken about that code in GLib-for-Win32, and that it may be related
451 to the breakage that forces us to just call "printf()" on the message
452 rather than passing the message on to "g_log_default_handler()"
453 (which is the routine that does the aforementioned non-functional
454 console window creation). */
456 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
457 const char *message, gpointer user_data _U_)
468 /* ignore log message, if log_level isn't interesting */
469 if( !(log_level & G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG|G_LOG_LEVEL_INFO))) {
470 #ifndef DEBUG_DUMPCAP
475 /* create a "timestamp" */
477 today = localtime(&curr);
479 switch(log_level & G_LOG_LEVEL_MASK) {
480 case G_LOG_LEVEL_ERROR:
483 case G_LOG_LEVEL_CRITICAL:
486 case G_LOG_LEVEL_WARNING:
489 case G_LOG_LEVEL_MESSAGE:
492 case G_LOG_LEVEL_INFO:
495 case G_LOG_LEVEL_DEBUG:
499 fprintf(stderr, "unknown log_level %u\n", log_level);
501 g_assert_not_reached();
504 /* don't use printf (stdout), in child mode we're using stdout for the sync_pipe */
505 if(log_level & G_LOG_LEVEL_MESSAGE) {
506 /* normal user messages without additional infos */
507 fprintf(stderr, "%s\n", message);
510 /* info/debug messages with additional infos */
511 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
512 today->tm_hour, today->tm_min, today->tm_sec,
513 log_domain != NULL ? log_domain : "",
520 /****************************************************************************************************************/
521 /* sync_pipe handling */
525 * Maximum length of sync pipe message data. Must be < 2^24, as the
526 * message length is 3 bytes.
527 * XXX - this must be large enough to handle a Really Big Filter
528 * Expression, as the error message for an incorrect filter expression
529 * is a bit larger than the filter expression.
531 #define SP_MAX_MSG_LEN 4096
534 /* write a message to the recipient pipe in the standard format
535 (3 digit message length (excluding length and indicator field),
536 1 byte message indicator and the rest is the message) */
538 pipe_write_block(int pipe, char indicator, int len, const char *msg)
540 guchar header[3+1]; /* indicator + 3-byte len */
543 /*g_warning("write %d enter", pipe);*/
545 g_assert(indicator < '0' || indicator > '9');
546 g_assert(len <= SP_MAX_MSG_LEN);
548 /* write header (indicator + 3-byte len) */
549 header[0] = indicator;
550 header[1] = (len >> 16) & 0xFF;
551 header[2] = (len >> 8) & 0xFF;
552 header[3] = (len >> 0) & 0xFF;
554 ret = write(pipe, header, sizeof header);
559 /* write value (if we have one) */
561 /*g_warning("write %d indicator: %c value len: %u msg: %s", pipe, indicator, len, msg);*/
562 ret = write(pipe, msg, len);
567 /*g_warning("write %d indicator: %c no value", pipe, indicator);*/
570 /*g_warning("write %d leave", pipe);*/
575 sync_pipe_packet_count_to_parent(int packet_count)
577 char tmp[SP_DECISIZE+1+1];
578 static int count = 0;
582 g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
583 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp);
584 pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp);
586 count += packet_count;
587 fprintf(stderr, "\rPackets: %u ", count);
588 /* stderr could be line buffered */
595 sync_pipe_filename_to_parent(const char *filename)
598 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "File: %s", filename);
601 pipe_write_block(1, SP_FILE, strlen(filename)+1, filename);
606 sync_pipe_errmsg_to_parent(const char *errmsg)
609 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Error: %s", errmsg);
612 pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
617 sync_pipe_drops_to_parent(int drops)
619 char tmp[SP_DECISIZE+1+1];
622 g_snprintf(tmp, sizeof(tmp), "%d", drops);
623 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Packets dropped: %s", tmp);
626 pipe_write_block(1, SP_DROPS, strlen(tmp)+1, tmp);
631 /****************************************************************************************************************/
632 /* signal_pipe handling */
637 signal_pipe_check_running(void)
639 /* any news from our parent (stdin)? -> just stop the capture */
645 /* if we are running standalone, no check required */
650 handle = (HANDLE) GetStdHandle(STD_INPUT_HANDLE);
651 result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
653 if(!result || avail > 0) {
654 /* peek failed or some bytes really available */
655 /* (if not piping from stdin this would fail) */
656 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
657 "Signal pipe: Stop capture");
658 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
659 "Signal pipe: handle: %x result: %u avail: %u", handle, result, avail);
662 /* pipe ok and no bytes available */
669 /****************************************************************************************************************/
670 /* simple_dialog stubs */
673 char *simple_dialog_primary_start(void)
678 char *simple_dialog_primary_end(void)
684 simple_dialog_format_message(const char *msg)
689 #if GTK_MAJOR_VERSION < 2
692 str = xml_escape(msg);
701 /****************************************************************************************************************/
705 const char *netsnmp_get_version(void) { return ""; }
707 gboolean dfilter_compile(const gchar *text, dfilter_t **dfp) { (void)text; (void)dfp; return FALSE; }
709 void dfilter_free(dfilter_t *df) { (void)df; }