We don't use NetSNMP any more.
[obnox/wireshark/wip.git] / dumpcap.c
1 /* dumpcap.c
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
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.
13  *
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.
18  *
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.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <stdlib.h> /* for exit() */
29 #include <glib.h>
30
31 #include <string.h>
32 #include <ctype.h>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #ifdef NEED_GETOPT_H
39 #include "getopt.h"
40 #endif
41
42 #ifdef HAVE_NETDB_H
43 #include <netdb.h>
44 #endif
45
46 #include "ringbuffer.h"
47 #include "clopts_common.h"
48 #include "cmdarg_err.h"
49 #include "version_info.h"
50
51 #include <pcap.h>
52 #include "capture-pcap-util.h"
53
54 #ifdef _WIN32
55 #include "capture-wpcap.h"
56 #endif
57
58 #include "sync_pipe.h"
59
60 #include "capture.h"
61 #include "capture_loop.h"
62 #include "capture_sync.h"
63
64 #include "simple_dialog.h"
65 #include "util.h"
66 #include "log.h"
67 #include "file_util.h"
68
69
70 /*#define DEBUG_DUMPCAP*/
71
72 gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */
73
74 static void
75 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
76                     const char *message, gpointer user_data _U_);
77
78 /* capture related options */
79 capture_options global_capture_opts;
80 capture_options *capture_opts = &global_capture_opts;
81
82 #if __GNUC__ >= 2
83 void exit_main(int err) __attribute__ ((noreturn));
84 #else
85 void exit_main(int err);
86 #endif
87
88
89 static void
90 print_usage(gboolean print_ver) {
91
92   FILE *output;
93
94
95   if (print_ver) {
96     output = stdout;
97     fprintf(output,
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);
102   } else {
103     output = stderr;
104   }
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");
112 #ifdef _WIN32
113   fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
114 #endif
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");
141 }
142
143 static void
144 show_version(GString *comp_info_str, GString *runtime_info_str)
145 {
146
147   printf(
148         "Dumpcap " VERSION "%s\n"
149         "\n"
150         "%s\n"
151         "%s\n"
152         "%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);
155 }
156
157 /*
158  * Report an error in command-line arguments.
159  */
160 void
161 cmdarg_err(const char *fmt, ...)
162 {
163   va_list ap;
164
165   if(capture_child) {
166     /* Print a bare error */
167     va_start(ap, fmt);
168     vfprintf(stderr, fmt, ap);
169     va_end(ap);
170   } else {
171     va_start(ap, fmt);
172     fprintf(stderr, "dumpcap: ");
173     vfprintf(stderr, fmt, ap);
174     fprintf(stderr, "\n");
175     va_end(ap);
176   }
177 }
178
179 /*
180  * Report additional information for an error in command-line arguments.
181  */
182 void
183 cmdarg_err_cont(const char *fmt, ...)
184 {
185   va_list ap;
186
187   if(capture_child) {
188     /* XXX - convert to g_log */
189   } else {
190     va_start(ap, fmt);
191     vfprintf(stderr, fmt, ap);
192     fprintf(stderr, "\n");
193     va_end(ap);
194   }
195 }
196
197
198 #ifdef _WIN32
199 BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
200 {
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);
205
206     /* Keep capture running if we're a service and a user logs off */
207     if (capture_child || (dwCtrlType != CTRL_LOGOFF_EVENT)) {
208         capture_loop_stop();
209         return TRUE;
210     } else {
211         return FALSE;
212     }
213 }
214 #endif
215
216 void exit_main(int status)
217 {
218 #ifdef _WIN32
219   /* Shutdown windows sockets */
220   WSACleanup();
221
222   /* can be helpful for debugging */
223 #ifdef DEBUG_DUMPCAP
224   printf("Press any key\n");
225   _getch();
226 #endif
227
228 #endif /* _WIN32 */
229
230   exit(status);
231 }
232
233
234 /* And now our feature presentation... [ fade to music ] */
235 int
236 main(int argc, char *argv[])
237 {
238   int                  opt;
239   extern char         *optarg;
240   gboolean             arg_error = FALSE;
241
242 #ifdef _WIN32
243   WSADATA              wsaData;
244 #endif  /* _WIN32 */
245
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;
255
256 #define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z"
257
258 #ifdef _WIN32
259 #define OPTSTRING_WIN32 "B:"
260 #else
261 #define OPTSTRING_WIN32 ""
262 #endif  /* _WIN32 */
263
264   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
265     OPTSTRING_INIT OPTSTRING_WIN32;
266
267 #ifdef _WIN32
268   /* Load wpcap if possible. Do this before collecting the run-time version information */
269   load_wpcap();
270
271   /* ... and also load the packet.dll from wpcap */
272   /* XXX - currently not required, may change later. */
273   /*wpcap_packet_load();*/
274
275   /* Start windows sockets */
276   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
277
278   /* Set handler for Ctrl+C key */
279   SetConsoleCtrlHandler(&ConsoleCtrlHandlerRoutine, TRUE);
280 #endif  /* _WIN32 */
281
282
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 */
286   log_flags =
287                     G_LOG_LEVEL_ERROR|
288                     G_LOG_LEVEL_CRITICAL|
289                     G_LOG_LEVEL_WARNING|
290                     G_LOG_LEVEL_MESSAGE|
291                     G_LOG_LEVEL_INFO|
292                     G_LOG_LEVEL_DEBUG|
293                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
294
295   g_log_set_handler(NULL,
296                     log_flags,
297                     console_log_handler, NULL /* user_data */);
298   g_log_set_handler(LOG_DOMAIN_MAIN,
299                     log_flags,
300                     console_log_handler, NULL /* user_data */);
301   g_log_set_handler(LOG_DOMAIN_CAPTURE,
302                     log_flags,
303             console_log_handler, NULL /* user_data */);
304   g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
305                     log_flags,
306             console_log_handler, NULL /* user_data */);
307
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);
311
312   /* Default to capturing the entire packet. */
313   capture_opts->snaplen             = WTAP_MAX_PACKET_SIZE;
314
315   /* We always save to a file - if no file was specified, we save to a
316      temporary file. */
317   capture_opts->saving_to_file      = TRUE;
318   capture_opts->has_ring_num_files  = TRUE;
319
320   /* Now get our args */
321   while ((opt = getopt(argc, argv, optstring)) != -1) {
322     switch (opt) {
323       case 'h':        /* Print help and exit */
324         print_usage(TRUE);
325         exit_main(0);
326         break;
327       case 'v':        /* Show version and exit */
328       {
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);
334
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);
341         exit_main(0);
342         break;
343       }
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 */
354 #ifdef _WIN32
355       case 'B':        /* Buffer size */
356 #endif /* _WIN32 */
357         status = capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
358         if(status != 0) {
359             exit_main(status);
360         }
361         break;
362       /*** hidden option: Wireshark child mode (using binary output messages) ***/
363       case 'Z':
364           capture_child = TRUE;
365 #ifdef _WIN32
366           /* set output pipe to binary mode, to avoid ugly text conversions */
367                   _setmode(1, O_BINARY);
368 #endif
369           break;
370
371       /*** all non capture option specific ***/
372       case 'D':        /* Print a list of capture devices and exit */
373         list_interfaces = TRUE;
374         run_once_args++;
375         break;
376       case 'L':        /* Print list of link-layer types and exit */
377         list_link_layer_types = TRUE;
378         run_once_args++;
379         break;
380       case 'S':        /* Print interface statistics once a second */
381         print_statistics = TRUE;
382         run_once_args++;
383         break;
384       case 'M':        /* For -D and -L, print machine-readable output */
385         machine_readable = TRUE;
386         break;
387       default:
388       case '?':        /* Bad flag - print usage message */
389         cmdarg_err("Invalid Option: %s", argv[optind-1]);
390         arg_error = TRUE;
391         break;
392     }
393   }
394   argc -= optind;
395   argv += optind;
396   if (argc >= 1) {
397       /* user specified file name as regular command-line argument */
398       /* XXX - use it as the capture file name (or something else)? */
399     argc--;
400     argv++;
401   }
402
403   if (argc != 0) {
404     /*
405      * Extra command line arguments were specified; complain.
406      * XXX - interpret as capture filter, as tcpdump and tshark do?
407      */
408     cmdarg_err("Invalid argument: %s", argv[0]);
409     arg_error = TRUE;
410   }
411
412   if (arg_error) {
413     print_usage(FALSE);
414     exit_main(1);
415   }
416
417   if (run_once_args > 1) {
418     cmdarg_err("Only one of -D, -L, or -S may be supplied.");
419     exit_main(1);
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.");
426       exit_main(1);
427     }
428   } else {
429     /* No - was the ring buffer option specified and, if so, does it make
430        sense? */
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;
439       }
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;*/
444       }
445     }
446   }
447
448   if (capture_opts_trim_iface(capture_opts, NULL) == FALSE) {
449         cmdarg_err("No capture interfaces available (maybe lack of privileges?).");
450     exit_main(1);
451   }
452
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);
456
457   if (list_interfaces) {
458     status = capture_opts_list_interfaces(machine_readable);
459     exit_main(status);
460   } else if (list_link_layer_types) {
461     status = capture_opts_list_link_layer_types(capture_opts, machine_readable);
462     exit_main(status);
463   } else if (print_statistics) {
464     status = capture_opts_print_statistics(machine_readable);
465     exit_main(status);
466   }
467
468   capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
469   capture_opts_trim_ring_num_files(capture_opts);
470
471   /* Now start the capture. */
472
473   if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
474       /* capture ok */
475       exit_main(0);
476   } else {
477       /* capture failed */
478       exit_main(1);
479   }
480 }
481
482
483 static void
484 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
485                     const char *message, gpointer user_data _U_)
486 {
487   time_t curr;
488   struct tm *today;
489   const char *level;
490
491
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
495     return;
496 #endif
497   }
498
499   /* create a "timestamp" */
500   time(&curr);
501   today = localtime(&curr);
502
503   switch(log_level & G_LOG_LEVEL_MASK) {
504   case G_LOG_LEVEL_ERROR:
505     level = "Err ";
506     break;
507   case G_LOG_LEVEL_CRITICAL:
508     level = "Crit";
509     break;
510   case G_LOG_LEVEL_WARNING:
511     level = "Warn";
512     break;
513   case G_LOG_LEVEL_MESSAGE:
514     level = "Msg ";
515     break;
516   case G_LOG_LEVEL_INFO:
517     level = "Info";
518     break;
519   case G_LOG_LEVEL_DEBUG:
520     level = "Dbg ";
521     break;
522   default:
523     fprintf(stderr, "unknown log_level %u\n", log_level);
524     level = NULL;
525     g_assert_not_reached();
526   }
527
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);
532     fflush(stderr);
533   } else {
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 : "",
538             level, message);
539     fflush(stderr);
540   }
541 }
542
543
544 /****************************************************************************************************************/
545 /* indication report routines */
546
547
548 void
549 report_packet_count(int packet_count)
550 {
551     char tmp[SP_DECISIZE+1+1];
552     static int count = 0;
553
554     if(capture_child) {
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);
558     } else {
559         count += packet_count;
560         fprintf(stderr, "\rPackets: %u ", count);
561         /* stderr could be line buffered */
562         fflush(stderr);
563     }
564 }
565
566 void
567 report_new_capture_file(const char *filename)
568 {
569     if(capture_child) {
570         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "File: %s", filename);
571         pipe_write_block(1, SP_FILE, filename);
572     } else {
573         fprintf(stderr, "File: %s\n", filename);
574         /* stderr could be line buffered */
575         fflush(stderr);
576     }
577 }
578
579 void
580 report_cfilter_error(const char *cfilter, const char *errmsg)
581 {
582     if (capture_child) {
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);
585     } else {
586         fprintf(stderr,
587           "Invalid capture filter: \"%s\"!\n"
588           "\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",
591           cfilter, errmsg);
592     }
593 }
594
595 void
596 report_capture_error(const char *error_msg, const char *secondary_error_msg)
597 {
598     if(capture_child) {
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);
604     } else {
605         fprintf(stderr, "%s\n%s\n", error_msg, secondary_error_msg);
606     }
607 }
608
609 void
610 report_packet_drops(int drops)
611 {
612     char tmp[SP_DECISIZE+1+1];
613
614     g_snprintf(tmp, sizeof(tmp), "%d", drops);
615
616     if(capture_child) {
617         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets dropped: %s", tmp);
618         pipe_write_block(1, SP_DROPS, tmp);
619     } else {
620         fprintf(stderr, "Packets dropped: %s\n", tmp);
621         /* stderr could be line buffered */
622         fflush(stderr);
623     }
624 }
625
626
627 /****************************************************************************************************************/
628 /* signal_pipe handling */
629
630
631 #ifdef _WIN32
632 gboolean
633 signal_pipe_check_running(void)
634 {
635     /* any news from our parent (stdin)? -> just stop the capture */
636     HANDLE handle;
637     DWORD avail = 0;
638     gboolean result;
639
640
641     /* if we are running standalone, no check required */
642     if(!capture_child) {
643         return TRUE;
644     }
645
646     handle = (HANDLE) GetStdHandle(STD_INPUT_HANDLE);
647     result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
648
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);
656         return FALSE;
657     } else {
658         /* pipe ok and no bytes available */
659         return TRUE;
660     }
661 }
662 #endif