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 gboolean
sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, info_data_t* cap_data, void (*update_cb)(void)) 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 #ifdef _WIN32
HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */ 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 */ 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->multi_files_on) {
if (capture_opts->has_autostop_filesize) { if (capture_opts->has_autostop_filesize) {
char sfilesize[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b"); argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize); g_snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
argv = sync_pipe_add_arg(argv, &argc, sfilesize); argv = sync_pipe_add_arg(argv, &argc, sfilesize);
} }
if (capture_opts->has_file_duration) { if (capture_opts->has_file_duration) {
char sfile_duration[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b"); argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->file_duration); g_snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->file_duration);
argv = sync_pipe_add_arg(argv, &argc, sfile_duration); argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
} }
if (capture_opts->has_file_interval) { if (capture_opts->has_file_interval) {
char sfile_interval[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b"); argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sfile_interval, ARGV_NUMBER_LEN, "interval:%d",capture_opts->file_interval); g_snprintf(sfile_interval, ARGV_NUMBER_LEN, "interval:%d",capture_opts->file_interval);
argv = sync_pipe_add_arg(argv, &argc, sfile_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) { if (capture_opts->has_ring_num_files) {
char sring_num_files[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b"); argv = sync_pipe_add_arg(argv, &argc, "-b");
g_snprintf(sring_num_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->ring_num_files); 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); argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
} }
if (capture_opts->has_autostop_files) { if (capture_opts->has_autostop_files) {
char sautostop_files[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a"); argv = sync_pipe_add_arg(argv, &argc, "-a");
g_snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files); g_snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files);
argv = sync_pipe_add_arg(argv, &argc, sautostop_files); argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
} }
} else { } else {
if (capture_opts->has_autostop_filesize) { if (capture_opts->has_autostop_filesize) {
char sautostop_filesize[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a"); argv = sync_pipe_add_arg(argv, &argc, "-a");
g_snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize); g_snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
argv = sync_pipe_add_arg(argv, &argc, sautostop_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) { if (capture_opts->has_autostop_packets) {
char scount[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-c"); argv = sync_pipe_add_arg(argv, &argc, "-c");
g_snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets); g_snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets);
argv = sync_pipe_add_arg(argv, &argc, scount); argv = sync_pipe_add_arg(argv, &argc, scount);
} }
if (capture_opts->has_autostop_duration) { if (capture_opts->has_autostop_duration) {
char sautostop_duration[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-a"); argv = sync_pipe_add_arg(argv, &argc, "-a");
g_snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->autostop_duration); g_snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->autostop_duration);
argv = sync_pipe_add_arg(argv, &argc, sautostop_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); argv = sync_pipe_add_arg(argv, &argc, interface_opts->cfilter);
} }
if (interface_opts->has_snaplen) { if (interface_opts->has_snaplen) {
char ssnap[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-s"); argv = sync_pipe_add_arg(argv, &argc, "-s");
g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d", interface_opts->snaplen); g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d", interface_opts->snaplen);
argv = sync_pipe_add_arg(argv, &argc, ssnap); 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 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
if (interface_opts->buffer_size != DEFAULT_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"); argv = sync_pipe_add_arg(argv, &argc, "-B");
if(interface_opts->buffer_size == 0x00) if(interface_opts->buffer_size == 0x00)
interface_opts->buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE; 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"); argv = sync_pipe_add_arg(argv, &argc, "-r");
if (interface_opts->auth_type == CAPTURE_AUTH_PWD) { if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
char sauth[256];
argv = sync_pipe_add_arg(argv, &argc, "-A"); argv = sync_pipe_add_arg(argv, &argc, "-A");
g_snprintf(sauth, sizeof(sauth), "%s:%s", g_snprintf(sauth, sizeof(sauth), "%s:%s",
interface_opts->auth_username, interface_opts->auth_username,
@ -390,6 +388,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf
#ifdef HAVE_PCAP_SETSAMPLING #ifdef HAVE_PCAP_SETSAMPLING
if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) { if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) {
char ssampling[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-m"); argv = sync_pipe_add_arg(argv, &argc, "-m");
g_snprintf(ssampling, ARGV_NUMBER_LEN, "%s:%d", g_snprintf(ssampling, ARGV_NUMBER_LEN, "%s:%d",
interface_opts->sampling_method == CAPTURE_SAMP_BY_COUNT ? "count" : 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->file_duration = 60.0; /* 1 min */
capture_opts->has_file_interval = FALSE; capture_opts->has_file_interval = FALSE;
capture_opts->file_interval = 60; /* 1 min */ 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->has_ring_num_files = FALSE;
capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES; 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, "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, "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, "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, "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); 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->multi_files_on = TRUE;
capture_opts->has_autostop_files = TRUE; capture_opts->has_autostop_files = TRUE;
capture_opts->autostop_files = get_positive_int(p,"autostop files"); 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 { } else {
return FALSE; return FALSE;
} }
@ -401,6 +407,9 @@ get_ring_arguments(capture_options *capture_opts, const char *arg)
} else if (strcmp(arg,"interval") == 0) { } else if (strcmp(arg,"interval") == 0) {
capture_opts->has_file_interval = TRUE; capture_opts->has_file_interval = TRUE;
capture_opts->file_interval = get_positive_int(p, "ring buffer interval"); 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 */ *colonp = ':'; /* put the colon back */
@ -805,6 +814,7 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_
break; break;
#endif #endif
case 'c': /* Capture n packets */ case 'c': /* Capture n packets */
/* XXX Use set_autostop_criterion instead? */
capture_opts->has_autostop_packets = TRUE; capture_opts->has_autostop_packets = TRUE;
capture_opts->autostop_packets = get_positive_int(optarg_str_p, "packet count"); capture_opts->autostop_packets = get_positive_int(optarg_str_p, "packet count");
break; break;

View File

@ -293,13 +293,16 @@ typedef struct capture_options_tag {
gdouble file_duration; /**< Switch file after n seconds */ gdouble file_duration; /**< Switch file after n seconds */
gboolean has_file_interval; /**< TRUE if ring interval specified */ gboolean has_file_interval; /**< TRUE if ring interval specified */
gint32 file_interval; /**< Create time intervals of n seconds */ 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 */ gboolean has_ring_num_files; /**< TRUE if ring num_files specified */
guint32 ring_num_files; /**< Number of multiple buffer files */ guint32 ring_num_files; /**< Number of multiple buffer files */
/* autostop conditions */ /* autostop conditions */
gboolean has_autostop_files; /**< TRUE if maximum number of capture files gboolean has_autostop_files; /**< TRUE if maximum number of capture files
are specified */ 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 gboolean has_autostop_packets; /**< TRUE if maximum packet count is
specified */ 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 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. 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 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 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 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. 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 B<packets>:I<value> Stop writing to a capture file after I<value> packets
were written. have been written. Same as B<-c> E<lt>capture packet countE<gt>.
=item -b E<lt>capture ring buffer optionE<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 elapsed, even if the current file is not completely filled up. Floating
point values (e.g. 0.5) are allowed. 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 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. 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 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 parameter takes exactly one criterion; to specify two criterion, each must be
preceded by the B<-b> option. 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 Example: B<-b filesize:1000 -b files:5> results in a ring buffer of five files
of size one megabyte each. 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> =item -c E<lt>capture packet countE<gt>
Set the maximum number of packets to read when capturing live 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> =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 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. 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 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> 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 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 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. 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 B<packets>:I<value> switch to the next file after it contains I<value>
were written. packets. Same as B<-c>E<lt>capture packet countE<gt>.
=item -b E<lt>capture ring buffer optionE<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 elapsed, even if the current file is not completely filled up. Floating
point values (e.g. 0.5) are allowed. 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 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. 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 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 parameter takes exactly one criterion; to specify two criterion, each must be
preceded by the B<-b> option. 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 Example: B<tshark -b filesize:1000 -b files:5> results in a ring buffer of five files
of size one megabyte each. 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> =item -c E<lt>capture packet countE<gt>
Set the maximum number of packets to read when capturing live 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> =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 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. 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 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 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 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 filesize is reached. Note that the filesize is limited to a maximum value of
2 GiB. 2 GiB.
B<files>:I<value> Stop writing to capture files after I<value> number of files B<packets>:I<value> switch to the next file after it contains I<value>
were written. packets. Same as B<-c>E<lt>capture packet countE<gt>.
=item -b E<lt>capture ring buffer optionE<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 elapsed, even if the current file is not completely filled up. Floating
point values (e.g. 0.5) are allowed. 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 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. 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 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 parameter takes exactly one criterion; to specify two criterion, each must be
preceded by the B<-b> option. 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 Example: B<-b filesize:1000 -b files:5> results in a ring buffer of five files
of size one megabyte each. 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> =item -c E<lt>capture packet countE<gt>
Set the maximum number of packets to read when capturing live 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> =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 * 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. calls the specific dissector directly without lower protocols.
* sshdump and ciscodump can now use a proxy for the ssh connection. * 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 === Removed Features and Support

133
dumpcap.c
View File

@ -291,8 +291,7 @@ typedef struct _loop_data {
/* common */ /* common */
gboolean go; /**< TRUE as long as we're supposed to keep capturing */ gboolean go; /**< TRUE as long as we're supposed to keep capturing */
int err; /**< if non-zero, error seen while capturing */ int err; /**< if non-zero, error seen while capturing */
gint packet_count; /**< Number of packets we have already captured */ gint packets_captured; /**< Number of packets we have already captured */
gint packet_max; /**< Number of packets we're supposed to capture - 0 means infinite */
guint inpkts_to_sync_pipe; /**< Packets not already send out to the sync_pipe */ guint inpkts_to_sync_pipe; /**< Packets not already send out to the sync_pipe */
#ifdef SIGINFO #ifdef SIGINFO
gboolean report_packet_count; /**< Set by SIGINFO handler; print packet count */ gboolean report_packet_count; /**< Set by SIGINFO handler; print packet count */
@ -301,8 +300,14 @@ typedef struct _loop_data {
/* output file(s) */ /* output file(s) */
FILE *pdh; FILE *pdh;
int save_file_fd; int save_file_fd;
guint64 bytes_written; guint64 bytes_written; /**< Bytes written for the current file. */
guint32 autostop_files; /* 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; } loop_data;
typedef struct _pcap_queue_element { typedef struct _pcap_queue_element {
@ -314,14 +319,6 @@ typedef struct _pcap_queue_element {
u_char *pd; u_char *pd;
} pcap_queue_element; } 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. * 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, " -a <autostop cond.> ... duration:NUM - stop after NUM seconds\n");
fprintf(output, " filesize:NUM - stop this file after NUM kB\n"); fprintf(output, " filesize:NUM - stop this file after NUM kB\n");
fprintf(output, " files:NUM - stop after NUM files\n"); fprintf(output, " files:NUM - stop after NUM files\n");
fprintf(output, " packets:NUM - stop after NUM packets\n");
/*fprintf(output, "\n");*/ /*fprintf(output, "\n");*/
fprintf(output, "Output (files):\n"); fprintf(output, "Output (files):\n");
fprintf(output, " -w <filename> name of file to save (def: tempfile)\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, " interval:NUM - create time intervals of NUM secs\n");
fprintf(output, " filesize:NUM - switch to next file after NUM kB\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, " 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, " -n use pcapng format instead of pcap (default)\n");
fprintf(output, " -P use libpcap format instead of pcapng\n"); fprintf(output, " -P use libpcap format instead of pcapng\n");
fprintf(output, " --capture-comment <comment>\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. */ /* Don't print this if we're a capture child. */
if (!capture_child && reportit) { 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 */ /* stderr could be line buffered */
fflush(stderr); 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. * instead stop with an error.
*/ */
g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)", 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; break;
} }
@ -2505,7 +2504,7 @@ pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int err
* instead stop with an error. * instead stop with an error.
*/ */
g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)", 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; break;
} }
@ -3086,7 +3085,7 @@ capture_loop_dispatch(loop_data *ld,
gint packet_count_before; gint packet_count_before;
int sel_ret; int sel_ret;
packet_count_before = ld->packet_count; packet_count_before = ld->packets_captured;
if (pcap_src->from_cap_pipe) { if (pcap_src->from_cap_pipe) {
/* dispatch from capture pipe */ /* dispatch from capture pipe */
#ifdef LOG_CAPTURE_VERBOSE #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")); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: %d new packet%s", inpkts, plurality(inpkts, "", "s"));
#endif #endif
return ld->packet_count - packet_count_before; return ld->packets_captured - packet_count_before;
} }
#ifdef _WIN32 #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 /* Do the work of handling either the file size or file duration capture
conditions being reached, and switching files or stopping. */ conditions being reached, and switching files or stopping. */
static gboolean static gboolean
do_file_switch_or_stop(capture_options *capture_opts, do_file_switch_or_stop(capture_options *capture_opts)
condition_data *conditions)
{ {
guint i; guint i;
capture_src *pcap_src; capture_src *pcap_src;
@ -3471,8 +3469,8 @@ do_file_switch_or_stop(capture_options *capture_opts,
gboolean successful; gboolean successful;
if (capture_opts->multi_files_on) { if (capture_opts->multi_files_on) {
if (conditions->autostop_files && if (capture_opts->has_autostop_files &&
++global_ld.autostop_files >= conditions->autostop_files) { ++global_ld.file_count >= capture_opts->autostop_files) {
/* no files left: stop here */ /* no files left: stop here */
global_ld.go = FALSE; global_ld.go = FALSE;
return FALSE; return FALSE;
@ -3484,6 +3482,7 @@ do_file_switch_or_stop(capture_options *capture_opts,
/* File switch succeeded: reset the conditions */ /* File switch succeeded: reset the conditions */
global_ld.bytes_written = 0; global_ld.bytes_written = 0;
global_ld.packets_written = 0;
pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0); pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0);
if (pcap_src->from_pcapng) { if (pcap_src->from_pcapng) {
/* Write the saved SHB and all IDBs to start of next file */ /* 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; global_ld.go = FALSE;
return FALSE; return FALSE;
} }
if (conditions->file_duration_timer) { if (global_ld.file_duration_timer) {
g_timer_reset(conditions->file_duration_timer); g_timer_reset(global_ld.file_duration_timer);
} }
if (conditions->next_interval_time) { if (global_ld.next_interval_time) {
conditions->next_interval_time = get_next_time_interval(conditions->interval_s); global_ld.next_interval_time = get_next_time_interval(global_ld.interval_s);
} }
fflush(global_ld.pdh); fflush(global_ld.pdh);
if (!quiet) if (!quiet)
@ -3611,7 +3610,6 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
#endif #endif
int err_close; int err_close;
int inpkts; int inpkts;
condition_data conditions;
GTimer *autostop_duration_timer = NULL; GTimer *autostop_duration_timer = NULL;
gboolean write_ok; gboolean write_ok;
gboolean close_ok; gboolean close_ok;
@ -3627,19 +3625,18 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
/* init the loop data */ /* init the loop data */
global_ld.go = TRUE; global_ld.go = TRUE;
global_ld.packet_count = 0; global_ld.packets_captured = 0;
#ifdef SIGINFO #ifdef SIGINFO
global_ld.report_packet_count = FALSE; global_ld.report_packet_count = FALSE;
#endif #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.inpkts_to_sync_pipe = 0;
global_ld.err = 0; /* no error seen yet */ global_ld.err = 0; /* no error seen yet */
global_ld.pdh = NULL; global_ld.pdh = NULL;
global_ld.autostop_files = 0;
global_ld.save_file_fd = -1; 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. */ /* We haven't yet gotten the capture statistics. */
*stats_known = FALSE; *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); 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) { if (capture_opts->has_file_interval) {
conditions.interval_s = capture_opts->file_interval; global_ld.interval_s = capture_opts->file_interval;
conditions.next_interval_time = get_next_time_interval(conditions.interval_s); global_ld.next_interval_time = get_next_time_interval(global_ld.interval_s);
} }
/* create stop conditions */ /* create stop conditions */
if (capture_opts->has_autostop_filesize) { 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->multi_files_on) {
if (capture_opts->has_file_duration) { 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 */ /* init the time values */
@ -3809,8 +3801,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
#ifdef SIGINFO #ifdef SIGINFO
/* Were we asked to print packet counts by the SIGINFO handler? */ /* Were we asked to print packet counts by the SIGINFO handler? */
if (global_ld.report_packet_count) { if (global_ld.report_packet_count) {
fprintf(stderr, "%u packet%s captured\n", global_ld.packet_count, fprintf(stderr, "%u packet%s captured\n", global_ld.packets_captured,
plurality(global_ld.packet_count, "", "s")); plurality(global_ld.packets_captured, "", "s"));
global_ld.report_packet_count = FALSE; global_ld.report_packet_count = FALSE;
} }
#endif #endif
@ -3825,14 +3817,6 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
if (inpkts > 0) { if (inpkts > 0) {
global_ld.inpkts_to_sync_pipe += inpkts; 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) { if (capture_opts->output_to_pipe) {
fflush(global_ld.pdh); fflush(global_ld.pdh);
} }
@ -3882,16 +3866,16 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
} }
/* check capture file duration condition */ /* 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? */ /* 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; continue;
} /* cnd_file_duration */ } /* cnd_file_duration */
/* check capture file interval condition */ /* 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? */ /* 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; continue;
} /* cnd_file_interval */ } /* cnd_file_interval */
} }
@ -3937,8 +3921,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
/* delete stop conditions */ /* delete stop conditions */
if (conditions.file_duration_timer != NULL) if (global_ld.file_duration_timer != NULL)
g_timer_destroy(conditions.file_duration_timer); g_timer_destroy(global_ld.file_duration_timer);
if (autostop_duration_timer != NULL) if (autostop_duration_timer != NULL)
g_timer_destroy(autostop_duration_timer); 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.", "Wrote a packet of length %d captured on interface %u.",
bh->block_total_length, pcap_src->interface_id); bh->block_total_length, pcap_src->interface_id);
#endif #endif
global_ld.packet_count++; global_ld.packets_captured++;
global_ld.packets_written++;
pcap_src->received++; pcap_src->received++;
/* if the user told us to stop after x packets, do we already have enough? */ /* 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; 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.", "Wrote a packet of length %d captured on interface %u.",
phdr->caplen, pcap_src->interface_id); phdr->caplen, pcap_src->interface_id);
#endif #endif
global_ld.packet_count++; global_ld.packets_captured++;
global_ld.packets_written++;
pcap_src->received++; 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; 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 && if (!global_capture_opts.has_autostop_filesize &&
!global_capture_opts.has_file_duration && !global_capture_opts.has_file_duration &&
!global_capture_opts.has_file_interval) { !global_capture_opts.has_file_interval &&
cmdarg_err("Ring buffer requested, but no maximum capture file size, duration" !global_capture_opts.has_file_packets) {
"or interval were specified."); cmdarg_err("Ring buffer requested, but no maximum capture file size, duration "
"interval, or packets were specified.");
#if 0 #if 0
/* XXX - this must be redesigned as the conditions changed */ /* XXX - this must be redesigned as the conditions changed */
global_capture_opts.multi_files_on = FALSE; global_capture_opts.multi_files_on = FALSE;

View File

@ -10,6 +10,7 @@
'''Capture tests''' '''Capture tests'''
import config import config
import glob
import os import os
import re import re
import subprocess import subprocess
@ -17,6 +18,7 @@ import subprocesstest
import sys import sys
import time import time
import unittest import unittest
import uuid
capture_duration = 5 capture_duration = 5
@ -139,11 +141,6 @@ def check_capture_stdin(self, cmd=None):
if (pipe_returncode == 0): if (pipe_returncode == 0):
self.checkPacketCount(8) 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): def check_capture_read_filter(self, cmd=None):
if not config.canCapture(): if not config.canCapture():
self.skipTest('Test requires capture privileges and an interface.') 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): if (capture_returncode == 0):
self.checkPacketCount(0, cap_file=testout2_file) 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): class case_wireshark_capture(subprocesstest.SubprocessTestCase):
def test_wireshark_capture_10_packets_to_file(self): def test_wireshark_capture_10_packets_to_file(self):
'''Capture 10 packets from the network to a file using Wireshark''' '''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): def test_dumpcap_capture_snapshot_len(self):
'''Capture truncated packets using Dumpcap''' '''Capture truncated packets using Dumpcap'''
check_capture_snapshot_len(self, cmd=config.cmd_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(): def main():
parser = argparse.ArgumentParser(description='Dump dhcp.pcap') parser = argparse.ArgumentParser(description='Dump dhcp.pcap')
parser.add_argument('dump_type', choices=['cat', 'slow', 'raw'], parser.add_argument('dump_type', choices=['cat', 'cat100', 'slow', 'raw'],
help='cat: Just dump the file. slow: Dump the file, pause, and dump its packet records. raw: Dump only the packet records.') 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() args = parser.parse_args()
dhcp_pcap = os.path.join(os.path.dirname(__file__), 'captures', 'dhcp.pcap') dhcp_pcap = os.path.join(os.path.dirname(__file__), 'captures', 'dhcp.pcap')
@ -27,12 +27,17 @@ def main():
contents = dhcp_fd.read() contents = dhcp_fd.read()
if args.dump_type != 'raw': if args.dump_type != 'raw':
os.write(1, contents) 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) sys.exit(0)
if args.dump_type == 'slow': if args.dump_type == 'slow':
time.sleep(1.5) time.sleep(1.5)
# slow, raw # slow, raw
os.write(1, contents[24:]) os.write(1, contents[24:])
sys.exit(0) sys.exit(0)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -549,6 +549,10 @@ void CaptureInterfacesDialog::updateInterfaces()
} }
ui->gbNewFileAuto->setChecked(global_capture_opts.multi_files_on); 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->MBCheckBox->setChecked(global_capture_opts.has_autostop_filesize);
ui->SecsCheckBox->setChecked(global_capture_opts.has_file_interval); ui->SecsCheckBox->setChecked(global_capture_opts.has_file_interval);
if (global_capture_opts.has_autostop_filesize) { if (global_capture_opts.has_autostop_filesize) {
@ -850,6 +854,10 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
break; 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(); global_capture_opts.has_autostop_filesize = ui->MBCheckBox->isChecked();
if (global_capture_opts.has_autostop_filesize) { if (global_capture_opts.has_autostop_filesize) {
global_capture_opts.autostop_filesize = ui->MBSpinBox->value(); global_capture_opts.autostop_filesize = ui->MBSpinBox->value();
@ -878,9 +886,12 @@ bool CaptureInterfacesDialog::saveOptionsToPreferences()
QMessageBox::warning(this, tr("Error"), 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.")); tr("Multiple files: No capture file name given. You must specify a filename if you want to use multiple files."));
return false; 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"), 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); g_free(global_capture_opts.save_file);
global_capture_opts.save_file = NULL; global_capture_opts.save_file = NULL;
return false; return false;

View File

@ -262,10 +262,38 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="1" column="1"> <item row="0" column="3" rowspan="4">
<widget class="QSpinBox" name="MBSpinBox"> <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"> <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>
<property name="wrapping"> <property name="wrapping">
<bool>true</bool> <bool>true</bool>
@ -284,30 +312,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2"> <item row="3" 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">
<widget class="QComboBox" name="SecsComboBox"> <widget class="QComboBox" name="SecsComboBox">
<property name="toolTip"> <property name="toolTip">
<string>If the selected file size is exceeded, capturing switches to the next file. <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> </widget>
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QSpinBox" name="SecsSpinBox"> <widget class="QSpinBox" name="MBSpinBox">
<property name="toolTip"> <property name="toolTip">
<string>If the selected file size is exceeded, capturing switches to the next file. <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>
PLEASE NOTE: One option MUST be selected.</string>
</property> </property>
<property name="wrapping"> <property name="wrapping">
<bool>true</bool> <bool>true</bool>
@ -353,30 +357,56 @@ PLEASE NOTE: One option MUST be selected.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="3" rowspan="3"> <item row="2" column="2">
<spacer name="horizontalSpacer_8"> <widget class="QComboBox" name="MBComboBox">
<property name="orientation"> <property name="toolTip">
<enum>Qt::Horizontal</enum> <string>If the selected file size is exceeded, capturing switches to the next file.
PLEASE NOTE: One option MUST be selected.</string>
</property> </property>
<property name="sizeHint" stdset="0"> <item>
<size> <property name="text">
<width>40</width> <string>kilobytes</string>
<height>20</height> </property>
</size> </item>
</property> <item>
</spacer> <property name="text">
<string>megabytes</string>
</property>
</item>
<item>
<property name="text">
<string>gigabytes</string>
</property>
</item>
</widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="MBCheckBox"> <widget class="QCheckBox" name="PktCheckBox">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="1" column="1">
<widget class="QCheckBox" name="SecsCheckBox"> <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"> <property name="text">
<string/> <string>packets</string>
</property> </property>
</widget> </widget>
</item> </item>