Dumpcap+Qt: Add support for `-a packets:NUM` and `-b packets:NUM`.

Add the ability to rotate files after a specified number of packets (`-b
packets:NUM`). Move some condition checks to capture_loop_write_packet_cb.

Add `-a packets:NUM` in order to be consistent. It is functionally
equivalent to the `-c` flag.

Add a corresponding "packets" option to the Capture Interfaces dialog
Output tab.

Add initial tests for autostop and ringbuffer conditions.

Change-Id: I66eb968927ed287deb8edb96db96d7c73526c257
Reviewed-on: https://code.wireshark.org/review/30534
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Gerald Combs 2018-10-31 10:03:04 +01:00 committed by Anders Broman
parent 9b6b36beae
commit 11a9a501fb
12 changed files with 348 additions and 167 deletions

View File

@ -194,26 +194,6 @@ init_pipe_args(int *argc) {
gboolean
sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, info_data_t* cap_data, void (*update_cb)(void))
{
char ssnap[ARGV_NUMBER_LEN];
char scount[ARGV_NUMBER_LEN];
char sfilesize[ARGV_NUMBER_LEN];
char sfile_duration[ARGV_NUMBER_LEN];
char sfile_interval[ARGV_NUMBER_LEN];
char sring_num_files[ARGV_NUMBER_LEN];
char sautostop_files[ARGV_NUMBER_LEN];
char sautostop_filesize[ARGV_NUMBER_LEN];
char sautostop_duration[ARGV_NUMBER_LEN];
#ifdef HAVE_PCAP_REMOTE
char sauth[256];
#endif
#ifdef HAVE_PCAP_SETSAMPLING
char ssampling[ARGV_NUMBER_LEN];
#endif
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
char buffer_size[ARGV_NUMBER_LEN];
#endif
#ifdef _WIN32
HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */
HANDLE sync_pipe_write; /* pipe used to send messages from child to parent */
@ -272,36 +252,49 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
if (capture_opts->multi_files_on) {
if (capture_opts->has_autostop_filesize) {
char sfilesize[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
argv = sync_pipe_add_arg(argv, &argc, sfilesize);
}
if (capture_opts->has_file_duration) {
char sfile_duration[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->file_duration);
argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
}
if (capture_opts->has_file_interval) {
char sfile_interval[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sfile_interval, ARGV_NUMBER_LEN, "interval:%d",capture_opts->file_interval);
argv = sync_pipe_add_arg(argv, &argc, sfile_interval);
}
if (capture_opts->has_file_packets) {
char sfile_packets[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sfile_packets, ARGV_NUMBER_LEN, "packets:%d",capture_opts->file_packets);
argv = sync_pipe_add_arg(argv, &argc, sfile_packets);
}
if (capture_opts->has_ring_num_files) {
char sring_num_files[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sring_num_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->ring_num_files);
argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
}
if (capture_opts->has_autostop_files) {
char sautostop_files[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a");
g_snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files);
argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
}
} else {
if (capture_opts->has_autostop_filesize) {
char sautostop_filesize[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a");
g_snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
@ -309,12 +302,14 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
}
if (capture_opts->has_autostop_packets) {
char scount[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-c");
g_snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets);
argv = sync_pipe_add_arg(argv, &argc, scount);
}
if (capture_opts->has_autostop_duration) {
char sautostop_duration[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a");
g_snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->autostop_duration);
argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
@ -338,6 +333,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
argv = sync_pipe_add_arg(argv, &argc, interface_opts->cfilter);
}
if (interface_opts->has_snaplen) {
char ssnap[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-s");
g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d", interface_opts->snaplen);
argv = sync_pipe_add_arg(argv, &argc, ssnap);
@ -358,6 +354,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
if (interface_opts->buffer_size != DEFAULT_CAPTURE_BUFFER_SIZE) {
char buffer_size[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-B");
if(interface_opts->buffer_size == 0x00)
interface_opts->buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE;
@ -380,6 +377,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
argv = sync_pipe_add_arg(argv, &argc, "-r");
if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
char sauth[256];
argv = sync_pipe_add_arg(argv, &argc, "-A");
g_snprintf(sauth, sizeof(sauth), "%s:%s",
interface_opts->auth_username,
@ -390,6 +388,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
#ifdef HAVE_PCAP_SETSAMPLING
if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) {
char ssampling[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-m");
g_snprintf(ssampling, ARGV_NUMBER_LEN, "%s:%d",
interface_opts->sampling_method == CAPTURE_SAMP_BY_COUNT ? "count" :

View File

@ -101,6 +101,8 @@ capture_opts_init(capture_options *capture_opts)
capture_opts->file_duration = 60.0; /* 1 min */
capture_opts->has_file_interval = FALSE;
capture_opts->file_interval = 60; /* 1 min */
capture_opts->has_file_packets = FALSE;
capture_opts->file_packets = 0;
capture_opts->has_ring_num_files = FALSE;
capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
@ -243,6 +245,7 @@ capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_optio
g_log(log_domain, log_level, "MultiFilesOn : %u", capture_opts->multi_files_on);
g_log(log_domain, log_level, "FileDuration (%u) : %.3f", capture_opts->has_file_duration, capture_opts->file_duration);
g_log(log_domain, log_level, "FileInterval (%u) : %u", capture_opts->has_file_interval, capture_opts->file_interval);
g_log(log_domain, log_level, "FilePackets (%u) : %u", capture_opts->has_file_packets, capture_opts->file_packets);
g_log(log_domain, log_level, "RingNumFiles (%u) : %u", capture_opts->has_ring_num_files, capture_opts->ring_num_files);
g_log(log_domain, log_level, "AutostopFiles (%u) : %u", capture_opts->has_autostop_files, capture_opts->autostop_files);
@ -295,6 +298,9 @@ set_autostop_criterion(capture_options *capture_opts, const char *autostoparg)
capture_opts->multi_files_on = TRUE;
capture_opts->has_autostop_files = TRUE;
capture_opts->autostop_files = get_positive_int(p,"autostop files");
} else if (strcmp(autostoparg,"packets") == 0) {
capture_opts->has_autostop_packets = TRUE;
capture_opts->autostop_packets = get_positive_int(p,"packet count");
} else {
return FALSE;
}
@ -401,6 +407,9 @@ get_ring_arguments(capture_options *capture_opts, const char *arg)
} else if (strcmp(arg,"interval") == 0) {
capture_opts->has_file_interval = TRUE;
capture_opts->file_interval = get_positive_int(p, "ring buffer interval");
} else if (strcmp(arg,"packets") == 0) {
capture_opts->has_file_packets = TRUE;
capture_opts->file_packets = get_positive_int(p, "ring buffer packet count");
}
*colonp = ':'; /* put the colon back */
@ -805,6 +814,7 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_
break;
#endif
case 'c': /* Capture n packets */
/* XXX Use set_autostop_criterion instead? */
capture_opts->has_autostop_packets = TRUE;
capture_opts->autostop_packets = get_positive_int(optarg_str_p, "packet count");
break;

View File

@ -293,13 +293,16 @@ typedef struct capture_options_tag {
gdouble file_duration; /**< Switch file after n seconds */
gboolean has_file_interval; /**< TRUE if ring interval specified */
gint32 file_interval; /**< Create time intervals of n seconds */
gboolean has_file_packets; /**< TRUE if ring packet count is
specified */
int file_packets; /**< Switch file after n packets */
gboolean has_ring_num_files; /**< TRUE if ring num_files specified */
guint32 ring_num_files; /**< Number of multiple buffer files */
/* autostop conditions */
gboolean has_autostop_files; /**< TRUE if maximum number of capture files
are specified */
gint32 autostop_files; /**< Maximum number of capture files */
int autostop_files; /**< Maximum number of capture files */
gboolean has_autostop_packets; /**< TRUE if maximum packet count is
specified */

View File

@ -74,13 +74,16 @@ where I<test> is one of:
B<duration>:I<value> Stop writing to a capture file after I<value> seconds have
elapsed. Floating point values (e.g. 0.5) are allowed.
B<files>:I<value> Stop writing to capture files after I<value> number of files
were written.
B<filesize>:I<value> Stop writing to a capture file after it reaches a size of
I<value> kB. If this option is used together with the -b option, dumpcap will
stop writing to the current capture file and switch to the next one if filesize
is reached. Note that the filesize is limited to a maximum value of 2 GiB.
B<files>:I<value> Stop writing to capture files after I<value> number of files
were written.
B<packets>:I<value> Stop writing to a capture file after I<value> packets
have been written. Same as B<-c> E<lt>capture packet countE<gt>.
=item -b E<lt>capture ring buffer optionE<gt>
@ -106,12 +109,6 @@ B<duration>:I<value> switch to the next file after I<value> seconds have
elapsed, even if the current file is not completely filled up. Floating
point values (e.g. 0.5) are allowed.
B<interval>:I<value> switch to the next file when the time is an exact
multiple of I<value> seconds
B<filesize>:I<value> switch to the next file after it reaches a size of
I<value> kB. Note that the filesize is limited to a maximum value of 2 GiB.
B<files>:I<value> begin again with the first file after I<value> number of
files were written (form a ring buffer). This value must be less than 100000.
Caution should be used when using large numbers of files: some filesystems do
@ -121,6 +118,15 @@ control when to go to the next file. It should be noted that each B<-b>
parameter takes exactly one criterion; to specify two criterion, each must be
preceded by the B<-b> option.
B<filesize>:I<value> switch to the next file after it reaches a size of
I<value> kB. Note that the filesize is limited to a maximum value of 2 GiB.
B<interval>:I<value> switch to the next file when the time is an exact
multiple of I<value> seconds
B<packets>:I<value> switch to the next file after it contains I<value>
packets.
Example: B<-b filesize:1000 -b files:5> results in a ring buffer of five files
of size one megabyte each.
@ -148,7 +154,7 @@ the default capture buffer size is used instead.
=item -c E<lt>capture packet countE<gt>
Set the maximum number of packets to read when capturing live
data.
data. Same as B<-a packets:>E<lt>capture packet countE<gt>.
=item -C E<lt>byte limitE<gt>

View File

@ -218,6 +218,9 @@ where I<test> is one of:
B<duration>:I<value> Stop writing to a capture file after I<value> seconds
have elapsed. Floating point values (e.g. 0.5) are allowed.
B<files>:I<value> Stop writing to capture files after I<value> number of files
were written.
B<filesize>:I<value> Stop writing to a capture file after it reaches a size of
I<value> kB. If this option is used together with the -b option, B<TShark>
will stop writing to the current capture file and switch to the next one if
@ -226,8 +229,8 @@ the file after the number of bytes read exceeds this number (the complete
packet will be read, so more bytes than this number may be read). Note that
the filesize is limited to a maximum value of 2 GiB.
B<files>:I<value> Stop writing to capture files after I<value> number of files
were written.
B<packets>:I<value> switch to the next file after it contains I<value>
packets. Same as B<-c>E<lt>capture packet countE<gt>.
=item -b E<lt>capture ring buffer optionE<gt>
@ -253,12 +256,6 @@ B<duration>:I<value> switch to the next file after I<value> seconds have
elapsed, even if the current file is not completely filled up. Floating
point values (e.g. 0.5) are allowed.
B<interval>:I<value> switch to the next file when the time is an exact
multiple of I<value> seconds
B<filesize>:I<value> switch to the next file after it reaches a size of
I<value> kB. Note that the filesize is limited to a maximum value of 2 GiB.
B<files>:I<value> begin again with the first file after I<value> number of
files were written (form a ring buffer). This value must be less than 100000.
Caution should be used when using large numbers of files: some filesystems do
@ -268,6 +265,15 @@ control when to go to the next file. It should be noted that each B<-b>
parameter takes exactly one criterion; to specify two criterion, each must be
preceded by the B<-b> option.
B<filesize>:I<value> switch to the next file after it reaches a size of
I<value> kB. Note that the filesize is limited to a maximum value of 2 GiB.
B<interval>:I<value> switch to the next file when the time is an exact
multiple of I<value> seconds
B<packets>:I<value> switch to the next file after it contains I<value>
packets.
Example: B<tshark -b filesize:1000 -b files:5> results in a ring buffer of five files
of size one megabyte each.
@ -295,7 +301,8 @@ the default capture buffer size is used instead.
=item -c E<lt>capture packet countE<gt>
Set the maximum number of packets to read when capturing live
data. If reading a capture file, set the maximum number of packets to read.
data. Same as B<-a packets:>E<lt>capture packet countE<gt>.
If reading a capture file, set the maximum number of packets to read.
=item -C E<lt>configuration profileE<gt>

View File

@ -242,14 +242,17 @@ where I<test> is one of:
B<duration>:I<value> Stop writing to a capture file after I<value> seconds have
elapsed. Floating point values (e.g. 0.5) are allowed.
B<files>:I<value> Stop writing to capture files after I<value> number of files
were written.
B<filesize>:I<value> Stop writing to a capture file after it reaches a size of
I<value> kB. If this option is used together with the -b option, Wireshark
will stop writing to the current capture file and switch to the next one if
filesize is reached. Note that the filesize is limited to a maximum value of
2 GiB.
B<files>:I<value> Stop writing to capture files after I<value> number of files
were written.
B<packets>:I<value> switch to the next file after it contains I<value>
packets. Same as B<-c>E<lt>capture packet countE<gt>.
=item -b E<lt>capture ring buffer optionE<gt>
@ -275,12 +278,6 @@ B<duration>:I<value> switch to the next file after I<value> seconds have
elapsed, even if the current file is not completely filled up. Floating
point values (e.g. 0.5) are allowed.
B<interval>:I<value> switch to the next file when the time is an exact
multiple of I<value> seconds
B<filesize>:I<value> switch to the next file after it reaches a size of
I<value> kB. Note that the filesize is limited to a maximum value of 2 GiB.
B<files>:I<value> begin again with the first file after I<value> number of
files were written (form a ring buffer). This value must be less than 100000.
Caution should be used when using large numbers of files: some filesystems do
@ -290,6 +287,15 @@ control when to go to the next file. It should be noted that each B<-b>
parameter takes exactly one criterion; to specify two criterion, each must be
preceded by the B<-b> option.
B<filesize>:I<value> switch to the next file after it reaches a size of
I<value> kB. Note that the filesize is limited to a maximum value of 2 GiB.
B<interval>:I<value> switch to the next file when the time is an exact
multiple of I<value> seconds
B<packets>:I<value> switch to the next file after it contains I<value>
packets.
Example: B<-b filesize:1000 -b files:5> results in a ring buffer of five files
of size one megabyte each.
@ -317,7 +323,7 @@ the default capture buffer size is used instead.
=item -c E<lt>capture packet countE<gt>
Set the maximum number of packets to read when capturing live
data.
data. Same as B<-a packets:>E<lt>capture packet countE<gt>.
=item -C E<lt>configuration profileE<gt>

View File

@ -60,6 +60,7 @@ since version 2.6.0:
* When importing from hex dump, it's now possible to add an ExportPDU header with a payload name. This
calls the specific dissector directly without lower protocols.
* sshdump and ciscodump can now use a proxy for the ssh connection.
* Dumpcap now supports the `-a packets:NUM` and `-b packets:NUM` options.
=== Removed Features and Support

133
dumpcap.c
View File

@ -291,8 +291,7 @@ typedef struct _loop_data {
/* common */
gboolean go; /**< TRUE as long as we're supposed to keep capturing */
int err; /**< if non-zero, error seen while capturing */
gint packet_count; /**< Number of packets we have already captured */
gint packet_max; /**< Number of packets we're supposed to capture - 0 means infinite */
gint packets_captured; /**< Number of packets we have already captured */
guint inpkts_to_sync_pipe; /**< Packets not already send out to the sync_pipe */
#ifdef SIGINFO
gboolean report_packet_count; /**< Set by SIGINFO handler; print packet count */
@ -301,8 +300,14 @@ typedef struct _loop_data {
/* output file(s) */
FILE *pdh;
int save_file_fd;
guint64 bytes_written;
guint32 autostop_files;
guint64 bytes_written; /**< Bytes written for the current file. */
/* autostop conditions */
int packets_written; /**< Packets written for the current file. */
int file_count;
/* ring buffer conditions */
GTimer *file_duration_timer;
time_t next_interval_time;
int interval_s;
} loop_data;
typedef struct _pcap_queue_element {
@ -314,14 +319,6 @@ typedef struct _pcap_queue_element {
u_char *pd;
} pcap_queue_element;
/* Conditions required by do_file_switch_or_stop */
typedef struct _condition_data {
GTimer *file_duration_timer;
time_t next_interval_time;
int interval_s;
unsigned autostop_files;
} condition_data;
/*
* Standard secondary message for unexpected errors.
*/
@ -455,6 +452,7 @@ print_usage(FILE *output)
fprintf(output, " -a <autostop cond.> ... duration:NUM - stop after NUM seconds\n");
fprintf(output, " filesize:NUM - stop this file after NUM kB\n");
fprintf(output, " files:NUM - stop after NUM files\n");
fprintf(output, " packets:NUM - stop after NUM packets\n");
/*fprintf(output, "\n");*/
fprintf(output, "Output (files):\n");
fprintf(output, " -w <filename> name of file to save (def: tempfile)\n");
@ -463,6 +461,7 @@ print_usage(FILE *output)
fprintf(output, " interval:NUM - create time intervals of NUM secs\n");
fprintf(output, " filesize:NUM - switch to next file after NUM kB\n");
fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n");
fprintf(output, " packets:NUM - ringbuffer: replace after NUM packets\n");
fprintf(output, " -n use pcapng format instead of pcap (default)\n");
fprintf(output, " -P use libpcap format instead of pcapng\n");
fprintf(output, " --capture-comment <comment>\n");
@ -1097,7 +1096,7 @@ report_capture_count(gboolean reportit)
{
/* Don't print this if we're a capture child. */
if (!capture_child && reportit) {
fprintf(stderr, "\rPackets captured: %d\n", global_ld.packet_count);
fprintf(stderr, "\rPackets captured: %d\n", global_ld.packets_captured);
/* stderr could be line buffered */
fflush(stderr);
}
@ -2275,7 +2274,7 @@ pcap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errms
* instead stop with an error.
*/
g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
ld->packet_count+1, pcap_info->rechdr.hdr.incl_len);
ld->packets_captured+1, pcap_info->rechdr.hdr.incl_len);
break;
}
@ -2505,7 +2504,7 @@ pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int err
* instead stop with an error.
*/
g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
ld->packet_count+1, bh->block_total_length);
ld->packets_captured+1, bh->block_total_length);
break;
}
@ -3086,7 +3085,7 @@ capture_loop_dispatch(loop_data *ld,
gint packet_count_before;
int sel_ret;
packet_count_before = ld->packet_count;
packet_count_before = ld->packets_captured;
if (pcap_src->from_cap_pipe) {
/* dispatch from capture pipe */
#ifdef LOG_CAPTURE_VERBOSE
@ -3254,7 +3253,7 @@ capture_loop_dispatch(loop_data *ld,
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: %d new packet%s", inpkts, plurality(inpkts, "", "s"));
#endif
return ld->packet_count - packet_count_before;
return ld->packets_captured - packet_count_before;
}
#ifdef _WIN32
@ -3462,8 +3461,7 @@ static time_t get_next_time_interval(int interval_s) {
/* Do the work of handling either the file size or file duration capture
conditions being reached, and switching files or stopping. */
static gboolean
do_file_switch_or_stop(capture_options *capture_opts,
condition_data *conditions)
do_file_switch_or_stop(capture_options *capture_opts)
{
guint i;
capture_src *pcap_src;
@ -3471,8 +3469,8 @@ do_file_switch_or_stop(capture_options *capture_opts,
gboolean successful;
if (capture_opts->multi_files_on) {
if (conditions->autostop_files &&
++global_ld.autostop_files >= conditions->autostop_files) {
if (capture_opts->has_autostop_files &&
++global_ld.file_count >= capture_opts->autostop_files) {
/* no files left: stop here */
global_ld.go = FALSE;
return FALSE;
@ -3484,6 +3482,7 @@ do_file_switch_or_stop(capture_options *capture_opts,
/* File switch succeeded: reset the conditions */
global_ld.bytes_written = 0;
global_ld.packets_written = 0;
pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0);
if (pcap_src->from_pcapng) {
/* Write the saved SHB and all IDBs to start of next file */
@ -3554,11 +3553,11 @@ do_file_switch_or_stop(capture_options *capture_opts,
global_ld.go = FALSE;
return FALSE;
}
if (conditions->file_duration_timer) {
g_timer_reset(conditions->file_duration_timer);
if (global_ld.file_duration_timer) {
g_timer_reset(global_ld.file_duration_timer);
}
if (conditions->next_interval_time) {
conditions->next_interval_time = get_next_time_interval(conditions->interval_s);
if (global_ld.next_interval_time) {
global_ld.next_interval_time = get_next_time_interval(global_ld.interval_s);
}
fflush(global_ld.pdh);
if (!quiet)
@ -3611,7 +3610,6 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
#endif
int err_close;
int inpkts;
condition_data conditions;
GTimer *autostop_duration_timer = NULL;
gboolean write_ok;
gboolean close_ok;
@ -3627,19 +3625,18 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
/* init the loop data */
global_ld.go = TRUE;
global_ld.packet_count = 0;
global_ld.packets_captured = 0;
#ifdef SIGINFO
global_ld.report_packet_count = FALSE;
#endif
if (capture_opts->has_autostop_packets)
global_ld.packet_max = capture_opts->autostop_packets;
else
global_ld.packet_max = 0; /* no limit */
global_ld.inpkts_to_sync_pipe = 0;
global_ld.err = 0; /* no error seen yet */
global_ld.pdh = NULL;
global_ld.autostop_files = 0;
global_ld.save_file_fd = -1;
global_ld.file_count = 0;
global_ld.file_duration_timer = NULL;
global_ld.next_interval_time = 0;
global_ld.interval_s = 0;
/* We haven't yet gotten the capture statistics. */
*stats_known = FALSE;
@ -3713,11 +3710,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
report_new_capture_file(capture_opts->save_file);
}
/* initialize capture stop (and alike) conditions */
memset(&conditions, 0, sizeof(conditions));
if (capture_opts->has_file_interval) {
conditions.interval_s = capture_opts->file_interval;
conditions.next_interval_time = get_next_time_interval(conditions.interval_s);
global_ld.interval_s = capture_opts->file_interval;
global_ld.next_interval_time = get_next_time_interval(global_ld.interval_s);
}
/* create stop conditions */
if (capture_opts->has_autostop_filesize) {
@ -3731,11 +3726,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
if (capture_opts->multi_files_on) {
if (capture_opts->has_file_duration) {
conditions.file_duration_timer = g_timer_new();
global_ld.file_duration_timer = g_timer_new();
}
if (capture_opts->has_autostop_files)
conditions.autostop_files = capture_opts->autostop_files;
}
/* init the time values */
@ -3809,8 +3801,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
#ifdef SIGINFO
/* Were we asked to print packet counts by the SIGINFO handler? */
if (global_ld.report_packet_count) {
fprintf(stderr, "%u packet%s captured\n", global_ld.packet_count,
plurality(global_ld.packet_count, "", "s"));
fprintf(stderr, "%u packet%s captured\n", global_ld.packets_captured,
plurality(global_ld.packets_captured, "", "s"));
global_ld.report_packet_count = FALSE;
}
#endif
@ -3825,14 +3817,6 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
if (inpkts > 0) {
global_ld.inpkts_to_sync_pipe += inpkts;
/* check capture size condition */
if (capture_opts->has_autostop_filesize &&
capture_opts->autostop_filesize > 0 &&
global_ld.bytes_written / 1000 >= capture_opts->autostop_filesize) {
/* Capture size limit reached, do we have another file? */
if (!do_file_switch_or_stop(capture_opts, &conditions))
continue;
} /* cnd_autostop_size */
if (capture_opts->output_to_pipe) {
fflush(global_ld.pdh);
}
@ -3882,16 +3866,16 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
}
/* check capture file duration condition */
if (conditions.file_duration_timer != NULL && g_timer_elapsed(conditions.file_duration_timer, NULL) >= capture_opts->file_duration) {
if (global_ld.file_duration_timer != NULL && g_timer_elapsed(global_ld.file_duration_timer, NULL) >= capture_opts->file_duration) {
/* duration limit reached, do we have another file? */
if (!do_file_switch_or_stop(capture_opts, &conditions))
if (!do_file_switch_or_stop(capture_opts))
continue;
} /* cnd_file_duration */
/* check capture file interval condition */
if (conditions.interval_s && time(NULL) >= conditions.next_interval_time) {
if (global_ld.interval_s && time(NULL) >= global_ld.next_interval_time) {
/* end of interval reached, do we have another file? */
if (!do_file_switch_or_stop(capture_opts, &conditions))
if (!do_file_switch_or_stop(capture_opts))
continue;
} /* cnd_file_interval */
}
@ -3937,8 +3921,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
/* delete stop conditions */
if (conditions.file_duration_timer != NULL)
g_timer_destroy(conditions.file_duration_timer);
if (global_ld.file_duration_timer != NULL)
g_timer_destroy(global_ld.file_duration_timer);
if (autostop_duration_timer != NULL)
g_timer_destroy(autostop_duration_timer);
@ -4210,10 +4194,13 @@ capture_loop_write_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_he
"Wrote a packet of length %d captured on interface %u.",
bh->block_total_length, pcap_src->interface_id);
#endif
global_ld.packet_count++;
global_ld.packets_captured++;
global_ld.packets_written++;
pcap_src->received++;
/* if the user told us to stop after x packets, do we already have enough? */
if ((global_ld.packet_max > 0) && (global_ld.packet_count >= global_ld.packet_max)) {
if (global_capture_opts.has_autostop_packets && global_ld.packets_captured >= global_capture_opts.autostop_packets) {
fflush(global_ld.pdh);
global_ld.go = FALSE;
}
}
@ -4271,11 +4258,28 @@ capture_loop_write_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr,
"Wrote a packet of length %d captured on interface %u.",
phdr->caplen, pcap_src->interface_id);
#endif
global_ld.packet_count++;
global_ld.packets_captured++;
global_ld.packets_written++;
pcap_src->received++;
/* if the user told us to stop after x packets, do we already have enough? */
if ((global_ld.packet_max > 0) && (global_ld.packet_count >= global_ld.packet_max)) {
/* check -c NUM / -a packets:NUM */
if (global_capture_opts.has_autostop_packets && global_ld.packets_captured >= global_capture_opts.autostop_packets) {
fflush(global_ld.pdh);
global_ld.go = FALSE;
return;
}
/* check -b packets:NUM */
if (global_capture_opts.has_file_packets && global_ld.packets_written >= global_capture_opts.file_packets) {
do_file_switch_or_stop(&global_capture_opts);
return;
}
/* check -a filesize:NUM */
if (global_capture_opts.has_autostop_filesize &&
global_capture_opts.autostop_filesize > 0 &&
global_ld.bytes_written / 1000 >= global_capture_opts.autostop_filesize) {
/* Capture size limit reached, do we have another file? */
do_file_switch_or_stop(&global_capture_opts);
return;
}
}
}
@ -5034,9 +5038,10 @@ real_main(int argc, char *argv[])
}
if (!global_capture_opts.has_autostop_filesize &&
!global_capture_opts.has_file_duration &&
!global_capture_opts.has_file_interval) {
cmdarg_err("Ring buffer requested, but no maximum capture file size, duration"
"or interval were specified.");
!global_capture_opts.has_file_interval &&
!global_capture_opts.has_file_packets) {
cmdarg_err("Ring buffer requested, but no maximum capture file size, duration "
"interval, or packets were specified.");
#if 0
/* XXX - this must be redesigned as the conditions changed */
global_capture_opts.multi_files_on = FALSE;

View File

@ -10,6 +10,7 @@
'''Capture tests'''
import config
import glob
import os
import re
import subprocess
@ -17,6 +18,7 @@ import subprocesstest
import sys
import time
import unittest
import uuid
capture_duration = 5
@ -139,11 +141,6 @@ def check_capture_stdin(self, cmd=None):
if (pipe_returncode == 0):
self.checkPacketCount(8)
def check_capture_2multi_10packets(self, cmd=None):
# This was present in the Bash version but was incorrect and not part of any suite.
# It's apparently intended to test file rotation.
self.skipTest('Not yet implemented')
def check_capture_read_filter(self, cmd=None):
if not config.canCapture():
self.skipTest('Test requires capture privileges and an interface.')
@ -207,6 +204,86 @@ def check_capture_snapshot_len(self, cmd=None):
if (capture_returncode == 0):
self.checkPacketCount(0, cap_file=testout2_file)
def check_dumpcap_autostop_stdin(self, packets=None, filesize=None):
# Similar to check_capture_stdin.
cmd = config.cmd_dumpcap
capture_file = os.path.join(config.capture_dir, 'dhcp.pcap')
testout_file = self.filename_from_id(testout_pcap)
cat100_dhcp_cmd = subprocesstest.cat_dhcp_command('cat100')
condition='oops:invalid'
self.assertTrue(packets is not None or filesize is not None, 'Need one of packets or filesize')
self.assertFalse(packets is not None and filesize is not None, 'Need one of packets or filesize')
if packets is not None:
condition = 'packets:{}'.format(packets)
elif filesize is not None:
condition = 'filesize:{}'.format(filesize)
capture_cmd = subprocesstest.capture_command(cmd,
'-i', '-',
'-w', testout_file,
'-a', condition,
shell=True
)
pipe_proc = self.runProcess(cat100_dhcp_cmd + ' | ' + capture_cmd, shell=True)
pipe_returncode = pipe_proc.returncode
self.assertEqual(pipe_returncode, 0)
self.assertTrue(os.path.isfile(testout_file))
if (pipe_returncode != 0):
return
if packets is not None:
self.checkPacketCount(packets)
elif filesize is not None:
capturekb = os.path.getsize(testout_file) / 1000
self.assertGreaterEqual(capturekb, filesize)
def check_dumpcap_ringbuffer_stdin(self, packets=None, filesize=None):
# Similar to check_capture_stdin.
cmd = config.cmd_dumpcap
capture_file = os.path.join(config.capture_dir, 'dhcp.pcap')
rb_unique = 'dhcp_rb_' + uuid.uuid4().hex[:6] # Random ID
testout_file = '{}.{}.pcapng'.format(self.id(), rb_unique)
testout_glob = '{}.{}_*.pcapng'.format(self.id(), rb_unique)
cat100_dhcp_cmd = subprocesstest.cat_dhcp_command('cat100')
condition='oops:invalid'
self.assertTrue(packets is not None or filesize is not None, 'Need one of packets or filesize')
self.assertFalse(packets is not None and filesize is not None, 'Need one of packets or filesize')
if packets is not None:
condition = 'packets:{}'.format(packets)
elif filesize is not None:
condition = 'filesize:{}'.format(filesize)
capture_cmd = subprocesstest.capture_command(cmd,
'-i', '-',
'-w', testout_file,
'-a', 'files:2',
'-b', condition,
shell=True
)
pipe_proc = self.runProcess(cat100_dhcp_cmd + ' | ' + capture_cmd, shell=True)
pipe_returncode = pipe_proc.returncode
self.assertEqual(pipe_returncode, 0)
if (pipe_returncode != 0):
return
rb_files = glob.glob(testout_glob)
for rbf in rb_files:
self.cleanup_files.append(rbf)
self.assertEqual(len(rb_files), 2)
for rbf in rb_files:
self.assertTrue(os.path.isfile(rbf))
if packets is not None:
self.checkPacketCount(packets, cap_file=rbf)
elif filesize is not None:
capturekb = os.path.getsize(rbf) / 1000
self.assertGreaterEqual(capturekb, filesize)
class case_wireshark_capture(subprocesstest.SubprocessTestCase):
def test_wireshark_capture_10_packets_to_file(self):
'''Capture 10 packets from the network to a file using Wireshark'''
@ -270,3 +347,24 @@ class case_dumpcap_capture(subprocesstest.SubprocessTestCase):
def test_dumpcap_capture_snapshot_len(self):
'''Capture truncated packets using Dumpcap'''
check_capture_snapshot_len(self, cmd=config.cmd_dumpcap)
class case_dumpcap_autostop(subprocesstest.SubprocessTestCase):
# duration, filesize, packets, files
def test_dumpcap_autostop_filesize(self):
'''Capture from stdin using Dumpcap until we reach a file size limit'''
check_dumpcap_autostop_stdin(self, filesize=15)
def test_dumpcap_autostop_packets(self):
'''Capture from stdin using Dumpcap until we reach a packet limit'''
check_dumpcap_autostop_stdin(self, packets=97) # Last prime before 100. Arbitrary.
class case_dumpcap_ringbuffer(subprocesstest.SubprocessTestCase):
# duration, interval, filesize, packets, files
# Need a function that finds ringbuffer file names.
def test_dumpcap_ringbuffer_filesize(self):
'''Capture from stdin using Dumpcap and write multiple files until we reach a file size limit'''
check_dumpcap_ringbuffer_stdin(self, filesize=15)
def test_dumpcap_ringbuffer_packets(self):
'''Capture from stdin using Dumpcap and write multiple files until we reach a packet limit'''
check_dumpcap_ringbuffer_stdin(self, packets=47) # Last prime before 50. Arbitrary.

View File

@ -17,8 +17,8 @@ import sys
def main():
parser = argparse.ArgumentParser(description='Dump dhcp.pcap')
parser.add_argument('dump_type', choices=['cat', 'slow', 'raw'],
help='cat: Just dump the file. slow: Dump the file, pause, and dump its packet records. raw: Dump only the packet records.')
parser.add_argument('dump_type', choices=['cat', 'cat100', 'slow', 'raw'],
help='cat: Just dump the file. cat100: Dump 100 packet records. slow: Dump the file, pause, and dump its packet records. raw: Dump only the packet records.')
args = parser.parse_args()
dhcp_pcap = os.path.join(os.path.dirname(__file__), 'captures', 'dhcp.pcap')
@ -27,12 +27,17 @@ def main():
contents = dhcp_fd.read()
if args.dump_type != 'raw':
os.write(1, contents)
if args.dump_type == 'cat':
if args.dump_type == 'cat100':
# The capture contains 4 packets. Write 96 more.
for _ in range(24):
os.write(1, contents[24:])
if args.dump_type.startswith('cat'):
sys.exit(0)
if args.dump_type == 'slow':
time.sleep(1.5)
# slow, raw
os.write(1, contents[24:])
sys.exit(0)
if __name__ == '__main__':

View File

@ -549,6 +549,10 @@ void CaptureInterfacesDialog::updateInterfaces()
}
ui->gbNewFileAuto->setChecked(global_capture_opts.multi_files_on);
ui->PktCheckBox->setChecked(global_capture_opts.has_file_packets);
if (global_capture_opts.has_file_packets) {
ui->PktSpinBox->setValue(global_capture_opts.file_packets);
}
ui->MBCheckBox->setChecked(global_capture_opts.has_autostop_filesize);
ui->SecsCheckBox->setChecked(global_capture_opts.has_file_interval);
if (global_capture_opts.has_autostop_filesize) {
@ -850,6 +854,10 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
break;
}
}
global_capture_opts.has_file_packets = ui->PktCheckBox->isChecked();
if (global_capture_opts.has_file_packets) {
global_capture_opts.file_packets = ui->PktSpinBox->value();
}
global_capture_opts.has_autostop_filesize = ui->MBCheckBox->isChecked();
if (global_capture_opts.has_autostop_filesize) {
global_capture_opts.autostop_filesize = ui->MBSpinBox->value();
@ -878,9 +886,12 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
QMessageBox::warning(this, tr("Error"),
tr("Multiple files: No capture file name given. You must specify a filename if you want to use multiple files."));
return false;
} else if (!global_capture_opts.has_autostop_filesize && !global_capture_opts.has_file_interval) {
} else if (!global_capture_opts.has_autostop_filesize &&
!global_capture_opts.has_file_interval &&
!global_capture_opts.has_file_duration &&
!global_capture_opts.has_file_packets) {
QMessageBox::warning(this, tr("Error"),
tr("Multiple files: No file limit given. You must specify a file size or interval at which is switched to the next capture file\n if you want to use multiple files."));
tr("Multiple files: No file limit given. You must specify a file size, interval, or number of packets for each file."));
g_free(global_capture_opts.save_file);
global_capture_opts.save_file = NULL;
return false;

View File

@ -262,10 +262,38 @@
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QSpinBox" name="MBSpinBox">
<item row="0" column="3" rowspan="4">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="MBCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="SecsCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="SecsSpinBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If the selected file size is exceeded, capturing switches to the next file.&lt;/p&gt;&lt;p&gt;PLEASE NOTE: One option MUST be selected.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>If the selected file size is exceeded, capturing switches to the next file.
PLEASE NOTE: One option MUST be selected.</string>
</property>
<property name="wrapping">
<bool>true</bool>
@ -284,30 +312,7 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="MBComboBox">
<property name="toolTip">
<string>If the selected file size is exceeded, capturing switches to the next file.
PLEASE NOTE: One option MUST be selected.</string>
</property>
<item>
<property name="text">
<string>kilobytes</string>
</property>
</item>
<item>
<property name="text">
<string>megabytes</string>
</property>
</item>
<item>
<property name="text">
<string>gigabytes</string>
</property>
</item>
</widget>
</item>
<item row="2" column="2">
<item row="3" column="2">
<widget class="QComboBox" name="SecsComboBox">
<property name="toolTip">
<string>If the selected file size is exceeded, capturing switches to the next file.
@ -331,10 +336,9 @@ PLEASE NOTE: One option MUST be selected.</string>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="SecsSpinBox">
<widget class="QSpinBox" name="MBSpinBox">
<property name="toolTip">
<string>If the selected file size is exceeded, capturing switches to the next file.
PLEASE NOTE: One option MUST be selected.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If the selected file size is exceeded, capturing switches to the next file.&lt;/p&gt;&lt;p&gt;PLEASE NOTE: One option MUST be selected.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wrapping">
<bool>true</bool>
@ -353,30 +357,56 @@ PLEASE NOTE: One option MUST be selected.</string>
</property>
</widget>
</item>
<item row="0" column="3" rowspan="3">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="2" column="2">
<widget class="QComboBox" name="MBComboBox">
<property name="toolTip">
<string>If the selected file size is exceeded, capturing switches to the next file.
PLEASE NOTE: One option MUST be selected.</string>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
<item>
<property name="text">
<string>kilobytes</string>
</property>
</item>
<item>
<property name="text">
<string>megabytes</string>
</property>
</item>
<item>
<property name="text">
<string>gigabytes</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="MBCheckBox">
<widget class="QCheckBox" name="PktCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="SecsCheckBox">
<item row="1" column="1">
<widget class="QSpinBox" name="PktSpinBox">
<property name="toolTip">
<string>Switch to the next file after the specified number of packets have been captured.</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::PlusMinus</enum>
</property>
<property name="maximum">
<number>2147483647</number>
</property>
<property name="value">
<number>100000</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="PktLabel">
<property name="text">
<string/>
<string>packets</string>
</property>
</widget>
</item>