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.
50 #include <epan/packet.h>
51 #include <epan/dfilter/dfilter.h>
54 #include "capture_sync.h"
55 #include "capture_ui_utils.h"
57 #include "pcap-util.h"
58 #include "alert_box.h"
59 #include "simple_dialog.h"
60 #include <epan/prefs.h>
61 #include "conditions.h"
62 #include "ringbuffer.h"
65 #include "capture-wpcap.h"
70 /* Win32 needs the O_BINARY flag for open() */
75 static gboolean normal_do_capture(capture_options *capture_opts, gboolean is_tempfile);
76 static void stop_capture_signal_handler(int signo);
80 capture_opts_init(capture_options *capture_opts, void *cfile)
82 capture_opts->cf = cfile;
83 capture_opts->cfilter = g_strdup("");
84 capture_opts->iface = NULL;
86 capture_opts->buffer_size = 1; /* 1 MB */
88 capture_opts->has_snaplen = FALSE;
89 capture_opts->snaplen = MIN_PACKET_SIZE;
90 capture_opts->promisc_mode = TRUE;
91 capture_opts->linktype = -1; /* the default linktype */
92 capture_opts->capture_child = FALSE;
93 capture_opts->save_file = NULL;
94 capture_opts->save_file_fd = -1;
95 capture_opts->sync_mode = TRUE;
96 capture_opts->show_info = TRUE;
97 capture_opts->quit_after_cap = FALSE;
99 capture_opts->multi_files_on = FALSE;
100 capture_opts->has_file_duration = FALSE;
101 capture_opts->file_duration = 60; /* 1 min */
102 capture_opts->has_ring_num_files = TRUE;
103 capture_opts->ring_num_files = 2;
105 capture_opts->has_autostop_files = FALSE;
106 capture_opts->autostop_files = 1;
107 capture_opts->has_autostop_packets = FALSE;
108 capture_opts->autostop_packets = 1;
109 capture_opts->has_autostop_filesize = FALSE;
110 capture_opts->autostop_filesize = 1024 * 1024; /* 1 MB */
111 capture_opts->has_autostop_duration = FALSE;
112 capture_opts->autostop_duration = 60; /* 1 min */
117 get_natural_int(const char *string, const char *name)
122 number = strtol(string, &p, 10);
123 if (p == string || *p != '\0') {
124 fprintf(stderr, "ethereal: The specified %s \"%s\" isn't a decimal number\n",
129 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
133 if (number > INT_MAX) {
134 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
135 name, string, INT_MAX);
143 get_positive_int(const char *string, const char *name)
147 number = get_natural_int(string, name);
150 fprintf(stderr, "ethereal: The specified %s is zero\n",
160 * Given a string of the form "<autostop criterion>:<value>", as might appear
161 * as an argument to a "-a" option, parse it and set the criterion in
162 * question. Return an indication of whether it succeeded or failed
166 set_autostop_criterion(capture_options *capture_opts, const char *autostoparg)
170 colonp = strchr(autostoparg, ':');
178 * Skip over any white space (there probably won't be any, but
179 * as we allow it in the preferences file, we might as well
182 while (isspace((guchar)*p))
186 * Put the colon back, so if our caller uses, in an
187 * error message, the string they passed us, the message
193 if (strcmp(autostoparg,"duration") == 0) {
194 capture_opts->has_autostop_duration = TRUE;
195 capture_opts->autostop_duration = get_positive_int(p,"autostop duration");
196 } else if (strcmp(autostoparg,"filesize") == 0) {
197 capture_opts->has_autostop_filesize = TRUE;
198 capture_opts->autostop_filesize = get_positive_int(p,"autostop filesize");
202 *colonp = ':'; /* put the colon back */
207 * Given a string of the form "<ring buffer file>:<duration>", as might appear
208 * as an argument to a "-b" option, parse it and set the arguments in
209 * question. Return an indication of whether it succeeded or failed
213 get_ring_arguments(capture_options *capture_opts, const char *arg)
215 gchar *p = NULL, *colonp;
217 colonp = strchr(arg, ':');
219 if (colonp != NULL) {
224 capture_opts->ring_num_files =
225 get_natural_int(arg, "number of ring buffer files");
231 * Skip over any white space (there probably won't be any, but
232 * as we allow it in the preferences file, we might as well
235 while (isspace((guchar)*p))
239 * Put the colon back, so if our caller uses, in an
240 * error message, the string they passed us, the message
247 capture_opts->has_file_duration = TRUE;
248 capture_opts->file_duration = get_positive_int(p,
249 "ring buffer duration");
251 *colonp = ':'; /* put the colon back */
257 capture_opt_add(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture)
264 case 'a': /* autostop criteria */
265 if (set_autostop_criterion(capture_opts, optarg) == FALSE) {
266 fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
270 case 'b': /* Ringbuffer option */
271 capture_opts->multi_files_on = TRUE;
272 capture_opts->has_ring_num_files = TRUE;
273 if (get_ring_arguments(capture_opts, optarg) == FALSE) {
274 fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
278 case 'c': /* Capture xxx packets */
279 capture_opts->has_autostop_packets = TRUE;
280 capture_opts->autostop_packets = get_positive_int(optarg, "packet count");
282 case 'f': /* capture filter */
283 if (capture_opts->cfilter)
284 g_free(capture_opts->cfilter);
285 capture_opts->cfilter = g_strdup(optarg);
287 case 'H': /* Hide capture info dialog box */
288 capture_opts->show_info = FALSE;
290 case 'i': /* Use interface xxx */
291 capture_opts->iface = g_strdup(optarg);
293 case 'k': /* Start capture immediately */
294 *start_capture = TRUE;
296 /*case 'l':*/ /* Automatic scrolling in live capture mode */
297 case 'p': /* Don't capture in promiscuous mode */
298 capture_opts->promisc_mode = FALSE;
300 case 'Q': /* Quit after capture (just capture to file) */
301 capture_opts->quit_after_cap = TRUE;
302 *start_capture = TRUE; /*** -Q implies -k !! ***/
304 case 's': /* Set the snapshot (capture) length */
305 capture_opts->has_snaplen = TRUE;
306 capture_opts->snaplen = get_positive_int(optarg, "snapshot length");
308 case 'S': /* "Sync" mode: used for following file ala tail -f */
309 capture_opts->sync_mode = TRUE;
311 case 'w': /* Write to capture file xxx */
312 capture_opts->save_file = g_strdup(optarg);
314 case 'W': /* Write to capture file FD xxx */
315 capture_opts->save_file_fd = atoi(optarg);
317 case 'y': /* Set the pcap data link type */
318 #ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
319 capture_opts->linktype = pcap_datalink_name_to_val(optarg);
320 if (capture_opts->linktype == -1) {
321 fprintf(stderr, "ethereal: The specified data link type \"%s\" isn't valid\n",
325 #else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
326 /* XXX - just treat it as a number */
327 capture_opts->linktype = get_natural_int(optarg, "data link type");
328 #endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
331 /* Hidden option supporting Sync mode */
332 case 'Z': /* Write to pipe FD XXX */
333 /* associate stdout with pipe */
335 if (dup2(i, 1) < 0) {
336 fprintf(stderr, "Unable to dup pipe handle\n");
342 /* the caller is responsible to send us only the right opt's */
343 g_assert_not_reached();
347 /* open the output file (temporary/specified name/ringbuffer) and close the old one */
348 /* Returns TRUE if the file opened successfully, FALSE otherwise. */
350 capture_open_output(capture_options *capture_opts, gboolean *is_tempfile) {
355 if (capture_opts->save_file != NULL) {
356 /* If the Sync option is set, we return to the caller while the capture
357 * is in progress. Therefore we need to take a copy of save_file in
358 * case the caller destroys it after we return.
360 capfile_name = g_strdup(capture_opts->save_file);
361 if (capture_opts->multi_files_on) {
362 /* ringbuffer is enabled */
363 capture_opts->save_file_fd = ringbuf_init(capfile_name,
364 (capture_opts->has_ring_num_files) ? capture_opts->ring_num_files : 0);
366 /* Try to open/create the specified file for use as a capture buffer. */
367 capture_opts->save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
370 *is_tempfile = FALSE;
372 /* Choose a random name for the temporary capture buffer */
373 capture_opts->save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
374 capfile_name = g_strdup(tmpname);
378 /* did we fail to open the output file? */
379 if (capture_opts->save_file_fd == -1) {
381 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
382 "The temporary file to which the capture would be saved (\"%s\")"
383 "could not be opened: %s.", capfile_name, strerror(errno));
385 if (capture_opts->multi_files_on) {
386 ringbuf_error_cleanup();
388 open_failure_alert_box(capfile_name, errno, TRUE);
390 g_free(capfile_name);
394 /* close the old file */
395 cf_close(capture_opts->cf);
396 if(capture_opts->save_file != NULL) {
397 g_free(capture_opts->save_file);
399 capture_opts->save_file = capfile_name;
400 /* capture_opts.save_file is "g_free"ed later, which is equivalent to
401 "g_free(capfile_name)". */
407 /* Open a specified file, or create a temporary file, and start a capture
408 to the file in question. */
409 /* Returns TRUE if the capture starts successfully, FALSE otherwise. */
411 do_capture(capture_options *capture_opts)
413 gboolean is_tempfile;
416 /* open the output file (temporary/specified name/ringbuffer) and close the old one */
417 if(!capture_open_output(capture_opts, &is_tempfile)) {
421 if (capture_opts->sync_mode) {
422 /* sync mode: do the capture in a child process */
423 ret = sync_pipe_do_capture(capture_opts, is_tempfile);
424 /* capture is still running */
425 cf_callback_invoke(cf_cb_live_capture_prepare, capture_opts);
427 /* normal mode: do the capture synchronously */
428 cf_callback_invoke(cf_cb_live_capture_prepare, capture_opts);
429 ret = normal_do_capture(capture_opts, is_tempfile);
430 /* capture is finished here */
437 /* start a normal capture session */
439 normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
441 int capture_succeeded;
442 gboolean stats_known;
443 struct pcap_stat stats;
447 capture_succeeded = capture_start(capture_opts, &stats_known, &stats);
448 if (capture_opts->quit_after_cap) {
449 /* DON'T unlink the save file. Presumably someone wants it. */
452 if (!capture_succeeded) {
453 /* We didn't succeed in doing the capture, so we don't have a save
455 if (capture_opts->multi_files_on) {
458 g_free(capture_opts->save_file);
460 capture_opts->save_file = NULL;
463 /* Capture succeeded; attempt to read in the capture file. */
464 if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
465 /* We're not doing a capture any more, so we don't have a save
467 if (capture_opts->multi_files_on) {
470 g_free(capture_opts->save_file);
472 capture_opts->save_file = NULL;
476 /* Set the read filter to NULL. */
477 cf_set_rfcode(capture_opts->cf, NULL);
479 /* Get the packet-drop statistics.
481 XXX - there are currently no packet-drop statistics stored
482 in libpcap captures, and that's what we're reading.
484 At some point, we will add support in Wiretap to return
485 packet-drop statistics for capture file formats that store it,
486 and will make "cf_read()" get those statistics from Wiretap.
487 We clear the statistics (marking them as "not known") in
488 "cf_open()", and "cf_read()" will only fetch them and mark
489 them as known if Wiretap supplies them, so if we get the
490 statistics now, after calling "cf_open()" but before calling
491 "cf_read()", the values we store will be used by "cf_read()".
493 If a future libpcap capture file format stores the statistics,
494 we'll put them into the capture file that we write, and will
495 thus not have to set them here - "cf_read()" will get them from
496 the file and use them. */
498 cf_set_drops_known(capture_opts->cf, TRUE);
500 /* XXX - on some systems, libpcap doesn't bother filling in
501 "ps_ifdrop" - it doesn't even set it to zero - so we don't
502 bother looking at it.
504 Ideally, libpcap would have an interface that gave us
505 several statistics - perhaps including various interface
506 error statistics - and would tell us which of them it
507 supplies, allowing us to display only the ones it does. */
508 cf_set_drops(capture_opts->cf, stats.ps_drop);
510 switch (cf_read(capture_opts->cf)) {
514 /* Just because we got an error, that doesn't mean we were unable
515 to read any of the file; we handle what we could get from the
519 case CF_READ_ABORTED:
520 /* Exit by leaving the main loop, so that any quit functions
521 we registered get called. */
522 main_window_nested_quit();
526 /* We're not doing a capture any more, so we don't have a save
528 if (capture_opts->multi_files_on) {
531 g_free(capture_opts->save_file);
533 capture_opts->save_file = NULL;
535 /* if we didn't captured even a single packet, close the file again */
536 if(cf_packet_count(capture_opts->cf) == 0) {
537 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
538 "%sNo packets captured!%s\n\n"
539 "As no data was captured, closing the %scapture file!",
540 simple_dialog_primary_start(), simple_dialog_primary_end(),
541 (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
542 cf_close(capture_opts->cf);
549 stop_capture_signal_handler(int signo _U_)
556 capture_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
560 * Catch SIGUSR1, so that we exit cleanly if the parent process
561 * kills us with it due to the user selecting "Capture->Stop".
563 if (capture_opts->capture_child)
564 signal(SIGUSR1, stop_capture_signal_handler);
567 return capture_loop_start(capture_opts, stats_known, stats);
571 capture_stop(capture_options *capture_opts)
574 if (capture_opts->sync_mode) {
575 sync_pipe_stop(capture_opts);
582 capture_kill_child(capture_options *capture_opts)
584 if (capture_opts->sync_mode) {
585 sync_pipe_kill(capture_opts);
590 #endif /* HAVE_LIBPCAP */