Fix for bug 1178. Allow FT_?INT24 BASE_DEC VALs in the expression selection dialog.
[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 <glib.h>
29
30 #include <string.h>
31 #include <ctype.h>
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #ifdef NEED_GETOPT_H
38 #include "getopt.h"
39 #endif
40
41 #ifdef HAVE_NETDB_H
42 #include <netdb.h>
43 #endif
44
45 #include "ringbuffer.h"
46 #include "clopts_common.h"
47 #include "cmdarg_err.h"
48 #include "version_info.h"
49
50 #include <pcap.h>
51 #include "capture-pcap-util.h"
52
53 #ifdef _WIN32
54 #include "capture-wpcap.h"
55 #endif
56
57 #include "sync_pipe.h"
58
59 #include "capture.h"
60 #include "capture_loop.h"
61 #include "capture_sync.h"
62
63 #include "simple_dialog.h"
64 #include "util.h"
65 #include "log.h"
66 #include "file_util.h"
67
68
69 /*#define DEBUG_DUMPCAP*/
70
71 gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */
72
73 static void
74 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
75                     const char *message, gpointer user_data _U_);
76
77 /* capture related options */
78 capture_options global_capture_opts;
79 capture_options *capture_opts = &global_capture_opts;
80
81 #if __GNUC__ >= 2
82 void exit_main(int err) __attribute__ ((noreturn));
83 #else
84 void exit_main(int err);
85 #endif
86
87
88 static void
89 print_usage(gboolean print_ver) {
90
91   FILE *output;
92
93
94   if (print_ver) {
95     output = stdout;
96     fprintf(output,
97         "Dumpcap " VERSION "%s\n"
98         "Capture network packets and dump them into a libpcap file.\n"
99         "See http://www.wireshark.org for more information.\n",
100         svnversion);
101   } else {
102     output = stderr;
103   }
104   fprintf(output, "\nUsage: dumpcap [options] ...\n");
105   fprintf(output, "\n");
106   fprintf(output, "Capture interface:\n");
107   fprintf(output, "  -i <interface>           name or idx of interface (def: first none loopback)\n");
108   fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
109   fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
110   fprintf(output, "  -p                       don't capture in promiscuous mode\n");
111 #ifdef _WIN32
112   fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
113 #endif
114   fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
115   fprintf(output, "  -D                       print list of interfaces and exit\n");
116   fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
117   fprintf(output, "\n");
118   fprintf(output, "Stop conditions:\n");
119   fprintf(output, "  -c <packet count>        stop after n packets (def: infinite)\n");
120   fprintf(output, "  -a <autostop cond.> ...  duration:NUM - stop after NUM seconds\n");
121   fprintf(output, "                           filesize:NUM - stop this file after NUM KB\n");
122   fprintf(output, "                              files:NUM - stop after NUM files\n");
123   /*fprintf(output, "\n");*/
124   fprintf(output, "Output (files):\n");
125   fprintf(output, "  -w <filename>            name of file to save (def: tempfile)\n");
126   fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
127   fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
128   fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
129   /*fprintf(output, "\n");*/
130   fprintf(output, "Miscellaneous:\n");
131   fprintf(output, "  -v                       print version information and exit\n");
132   fprintf(output, "  -h                       display this help and exit\n");
133   fprintf(output, "\n");
134   fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcap\n");
135   fprintf(output, "\"Capture network packets from interface eth0 until 60s passed into output.pcap\"\n");
136   fprintf(output, "\n");
137   fprintf(output, "Use Ctrl-C to stop capturing at any time.\n");
138 }
139
140 static void
141 show_version(GString *comp_info_str, GString *runtime_info_str)
142 {
143
144   printf(
145         "Dumpcap " VERSION "%s\n"
146         "\n"
147         "%s\n"
148         "%s\n"
149         "%s\n"
150         "See http://www.wireshark.org for more information.\n",
151         svnversion, get_copyright_info() ,comp_info_str->str, runtime_info_str->str);
152 }
153
154 /*
155  * Report an error in command-line arguments.
156  */
157 void
158 cmdarg_err(const char *fmt, ...)
159 {
160   va_list ap;
161
162   if(capture_child) {
163     /* XXX - convert to g_log */
164   } else {
165     va_start(ap, fmt);
166     fprintf(stderr, "dumpcap: ");
167     vfprintf(stderr, fmt, ap);
168     fprintf(stderr, "\n");
169     va_end(ap);
170   }
171 }
172
173 /*
174  * Report additional information for an error in command-line arguments.
175  */
176 void
177 cmdarg_err_cont(const char *fmt, ...)
178 {
179   va_list ap;
180
181   if(capture_child) {
182     /* XXX - convert to g_log */
183   } else {
184     va_start(ap, fmt);
185     vfprintf(stderr, fmt, ap);
186     fprintf(stderr, "\n");
187     va_end(ap);
188   }
189 }
190
191
192 #ifdef _WIN32
193 BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
194 {
195     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
196         "Console: Control signal");
197     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
198         "Console: Control signal, CtrlType: %u", dwCtrlType);
199
200     /* Keep capture running if we're a service and a user logs off */
201     if (capture_child || (dwCtrlType != CTRL_LOGOFF_EVENT)) {
202         capture_loop_stop();
203         return TRUE;
204     } else {
205         return FALSE;
206     }
207 }
208 #endif
209
210 void exit_main(int status)
211 {
212 #ifdef _WIN32
213   /* Shutdown windows sockets */
214   WSACleanup();
215
216   /* can be helpful for debugging */
217 #ifdef DEBUG_DUMPCAP
218   printf("Press any key\n");
219   _getch();
220 #endif
221
222 #endif /* _WIN32 */
223
224   exit(status);
225 }
226
227
228 /* And now our feature presentation... [ fade to music ] */
229 int
230 main(int argc, char *argv[])
231 {
232   int                  opt;
233   extern char         *optarg;
234   gboolean             arg_error = FALSE;
235   GString             *comp_info_str;
236   GString             *runtime_info_str;
237
238 #ifdef _WIN32
239   WSADATA              wsaData;
240 #endif  /* _WIN32 */
241
242   gboolean             start_capture = TRUE;
243   gboolean             stats_known;
244   struct pcap_stat     stats;
245   GLogLevelFlags       log_flags;
246   gboolean             list_link_layer_types = FALSE;
247   int                  status;
248
249 #define OPTSTRING_INIT "a:b:c:Df:hi:Lps:vw:y:Z"
250
251 #ifdef _WIN32
252 #define OPTSTRING_WIN32 "B:"
253 #else
254 #define OPTSTRING_WIN32 ""
255 #endif  /* _WIN32 */
256
257   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
258     OPTSTRING_INIT OPTSTRING_WIN32;
259
260 #ifdef _WIN32
261   /* Load wpcap if possible. Do this before collecting the run-time version information */
262   load_wpcap();
263
264   /* ... and also load the packet.dll from wpcap */
265   /* XXX - currently not required, may change later. */
266   /*wpcap_packet_load();*/
267
268   /* Start windows sockets */
269   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
270
271   /* Set handler for Ctrl+C key */
272   SetConsoleCtrlHandler(&ConsoleCtrlHandlerRoutine, TRUE);
273 #endif  /* _WIN32 */
274
275   /* Assemble the compile-time version information string */
276   comp_info_str = g_string_new("Compiled ");
277   get_compiled_version_info(comp_info_str, NULL);
278
279   /* Assemble the run-time version information string */
280   runtime_info_str = g_string_new("Running ");
281   get_runtime_version_info(runtime_info_str, NULL);
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         show_version(comp_info_str, runtime_info_str);
329         exit_main(0);
330         break;
331       /*** capture option specific ***/
332       case 'a':        /* autostop criteria */
333       case 'b':        /* Ringbuffer option */
334       case 'c':        /* Capture x packets */
335       case 'f':        /* capture filter */
336       case 'i':        /* Use interface x */
337       case 'p':        /* Don't capture in promiscuous mode */
338       case 's':        /* Set the snapshot (capture) length */
339       case 'w':        /* Write to capture file x */
340       case 'y':        /* Set the pcap data link type */
341 #ifdef _WIN32
342       case 'B':        /* Buffer size */
343 #endif /* _WIN32 */
344         status = capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
345         if(status != 0) {
346             exit_main(status);
347         }
348         break;
349       /*** hidden option: Wireshark child mode (using binary output messages) ***/
350       case 'Z':
351           capture_child = TRUE;
352 #ifdef _WIN32
353           /* set output pipe to binary mode, to avoid ugly text conversions */
354                   _setmode(1, O_BINARY);
355 #endif
356           break;
357
358       /*** all non capture option specific ***/
359       case 'D':        /* Print a list of capture devices and exit */
360         status = capture_opts_list_interfaces();
361         exit_main(status);
362         break;
363       case 'L':        /* Print list of link-layer types and exit */
364         list_link_layer_types = TRUE;
365         break;
366       default:
367       case '?':        /* Bad flag - print usage message */
368         cmdarg_err("Invalid Option: %s", argv[optind-1]);
369         arg_error = TRUE;
370         break;
371     }
372   }
373   argc -= optind;
374   argv += optind;
375   if (argc >= 1) {
376       /* user specified file name as regular command-line argument */
377       /* XXX - use it as the capture file name (or something else)? */
378     argc--;
379     argv++;
380   }
381
382   if (argc != 0) {
383     /*
384      * Extra command line arguments were specified; complain.
385      * XXX - interpret as capture filter, as tcpdump and tshark do?
386      */
387     cmdarg_err("Invalid argument: %s", argv[0]);
388     arg_error = TRUE;
389   }
390
391   if (arg_error) {
392     print_usage(FALSE);
393     exit_main(1);
394   }
395
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.");
402       exit_main(1);
403     }
404   } else {
405     /* No - was the ring buffer option specified and, if so, does it make
406        sense? */
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;
415       }
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;*/
420       }
421     }
422   }
423
424   if (capture_opts_trim_iface(capture_opts, NULL) == FALSE) {
425         cmdarg_err("No capture interfaces available (maybe lack of privileges?).");
426     exit_main(1);
427   }
428
429   /* Let the user know what interface was chosen. */
430   /* get_interface_descriptive_name() is not available! */
431   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Interface: %s\n", capture_opts->iface);
432
433   if (list_link_layer_types) {
434     status = capture_opts_list_link_layer_types(capture_opts);
435     exit_main(status);
436   }
437
438   capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
439   capture_opts_trim_ring_num_files(capture_opts);
440
441   /* Now start the capture. */
442
443   if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
444       /* capture ok */
445       exit_main(0);
446   } else {
447       /* capture failed */
448       exit_main(1);
449   }
450 }
451
452
453 static void
454 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
455                     const char *message, gpointer user_data _U_)
456 {
457   time_t curr;
458   struct tm *today;
459   const char *level;
460
461
462   /* ignore log message, if log_level isn't interesting */
463   if( !(log_level & G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG|G_LOG_LEVEL_INFO))) {
464 #ifndef DEBUG_DUMPCAP
465     return;
466 #endif
467   }
468
469   /* create a "timestamp" */
470   time(&curr);
471   today = localtime(&curr);    
472
473   switch(log_level & G_LOG_LEVEL_MASK) {
474   case G_LOG_LEVEL_ERROR:
475     level = "Err ";
476     break;
477   case G_LOG_LEVEL_CRITICAL:
478     level = "Crit";
479     break;
480   case G_LOG_LEVEL_WARNING:
481     level = "Warn";
482     break;
483   case G_LOG_LEVEL_MESSAGE:
484     level = "Msg ";
485     break;
486   case G_LOG_LEVEL_INFO:
487     level = "Info";
488     break;
489   case G_LOG_LEVEL_DEBUG:
490     level = "Dbg ";
491     break;
492   default:
493     fprintf(stderr, "unknown log_level %u\n", log_level);
494     level = NULL;
495     g_assert_not_reached();
496   }
497
498   /* don't use printf (stdout), in child mode we're using stdout for the sync_pipe */
499   if(log_level & G_LOG_LEVEL_MESSAGE) {
500     /* normal user messages without additional infos */
501     fprintf(stderr, "%s\n", message);
502     fflush(stderr);
503   } else {
504     /* info/debug messages with additional infos */
505     fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
506             today->tm_hour, today->tm_min, today->tm_sec,
507             log_domain != NULL ? log_domain : "",
508             level, message);
509     fflush(stderr);
510   }
511 }
512
513
514 /****************************************************************************************************************/
515 /* indication report routines */
516
517
518 void
519 report_packet_count(int packet_count)
520 {
521     char tmp[SP_DECISIZE+1+1];
522     static int count = 0;
523
524
525     if(capture_child) {
526         g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
527         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp);
528         pipe_write_block(1, SP_PACKET_COUNT, tmp);
529     } else {
530         count += packet_count;
531         fprintf(stderr, "\rPackets: %u ", count);
532         /* stderr could be line buffered */
533         fflush(stderr);
534     }
535 }
536
537 void
538 report_new_capture_file(const char *filename)
539 {
540
541     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "File: %s", filename);
542
543     if(capture_child) {
544         pipe_write_block(1, SP_FILE, filename);
545     }
546 }
547
548 void
549 report_cfilter_error(const char *cfilter _U_, const char *errmsg)
550 {
551
552     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Capture filter error: %s", errmsg);
553
554     if (capture_child) {
555         pipe_write_block(1, SP_BAD_FILTER, errmsg);
556     }
557 }
558
559 void
560 report_capture_error(const char *error_msg, const char *secondary_error_msg)
561 {
562
563     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, 
564         "Primary Error: %s", error_msg);
565     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, 
566         "Secondary Error: %s", secondary_error_msg);
567
568     if(capture_child) {
569         sync_pipe_errmsg_to_parent(error_msg, secondary_error_msg);
570     }
571 }
572
573 void
574 report_packet_drops(int drops)
575 {
576     char tmp[SP_DECISIZE+1+1];
577
578
579     g_snprintf(tmp, sizeof(tmp), "%d", drops);
580     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets dropped: %s", tmp);
581
582     if(capture_child) {
583         pipe_write_block(1, SP_DROPS, tmp);
584     }
585 }
586
587
588 /****************************************************************************************************************/
589 /* signal_pipe handling */
590
591
592 #ifdef _WIN32
593 gboolean
594 signal_pipe_check_running(void)
595 {
596     /* any news from our parent (stdin)? -> just stop the capture */
597     HANDLE handle;
598     DWORD avail = 0;
599     gboolean result;
600
601
602     /* if we are running standalone, no check required */
603     if(!capture_child) {
604         return TRUE;
605     }
606
607     handle = (HANDLE) GetStdHandle(STD_INPUT_HANDLE);
608     result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
609
610     if(!result || avail > 0) {
611         /* peek failed or some bytes really available */
612         /* (if not piping from stdin this would fail) */
613         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
614             "Signal pipe: Stop capture");
615         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
616             "Signal pipe: handle: %x result: %u avail: %u", handle, result, avail);
617         return FALSE;
618     } else {
619         /* pipe ok and no bytes available */
620         return TRUE;
621     }
622 }
623 #endif
624
625
626 /****************************************************************************************************************/
627 /* Stub functions */
628
629
630 const char *netsnmp_get_version(void) { return ""; }
631