2 * Routines for packet capture windows
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 /* With MSVC and a libethereal.dll this file needs to import some variables
26 in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
27 #define _NEED_VAR_IMPORT_
54 #include <epan/packet.h>
55 #include <epan/dfilter/dfilter.h>
58 #include "capture_sync.h"
59 #include "capture_ui_utils.h"
61 #include "pcap-util.h"
62 #include "alert_box.h"
63 #include "simple_dialog.h"
64 #include <epan/prefs.h>
65 #include "conditions.h"
66 #include "ringbuffer.h"
69 #include "capture-wpcap.h"
74 /* Win32 needs the O_BINARY flag for open() */
79 static gboolean normal_do_capture(capture_options *capture_opts, gboolean is_tempfile);
80 static void stop_capture_signal_handler(int signo);
84 capture_opts_init(capture_options *capture_opts, void *cfile)
86 capture_opts->cf = cfile;
87 capture_opts->cfilter = g_strdup("");
88 capture_opts->iface = NULL;
90 capture_opts->buffer_size = 1; /* 1 MB */
92 capture_opts->has_snaplen = FALSE;
93 capture_opts->snaplen = MIN_PACKET_SIZE;
94 capture_opts->promisc_mode = TRUE;
95 capture_opts->linktype = -1; /* the default linktype */
96 capture_opts->capture_child = FALSE;
97 capture_opts->save_file = NULL;
98 capture_opts->save_file_fd = -1;
99 capture_opts->sync_mode = TRUE;
100 capture_opts->show_info = TRUE;
101 capture_opts->quit_after_cap = FALSE;
103 capture_opts->multi_files_on = FALSE;
104 capture_opts->has_file_duration = FALSE;
105 capture_opts->file_duration = 60; /* 1 min */
106 capture_opts->has_ring_num_files = TRUE;
107 capture_opts->ring_num_files = 2;
109 capture_opts->has_autostop_files = FALSE;
110 capture_opts->autostop_files = 1;
111 capture_opts->has_autostop_packets = FALSE;
112 capture_opts->autostop_packets = 1;
113 capture_opts->has_autostop_filesize = FALSE;
114 capture_opts->autostop_filesize = 1024 * 1024; /* 1 MB */
115 capture_opts->has_autostop_duration = FALSE;
116 capture_opts->autostop_duration = 60; /* 1 min */
121 get_natural_int(const char *string, const char *name)
126 number = strtol(string, &p, 10);
127 if (p == string || *p != '\0') {
128 fprintf(stderr, "ethereal: The specified %s \"%s\" isn't a decimal number\n",
133 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
137 if (number > INT_MAX) {
138 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
139 name, string, INT_MAX);
147 get_positive_int(const char *string, const char *name)
151 number = get_natural_int(string, name);
154 fprintf(stderr, "ethereal: The specified %s is zero\n",
164 * Given a string of the form "<autostop criterion>:<value>", as might appear
165 * as an argument to a "-a" option, parse it and set the criterion in
166 * question. Return an indication of whether it succeeded or failed
170 set_autostop_criterion(capture_options *capture_opts, const char *autostoparg)
174 colonp = strchr(autostoparg, ':');
182 * Skip over any white space (there probably won't be any, but
183 * as we allow it in the preferences file, we might as well
186 while (isspace((guchar)*p))
190 * Put the colon back, so if our caller uses, in an
191 * error message, the string they passed us, the message
197 if (strcmp(autostoparg,"duration") == 0) {
198 capture_opts->has_autostop_duration = TRUE;
199 capture_opts->autostop_duration = get_positive_int(p,"autostop duration");
200 } else if (strcmp(autostoparg,"filesize") == 0) {
201 capture_opts->has_autostop_filesize = TRUE;
202 capture_opts->autostop_filesize = get_positive_int(p,"autostop filesize");
206 *colonp = ':'; /* put the colon back */
211 * Given a string of the form "<ring buffer file>:<duration>", as might appear
212 * as an argument to a "-b" option, parse it and set the arguments in
213 * question. Return an indication of whether it succeeded or failed
217 get_ring_arguments(capture_options *capture_opts, const char *arg)
219 gchar *p = NULL, *colonp;
221 colonp = strchr(arg, ':');
223 if (colonp != NULL) {
228 capture_opts->ring_num_files =
229 get_natural_int(arg, "number of ring buffer files");
235 * Skip over any white space (there probably won't be any, but
236 * as we allow it in the preferences file, we might as well
239 while (isspace((guchar)*p))
243 * Put the colon back, so if our caller uses, in an
244 * error message, the string they passed us, the message
251 capture_opts->has_file_duration = TRUE;
252 capture_opts->file_duration = get_positive_int(p,
253 "ring buffer duration");
255 *colonp = ':'; /* put the colon back */
261 capture_opt_add(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture)
268 case 'a': /* autostop criteria */
269 if (set_autostop_criterion(capture_opts, optarg) == FALSE) {
270 fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
274 case 'b': /* Ringbuffer option */
275 capture_opts->multi_files_on = TRUE;
276 capture_opts->has_ring_num_files = TRUE;
277 if (get_ring_arguments(capture_opts, optarg) == FALSE) {
278 fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
282 case 'c': /* Capture xxx packets */
283 capture_opts->has_autostop_packets = TRUE;
284 capture_opts->autostop_packets = get_positive_int(optarg, "packet count");
286 case 'f': /* capture filter */
287 if (capture_opts->cfilter)
288 g_free(capture_opts->cfilter);
289 capture_opts->cfilter = g_strdup(optarg);
291 case 'H': /* Hide capture info dialog box */
292 capture_opts->show_info = FALSE;
294 case 'i': /* Use interface xxx */
295 capture_opts->iface = g_strdup(optarg);
297 case 'k': /* Start capture immediately */
298 *start_capture = TRUE;
300 /*case 'l':*/ /* Automatic scrolling in live capture mode */
301 case 'p': /* Don't capture in promiscuous mode */
302 capture_opts->promisc_mode = FALSE;
304 case 'Q': /* Quit after capture (just capture to file) */
305 capture_opts->quit_after_cap = TRUE;
306 *start_capture = TRUE; /*** -Q implies -k !! ***/
308 case 's': /* Set the snapshot (capture) length */
309 capture_opts->has_snaplen = TRUE;
310 capture_opts->snaplen = get_positive_int(optarg, "snapshot length");
312 case 'S': /* "Sync" mode: used for following file ala tail -f */
313 capture_opts->sync_mode = TRUE;
315 case 'w': /* Write to capture file xxx */
316 capture_opts->save_file = g_strdup(optarg);
318 case 'W': /* Write to capture file FD xxx */
319 capture_opts->save_file_fd = atoi(optarg);
321 case 'y': /* Set the pcap data link type */
322 #ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
323 capture_opts->linktype = pcap_datalink_name_to_val(optarg);
324 if (capture_opts->linktype == -1) {
325 fprintf(stderr, "ethereal: The specified data link type \"%s\" isn't valid\n",
329 #else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
330 /* XXX - just treat it as a number */
331 capture_opts->linktype = get_natural_int(optarg, "data link type");
332 #endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
335 /* Hidden option supporting Sync mode */
336 case 'Z': /* Write to pipe FD XXX */
337 /* associate stdout with pipe */
339 if (dup2(i, 1) < 0) {
340 fprintf(stderr, "Unable to dup pipe handle\n");
346 /* the caller is responsible to send us only the right opt's */
347 g_assert_not_reached();
351 /* open the output file (temporary/specified name/ringbuffer) and close the old one */
352 /* Returns TRUE if the file opened successfully, FALSE otherwise. */
354 capture_open_output(capture_options *capture_opts, gboolean *is_tempfile) {
359 if (capture_opts->save_file != NULL) {
360 /* If the Sync option is set, we return to the caller while the capture
361 * is in progress. Therefore we need to take a copy of save_file in
362 * case the caller destroys it after we return.
364 capfile_name = g_strdup(capture_opts->save_file);
365 if (capture_opts->multi_files_on) {
366 /* ringbuffer is enabled */
367 capture_opts->save_file_fd = ringbuf_init(capfile_name,
368 (capture_opts->has_ring_num_files) ? capture_opts->ring_num_files : 0);
370 /* Try to open/create the specified file for use as a capture buffer. */
371 capture_opts->save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
374 *is_tempfile = FALSE;
376 /* Choose a random name for the temporary capture buffer */
377 capture_opts->save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
378 capfile_name = g_strdup(tmpname);
382 /* did we fail to open the output file? */
383 if (capture_opts->save_file_fd == -1) {
385 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
386 "The temporary file to which the capture would be saved (\"%s\")"
387 "could not be opened: %s.", capfile_name, strerror(errno));
389 if (capture_opts->multi_files_on) {
390 ringbuf_error_cleanup();
392 open_failure_alert_box(capfile_name, errno, TRUE);
394 g_free(capfile_name);
398 /* close the old file */
399 cf_close(capture_opts->cf);
400 if(capture_opts->save_file != NULL) {
401 g_free(capture_opts->save_file);
403 capture_opts->save_file = capfile_name;
404 /* capture_opts.save_file is "g_free"ed later, which is equivalent to
405 "g_free(capfile_name)". */
411 /* Open a specified file, or create a temporary file, and start a capture
412 to the file in question. */
413 /* Returns TRUE if the capture starts successfully, FALSE otherwise. */
415 do_capture(capture_options *capture_opts)
417 gboolean is_tempfile;
420 /* open the output file (temporary/specified name/ringbuffer) and close the old one */
421 if(!capture_open_output(capture_opts, &is_tempfile)) {
425 if (capture_opts->sync_mode) {
426 /* sync mode: do the capture in a child process */
427 ret = sync_pipe_do_capture(capture_opts, is_tempfile);
428 /* capture is still running */
429 cf_callback_invoke(cf_cb_live_capture_started, capture_opts);
431 /* normal mode: do the capture synchronously */
432 cf_callback_invoke(cf_cb_live_capture_started, capture_opts);
433 ret = normal_do_capture(capture_opts, is_tempfile);
434 /* capture is finished here */
441 /* start a normal capture session */
443 normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
445 int capture_succeeded;
446 gboolean stats_known;
447 struct pcap_stat stats;
451 capture_succeeded = capture_start(capture_opts, &stats_known, &stats);
452 if (capture_opts->quit_after_cap) {
453 /* DON'T unlink the save file. Presumably someone wants it. */
456 if (!capture_succeeded) {
457 /* We didn't succeed in doing the capture, so we don't have a save
459 if (capture_opts->multi_files_on) {
462 g_free(capture_opts->save_file);
464 capture_opts->save_file = NULL;
467 /* Capture succeeded; attempt to read in the capture file. */
468 if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
469 /* We're not doing a capture any more, so we don't have a save
471 if (capture_opts->multi_files_on) {
474 g_free(capture_opts->save_file);
476 capture_opts->save_file = NULL;
480 /* Set the read filter to NULL. */
481 cf_set_rfcode(capture_opts->cf, NULL);
483 /* Get the packet-drop statistics.
485 XXX - there are currently no packet-drop statistics stored
486 in libpcap captures, and that's what we're reading.
488 At some point, we will add support in Wiretap to return
489 packet-drop statistics for capture file formats that store it,
490 and will make "cf_read()" get those statistics from Wiretap.
491 We clear the statistics (marking them as "not known") in
492 "cf_open()", and "cf_read()" will only fetch them and mark
493 them as known if Wiretap supplies them, so if we get the
494 statistics now, after calling "cf_open()" but before calling
495 "cf_read()", the values we store will be used by "cf_read()".
497 If a future libpcap capture file format stores the statistics,
498 we'll put them into the capture file that we write, and will
499 thus not have to set them here - "cf_read()" will get them from
500 the file and use them. */
502 cf_set_drops_known(capture_opts->cf, TRUE);
504 /* XXX - on some systems, libpcap doesn't bother filling in
505 "ps_ifdrop" - it doesn't even set it to zero - so we don't
506 bother looking at it.
508 Ideally, libpcap would have an interface that gave us
509 several statistics - perhaps including various interface
510 error statistics - and would tell us which of them it
511 supplies, allowing us to display only the ones it does. */
512 cf_set_drops(capture_opts->cf, stats.ps_drop);
514 switch (cf_read(capture_opts->cf)) {
518 /* Just because we got an error, that doesn't mean we were unable
519 to read any of the file; we handle what we could get from the
523 case CF_READ_ABORTED:
524 /* Exit by leaving the main loop, so that any quit functions
525 we registered get called. */
526 main_window_nested_quit();
530 /* We're not doing a capture any more, so we don't have a save
532 if (capture_opts->multi_files_on) {
535 g_free(capture_opts->save_file);
537 capture_opts->save_file = NULL;
539 /* if we didn't captured even a single packet, close the file again */
540 if(cf_packet_count(capture_opts->cf) == 0) {
541 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
542 "%sNo packets captured!%s\n\n"
543 "As no data was captured, closing the %scapture file!",
544 simple_dialog_primary_start(), simple_dialog_primary_end(),
545 (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
546 cf_close(capture_opts->cf);
553 stop_capture_signal_handler(int signo _U_)
560 capture_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
564 * Catch SIGUSR1, so that we exit cleanly if the parent process
565 * kills us with it due to the user selecting "Capture->Stop".
567 if (capture_opts->capture_child)
568 signal(SIGUSR1, stop_capture_signal_handler);
571 return capture_loop_start(capture_opts, stats_known, stats);
575 capture_stop(capture_options *capture_opts)
578 if (capture_opts->sync_mode) {
579 sync_pipe_stop(capture_opts);
586 capture_kill_child(capture_options *capture_opts)
588 if (capture_opts->sync_mode) {
589 sync_pipe_kill(capture_opts);
594 #endif /* HAVE_LIBPCAP */