forked from osmocom/wireshark
Dumpcap: Fix writing SHBs and IDBs.
If we have a single capture source and that capture source is pcapng and we're writing a pcapng file, do the following: - Pass its SHB and IDBs through unmodified. Don't save or write command line interface IDBs. - Save the most recent SHB and IDBs so that we can write them when we're writing multiple output files. If we have multiple capture sources, do the following: - Write Dumpcap's SHB. - Keep a global list of IDBs, consisting of both command line interfaces and IDBs read from pcapng sources. - When reading an EPB or ISB, remap its local interface number to its corresponding global number. Add Dumpcap pcapng section tests. Make the application IDs in the "many_interfaces" captures unique. Change-Id: I2005934c1f83d839727421960005f106d6c682dd Reviewed-on: https://code.wireshark.org/review/30085 Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot Reviewed-by: Gerald Combs <gerald@wireshark.org>
This commit is contained in:
parent
377f5d0de7
commit
f300676bec
431
dumpcap.c
431
dumpcap.c
|
@ -227,8 +227,7 @@ typedef struct _pcap_pipe_info {
|
||||||
|
|
||||||
typedef struct _pcapng_pipe_info {
|
typedef struct _pcapng_pipe_info {
|
||||||
struct pcapng_block_header_s bh; /**< Pcapng general block header when capturing from a pipe */
|
struct pcapng_block_header_s bh; /**< Pcapng general block header when capturing from a pipe */
|
||||||
struct pcapng_section_header_block_s shb; /**< Pcapng section header when capturing from a pipe */
|
GArray *src_iface_to_global; /**< Int array mapping local IDB numbers to global_ld.interface_data */
|
||||||
GList *saved_blocks; /**< Pcapng block list of SHB and IDBs for multi_file_on */
|
|
||||||
} pcapng_pipe_info_t;
|
} pcapng_pipe_info_t;
|
||||||
|
|
||||||
struct _loop_data; /* forward declaration so we can use it in the cap_pipe_dispatch function pointer */
|
struct _loop_data; /* forward declaration so we can use it in the cap_pipe_dispatch function pointer */
|
||||||
|
@ -284,6 +283,13 @@ typedef struct _capture_src {
|
||||||
#endif
|
#endif
|
||||||
} capture_src;
|
} capture_src;
|
||||||
|
|
||||||
|
typedef struct _saved_idb {
|
||||||
|
gboolean deleted;
|
||||||
|
guint interface_id; /* capture_src->interface_id for the associated SHB */
|
||||||
|
guint8 *idb; /* If non-NULL, IDB read from capture_src. This is an interface specified on the command line otherwise. */
|
||||||
|
guint idb_len;
|
||||||
|
} saved_idb_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global capture loop state.
|
* Global capture loop state.
|
||||||
*/
|
*/
|
||||||
|
@ -297,6 +303,10 @@ typedef struct _loop_data {
|
||||||
gboolean report_packet_count; /**< Set by SIGINFO handler; print packet count */
|
gboolean report_packet_count; /**< Set by SIGINFO handler; print packet count */
|
||||||
#endif
|
#endif
|
||||||
GArray *pcaps; /**< Array of capture_src's on which we're capturing */
|
GArray *pcaps; /**< Array of capture_src's on which we're capturing */
|
||||||
|
gboolean pcapng_passthrough; /**< We have one source and it's pcapng. Pass its SHB and IDBs through. */
|
||||||
|
guint8 *saved_shb; /**< SHB to write when we have one pcapng input */
|
||||||
|
GArray *saved_idbs; /**< Array of saved_idb_t, written when we have a new section or output file. */
|
||||||
|
GRWLock saved_shb_idb_lock; /**< Saved IDB RW mutex */
|
||||||
/* output file(s) */
|
/* output file(s) */
|
||||||
FILE *pdh;
|
FILE *pdh;
|
||||||
int save_file_fd;
|
int save_file_fd;
|
||||||
|
@ -329,7 +339,7 @@ static const char please_report[] =
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This needs to be static, so that the SIGINT handler can clear the "go"
|
* This needs to be static, so that the SIGINT handler can clear the "go"
|
||||||
* flag.
|
* flag and for saved_shb_idb_lock.
|
||||||
*/
|
*/
|
||||||
static loop_data global_ld;
|
static loop_data global_ld;
|
||||||
|
|
||||||
|
@ -1846,6 +1856,7 @@ cap_pipe_open_live(char *pipename,
|
||||||
/* This isn't pcap, it's pcapng. */
|
/* This isn't pcap, it's pcapng. */
|
||||||
pcap_src->from_pcapng = TRUE;
|
pcap_src->from_pcapng = TRUE;
|
||||||
pcap_src->cap_pipe_dispatch = pcapng_pipe_dispatch;
|
pcap_src->cap_pipe_dispatch = pcapng_pipe_dispatch;
|
||||||
|
pcap_src->cap_pipe_info.pcapng.src_iface_to_global = g_array_new(FALSE, FALSE, sizeof(guint32));
|
||||||
global_capture_opts.use_pcapng = TRUE; /* we can only output in pcapng format */
|
global_capture_opts.use_pcapng = TRUE; /* we can only output in pcapng format */
|
||||||
pcapng_pipe_open_live(fd, pcap_src, errmsg, errmsgl);
|
pcapng_pipe_open_live(fd, pcap_src, errmsg, errmsgl);
|
||||||
return;
|
return;
|
||||||
|
@ -1967,7 +1978,7 @@ pcapng_read_shb(capture_src *pcap_src,
|
||||||
char *errmsg,
|
char *errmsg,
|
||||||
int errmsgl)
|
int errmsgl)
|
||||||
{
|
{
|
||||||
struct pcapng_section_header_block_s *shb = &pcap_src->cap_pipe_info.pcapng.shb;
|
struct pcapng_section_header_block_s shb;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (pcap_src->from_cap_socket)
|
if (pcap_src->from_cap_socket)
|
||||||
|
@ -1997,8 +2008,8 @@ pcapng_read_shb(capture_src *pcap_src,
|
||||||
pcap_src->cap_pipe_bytes_read = sizeof(struct pcapng_block_header_s) + sizeof(struct pcapng_section_header_block_s);
|
pcap_src->cap_pipe_bytes_read = sizeof(struct pcapng_block_header_s) + sizeof(struct pcapng_section_header_block_s);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
memcpy(shb, pcap_src->cap_pipe_databuf + sizeof(struct pcapng_block_header_s), sizeof(struct pcapng_section_header_block_s));
|
memcpy(&shb, pcap_src->cap_pipe_databuf + sizeof(struct pcapng_block_header_s), sizeof(struct pcapng_section_header_block_s));
|
||||||
switch (shb->magic)
|
switch (shb.magic)
|
||||||
{
|
{
|
||||||
case PCAPNG_MAGIC:
|
case PCAPNG_MAGIC:
|
||||||
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng SHB MAGIC");
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng SHB MAGIC");
|
||||||
|
@ -2034,29 +2045,101 @@ pcapng_read_shb(capture_src *pcap_src,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save SHB and IDB blocks to playback whenever we change output files. */
|
/*
|
||||||
/* The list is saved in reverse order of blocks added */
|
* Save IDB blocks for playback whenever we change output files.
|
||||||
|
* Rewrite EPB and ISB interface IDs.
|
||||||
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
pcapng_block_save(capture_src *pcap_src)
|
pcapng_adjust_block(loop_data *ld, capture_src *pcap_src)
|
||||||
{
|
{
|
||||||
pcapng_pipe_info_t *pcapng = &pcap_src->cap_pipe_info.pcapng;
|
pcapng_pipe_info_t *pcapng = &pcap_src->cap_pipe_info.pcapng;
|
||||||
struct pcapng_block_header_s *bh = &pcapng->bh;
|
struct pcapng_block_header_s *bh = &pcapng->bh;
|
||||||
|
|
||||||
/* Delete all the old blocks first whenever we get a SHB */
|
switch(bh->block_type) {
|
||||||
if (bh->block_type == BLOCK_TYPE_SHB) {
|
case BLOCK_TYPE_SHB:
|
||||||
g_list_free_full(pcapng->saved_blocks, g_free);
|
{
|
||||||
pcapng->saved_blocks = NULL;
|
g_rw_lock_writer_lock (&ld->saved_shb_idb_lock);
|
||||||
} else if (bh->block_type != BLOCK_TYPE_IDB) {
|
if (ld->pcapng_passthrough) {
|
||||||
return TRUE;
|
/*
|
||||||
}
|
* We have a single pcapng input. We pass the SHB through when
|
||||||
|
* writing a single output file and for the first ring buffer
|
||||||
|
* file. We need to save it for the second and subsequent ring
|
||||||
|
* buffer files.
|
||||||
|
*/
|
||||||
|
g_free(ld->saved_shb);
|
||||||
|
ld->saved_shb = (guint8 *) g_memdup(pcap_src->cap_pipe_databuf, bh->block_total_length);
|
||||||
|
|
||||||
gpointer data = g_malloc(bh->block_total_length);
|
/*
|
||||||
if (data == NULL) {
|
* We're dealing with one section at a time, so we can (and must)
|
||||||
return FALSE;
|
* get rid of our old IDBs.
|
||||||
}
|
*/
|
||||||
memcpy(data, pcap_src->cap_pipe_databuf, bh->block_total_length);
|
for (unsigned i = 0; i < ld->saved_idbs->len; i++) {
|
||||||
|
saved_idb_t *idb_source = &g_array_index(ld->saved_idbs, saved_idb_t, i);
|
||||||
|
g_free(idb_source->idb);
|
||||||
|
}
|
||||||
|
g_array_set_size(ld->saved_idbs, 0);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* We have a new SHB from this capture source. We need to keep
|
||||||
|
* global_ld.saved_idbs intact, so we mark IDBs we previously
|
||||||
|
* collected from this source as deleted.
|
||||||
|
*/
|
||||||
|
for (unsigned i = 0; i < pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len; i++) {
|
||||||
|
guint32 iface_id = g_array_index(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, guint32, i);
|
||||||
|
saved_idb_t *idb_source = &g_array_index(ld->saved_idbs, saved_idb_t, iface_id);
|
||||||
|
g_assert(idb_source->interface_id == pcap_src->interface_id);
|
||||||
|
g_free(idb_source->idb);
|
||||||
|
memset(idb_source, 0, sizeof(saved_idb_t));
|
||||||
|
idb_source->deleted = TRUE;
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: deleted pcapng IDB %u", G_STRFUNC, iface_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_rw_lock_writer_unlock (&ld->saved_shb_idb_lock);
|
||||||
|
|
||||||
pcapng->saved_blocks = g_list_prepend(pcapng->saved_blocks, data);
|
g_array_set_size(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLOCK_TYPE_IDB:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Always gather IDBs. We can remove them or mark them as deleted
|
||||||
|
* when we get a new SHB.
|
||||||
|
*/
|
||||||
|
saved_idb_t idb_source = { 0 };
|
||||||
|
idb_source.interface_id = pcap_src->interface_id;
|
||||||
|
idb_source.idb_len = bh->block_total_length;
|
||||||
|
idb_source.idb = (guint8 *) g_memdup(pcap_src->cap_pipe_databuf, idb_source.idb_len);
|
||||||
|
g_rw_lock_writer_lock (&ld->saved_shb_idb_lock);
|
||||||
|
g_array_append_val(ld->saved_idbs, idb_source);
|
||||||
|
guint32 iface_id = ld->saved_idbs->len - 1;
|
||||||
|
g_rw_lock_writer_unlock (&ld->saved_shb_idb_lock);
|
||||||
|
g_array_append_val(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, iface_id);
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: saved pcapng IDB %u -> %u from source %u",
|
||||||
|
G_STRFUNC, pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len - 1, iface_id, pcap_src->interface_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLOCK_TYPE_EPB:
|
||||||
|
case BLOCK_TYPE_ISB:
|
||||||
|
{
|
||||||
|
if (ld->pcapng_passthrough) {
|
||||||
|
/* Our input and output interface IDs are the same. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* The interface ID is the first 32-bit field after the BH for both EPBs and ISBs. */
|
||||||
|
guint32 iface_id;
|
||||||
|
memcpy(&iface_id, pcap_src->cap_pipe_databuf + sizeof(struct pcapng_block_header_s), 4);
|
||||||
|
if (iface_id < pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len) {
|
||||||
|
memcpy(pcap_src->cap_pipe_databuf + sizeof(struct pcapng_block_header_s),
|
||||||
|
&g_array_index(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, guint32, iface_id), 4);
|
||||||
|
} else {
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: pcapng EPB or ISB interface id %u > max %u", G_STRFUNC, iface_id, pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -2545,7 +2628,7 @@ pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int err
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case PD_DATA_READ:
|
case PD_DATA_READ:
|
||||||
if (!pcapng_block_save(pcap_src)) {
|
if (!pcapng_adjust_block(ld, pcap_src)) {
|
||||||
g_snprintf(errmsg, errmsgl, "pcapng_pipe_dispatch block save failed");
|
g_snprintf(errmsg, errmsgl, "pcapng_pipe_dispatch block save failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -2656,6 +2739,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pcapng_src_count = 0;
|
||||||
for (i = 0; i < capture_opts->ifaces->len; i++) {
|
for (i = 0; i < capture_opts->ifaces->len; i++) {
|
||||||
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
|
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
|
||||||
pcap_src = (capture_src *)g_malloc0(sizeof (capture_src));
|
pcap_src = (capture_src *)g_malloc0(sizeof (capture_src));
|
||||||
|
@ -2664,6 +2748,19 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
|
||||||
"Could not allocate memory.");
|
"Could not allocate memory.");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add our pcapng interface entry. This will be deleted further
|
||||||
|
* down if pcapng_passthrough == TRUE.
|
||||||
|
*/
|
||||||
|
saved_idb_t idb_source = { 0 };
|
||||||
|
idb_source.interface_id = i;
|
||||||
|
g_rw_lock_writer_lock (&ld->saved_shb_idb_lock);
|
||||||
|
g_array_append_val(global_ld.saved_idbs, idb_source);
|
||||||
|
g_rw_lock_writer_unlock (&ld->saved_shb_idb_lock);
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: saved capture_opts IDB %u",
|
||||||
|
G_STRFUNC, i);
|
||||||
|
|
||||||
#ifdef MUST_DO_SELECT
|
#ifdef MUST_DO_SELECT
|
||||||
pcap_src->pcap_fd = -1;
|
pcap_src->pcap_fd = -1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2801,6 +2898,17 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
|
||||||
report_capture_error(sync_msg_str, "");
|
report_capture_error(sync_msg_str, "");
|
||||||
g_free(sync_msg_str);
|
g_free(sync_msg_str);
|
||||||
}
|
}
|
||||||
|
if (pcap_src->from_pcapng) {
|
||||||
|
pcapng_src_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (capture_opts->ifaces->len == 1 && pcapng_src_count == 1) {
|
||||||
|
ld->pcapng_passthrough = TRUE;
|
||||||
|
g_rw_lock_writer_lock (&ld->saved_shb_idb_lock);
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: Clearing %u interfaces for passthrough",
|
||||||
|
G_STRFUNC, global_ld.saved_idbs->len);
|
||||||
|
g_array_set_size(global_ld.saved_idbs, 0);
|
||||||
|
g_rw_lock_writer_unlock (&ld->saved_shb_idb_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If not using libcap: we now can now set euid/egid to ruid/rgid */
|
/* If not using libcap: we now can now set euid/egid to ruid/rgid */
|
||||||
|
@ -2845,8 +2953,8 @@ static void capture_loop_close_input(loop_data *ld)
|
||||||
pcap_src->cap_pipe_databuf = NULL;
|
pcap_src->cap_pipe_databuf = NULL;
|
||||||
}
|
}
|
||||||
if (pcap_src->from_pcapng) {
|
if (pcap_src->from_pcapng) {
|
||||||
g_list_free_full(pcap_src->cap_pipe_info.pcapng.saved_blocks, g_free);
|
g_array_free(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, TRUE);
|
||||||
pcap_src->cap_pipe_info.pcapng.saved_blocks = NULL;
|
pcap_src->cap_pipe_info.pcapng.src_iface_to_global = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Capture device. If open, close the pcap_t. */
|
/* Capture device. If open, close the pcap_t. */
|
||||||
|
@ -2899,15 +3007,124 @@ capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe,
|
||||||
return INITFILTER_NO_ERROR;
|
return INITFILTER_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the dumpcap pcapng SHB and IDBs if needed.
|
||||||
|
* Called from capture_loop_init_output and do_file_switch_or_stop.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
capture_loop_init_pcapng_output(capture_options *capture_opts, loop_data *ld)
|
||||||
|
{
|
||||||
|
g_rw_lock_reader_lock (&ld->saved_shb_idb_lock);
|
||||||
|
|
||||||
|
if (ld->pcapng_passthrough && !ld->saved_shb) {
|
||||||
|
/* We have a single pcapng capture interface and this is the first or only output file. */
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: skipping dumpcap SHB and IDBs in favor of source", G_STRFUNC);
|
||||||
|
g_rw_lock_reader_unlock (&ld->saved_shb_idb_lock);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean successful = TRUE;
|
||||||
|
int err;
|
||||||
|
GString *os_info_str = g_string_new("");
|
||||||
|
|
||||||
|
get_os_version_info(os_info_str);
|
||||||
|
|
||||||
|
if (ld->saved_shb) {
|
||||||
|
/* We have a single pcapng capture interface and multiple output files. */
|
||||||
|
|
||||||
|
struct pcapng_block_header_s bh;
|
||||||
|
|
||||||
|
memcpy(&bh, ld->saved_shb, sizeof(struct pcapng_block_header_s));
|
||||||
|
|
||||||
|
successful = pcapng_write_block(ld->pdh, ld->saved_shb, bh.block_total_length, &ld->bytes_written, &err);
|
||||||
|
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: wrote saved passthrough SHB %d", G_STRFUNC, successful);
|
||||||
|
} else {
|
||||||
|
GString *cpu_info_str = g_string_new("");
|
||||||
|
get_cpu_info(cpu_info_str);
|
||||||
|
|
||||||
|
char *appname = g_strdup_printf("Dumpcap (Wireshark) %s", get_ws_vcs_version_info());
|
||||||
|
successful = pcapng_write_session_header_block(ld->pdh,
|
||||||
|
(const char *)capture_opts->capture_comment, /* Comment */
|
||||||
|
cpu_info_str->str, /* HW */
|
||||||
|
os_info_str->str, /* OS */
|
||||||
|
appname,
|
||||||
|
-1, /* section_length */
|
||||||
|
&ld->bytes_written,
|
||||||
|
&err);
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: wrote dumpcap SHB %d", G_STRFUNC, successful);
|
||||||
|
g_string_free(cpu_info_str, TRUE);
|
||||||
|
g_free(appname);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; successful && (i < ld->saved_idbs->len); i++) {
|
||||||
|
saved_idb_t idb_source = g_array_index(ld->saved_idbs, saved_idb_t, i);
|
||||||
|
if (idb_source.deleted) {
|
||||||
|
/*
|
||||||
|
* Our interface is out of scope. Suppose we're writing multiple
|
||||||
|
* files and a source switches sections. We currently write dummy
|
||||||
|
* IDBs like so:
|
||||||
|
*
|
||||||
|
* File 1: IDB0, IDB1, IDB2
|
||||||
|
* [ The source of IDBs 1 and 2 writes an SHB with two new IDBs ]
|
||||||
|
* [ We switch output files ]
|
||||||
|
* File 2: IDB0, dummy IDB, dummy IDB, IDB3, IDB4
|
||||||
|
*
|
||||||
|
* It might make more sense to write the original data so that
|
||||||
|
* so that our IDB lists are more consistent across files.
|
||||||
|
*/
|
||||||
|
successful = pcapng_write_interface_description_block(global_ld.pdh,
|
||||||
|
"Interface went out of scope", /* OPT_COMMENT 1 */
|
||||||
|
"dummy", /* IDB_NAME 2 */
|
||||||
|
"Dumpcap dummy interface", /* IDB_DESCRIPTION 3 */
|
||||||
|
NULL, /* IDB_FILTER 11 */
|
||||||
|
os_info_str->str, /* IDB_OS 12 */
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
&(global_ld.bytes_written),
|
||||||
|
0, /* IDB_IF_SPEED 8 */
|
||||||
|
6, /* IDB_TSRESOL 9 */
|
||||||
|
&global_ld.err);
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: skipping deleted pcapng IDB %u", G_STRFUNC, i);
|
||||||
|
} else if (idb_source.idb && idb_source.idb_len) {
|
||||||
|
successful = pcapng_write_block(global_ld.pdh, idb_source.idb, idb_source.idb_len, &ld->bytes_written, &err);
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: wrote pcapng IDB %d", G_STRFUNC, successful);
|
||||||
|
} else if (idb_source.interface_id < capture_opts->ifaces->len) {
|
||||||
|
unsigned if_id = idb_source.interface_id;
|
||||||
|
interface_options *interface_opts = &g_array_index(capture_opts->ifaces, interface_options, if_id);
|
||||||
|
capture_src *pcap_src = g_array_index(ld->pcaps, capture_src *, if_id);
|
||||||
|
if (pcap_src->from_cap_pipe) {
|
||||||
|
pcap_src->snaplen = pcap_src->cap_pipe_info.pcap.hdr.snaplen;
|
||||||
|
} else {
|
||||||
|
pcap_src->snaplen = pcap_snapshot(pcap_src->pcap_h);
|
||||||
|
}
|
||||||
|
successful = pcapng_write_interface_description_block(global_ld.pdh,
|
||||||
|
NULL, /* OPT_COMMENT 1 */
|
||||||
|
interface_opts->name, /* IDB_NAME 2 */
|
||||||
|
interface_opts->descr, /* IDB_DESCRIPTION 3 */
|
||||||
|
interface_opts->cfilter, /* IDB_FILTER 11 */
|
||||||
|
os_info_str->str, /* IDB_OS 12 */
|
||||||
|
pcap_src->linktype,
|
||||||
|
pcap_src->snaplen,
|
||||||
|
&(global_ld.bytes_written),
|
||||||
|
0, /* IDB_IF_SPEED 8 */
|
||||||
|
pcap_src->ts_nsec ? 9 : 6, /* IDB_TSRESOL 9 */
|
||||||
|
&global_ld.err);
|
||||||
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: wrote capture_opts IDB %d: %d", G_STRFUNC, if_id, successful);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_rw_lock_reader_unlock (&ld->saved_shb_idb_lock);
|
||||||
|
|
||||||
|
g_string_free(os_info_str, TRUE);
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
/* set up to write to the already-opened capture output file/files */
|
/* set up to write to the already-opened capture output file/files */
|
||||||
static gboolean
|
static gboolean
|
||||||
capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len)
|
capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
guint i;
|
|
||||||
capture_src *pcap_src;
|
|
||||||
interface_options *interface_opts;
|
|
||||||
gboolean successful;
|
gboolean successful;
|
||||||
|
|
||||||
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_init_output");
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_init_output");
|
||||||
|
@ -2929,58 +3146,10 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ld->pdh) {
|
if (ld->pdh) {
|
||||||
pcap_src = g_array_index(ld->pcaps, capture_src *, 0);
|
|
||||||
if (pcap_src->from_pcapng) {
|
|
||||||
/* We are just going to rewrite the source SHB and IDB blocks */
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
if (capture_opts->use_pcapng) {
|
if (capture_opts->use_pcapng) {
|
||||||
char *appname;
|
successful = capture_loop_init_pcapng_output(capture_opts, ld);
|
||||||
GString *cpu_info_str;
|
|
||||||
GString *os_info_str;
|
|
||||||
|
|
||||||
cpu_info_str = g_string_new("");
|
|
||||||
os_info_str = g_string_new("");
|
|
||||||
get_cpu_info(cpu_info_str);
|
|
||||||
get_os_version_info(os_info_str);
|
|
||||||
|
|
||||||
appname = g_strdup_printf("Dumpcap (Wireshark) %s", get_ws_vcs_version_info());
|
|
||||||
successful = pcapng_write_session_header_block(ld->pdh,
|
|
||||||
(const char *)capture_opts->capture_comment, /* Comment */
|
|
||||||
cpu_info_str->str, /* HW */
|
|
||||||
os_info_str->str, /* OS */
|
|
||||||
appname,
|
|
||||||
-1, /* section_length */
|
|
||||||
&ld->bytes_written,
|
|
||||||
&err);
|
|
||||||
g_string_free(cpu_info_str, TRUE);
|
|
||||||
g_free(appname);
|
|
||||||
|
|
||||||
for (i = 0; successful && (i < capture_opts->ifaces->len); i++) {
|
|
||||||
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
|
|
||||||
pcap_src = g_array_index(ld->pcaps, capture_src *, i);
|
|
||||||
if (pcap_src->from_cap_pipe) {
|
|
||||||
pcap_src->snaplen = pcap_src->cap_pipe_info.pcap.hdr.snaplen;
|
|
||||||
} else {
|
|
||||||
pcap_src->snaplen = pcap_snapshot(pcap_src->pcap_h);
|
|
||||||
}
|
|
||||||
successful = pcapng_write_interface_description_block(global_ld.pdh,
|
|
||||||
NULL, /* OPT_COMMENT 1 */
|
|
||||||
interface_opts->name, /* IDB_NAME 2 */
|
|
||||||
interface_opts->descr, /* IDB_DESCRIPTION 3 */
|
|
||||||
interface_opts->cfilter, /* IDB_FILTER 11 */
|
|
||||||
os_info_str->str, /* IDB_OS 12 */
|
|
||||||
pcap_src->linktype,
|
|
||||||
pcap_src->snaplen,
|
|
||||||
&(global_ld.bytes_written),
|
|
||||||
0, /* IDB_IF_SPEED 8 */
|
|
||||||
pcap_src->ts_nsec ? 9 : 6, /* IDB_TSRESOL 9 */
|
|
||||||
&global_ld.err);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_string_free(os_info_str, TRUE);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
capture_src *pcap_src;
|
||||||
pcap_src = g_array_index(ld->pcaps, capture_src *, 0);
|
pcap_src = g_array_index(ld->pcaps, capture_src *, 0);
|
||||||
if (pcap_src->from_cap_pipe) {
|
if (pcap_src->from_cap_pipe) {
|
||||||
pcap_src->snaplen = pcap_src->cap_pipe_info.pcap.hdr.snaplen;
|
pcap_src->snaplen = pcap_src->cap_pipe_info.pcap.hdr.snaplen;
|
||||||
|
@ -3471,9 +3640,6 @@ static time_t get_next_time_interval(int interval_s) {
|
||||||
static gboolean
|
static gboolean
|
||||||
do_file_switch_or_stop(capture_options *capture_opts)
|
do_file_switch_or_stop(capture_options *capture_opts)
|
||||||
{
|
{
|
||||||
guint i;
|
|
||||||
capture_src *pcap_src;
|
|
||||||
interface_options *interface_opts;
|
|
||||||
gboolean successful;
|
gboolean successful;
|
||||||
|
|
||||||
if (capture_opts->multi_files_on) {
|
if (capture_opts->multi_files_on) {
|
||||||
|
@ -3491,70 +3657,15 @@ 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;
|
global_ld.packets_written = 0;
|
||||||
pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0);
|
if (capture_opts->use_pcapng) {
|
||||||
if (pcap_src->from_pcapng) {
|
successful = capture_loop_init_pcapng_output(capture_opts, &global_ld);
|
||||||
/* Write the saved SHB and all IDBs to start of next file */
|
|
||||||
/* The blocks were saved in reverse so reverse it before iterating */
|
|
||||||
GList *rlist = g_list_reverse(pcap_src->cap_pipe_info.pcapng.saved_blocks);
|
|
||||||
GList *list = rlist;
|
|
||||||
successful = TRUE;
|
|
||||||
while (list && successful) {
|
|
||||||
struct pcapng_block_header_s *bh = (struct pcapng_block_header_s *) list->data;
|
|
||||||
successful = pcapng_write_block(global_ld.pdh,
|
|
||||||
(const guint8 *) bh,
|
|
||||||
bh->block_total_length,
|
|
||||||
&global_ld.bytes_written, &global_ld.err);
|
|
||||||
list = g_list_next(list);
|
|
||||||
}
|
|
||||||
pcap_src->cap_pipe_info.pcapng.saved_blocks = g_list_reverse(rlist);
|
|
||||||
} else {
|
} else {
|
||||||
if (capture_opts->use_pcapng) {
|
capture_src *pcap_src;
|
||||||
char *appname;
|
pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0);
|
||||||
GString *cpu_info_str;
|
successful = libpcap_write_file_header(global_ld.pdh, pcap_src->linktype, pcap_src->snaplen,
|
||||||
GString *os_info_str;
|
pcap_src->ts_nsec, &global_ld.bytes_written, &global_ld.err);
|
||||||
|
|
||||||
cpu_info_str = g_string_new("");
|
|
||||||
os_info_str = g_string_new("");
|
|
||||||
get_cpu_info(cpu_info_str);
|
|
||||||
get_os_version_info(os_info_str);
|
|
||||||
|
|
||||||
appname = g_strdup_printf("Dumpcap (Wireshark) %s", get_ws_vcs_version_info());
|
|
||||||
successful = pcapng_write_session_header_block(global_ld.pdh,
|
|
||||||
(const char *)capture_opts->capture_comment, /* Comment */
|
|
||||||
cpu_info_str->str, /* HW */
|
|
||||||
os_info_str->str, /* OS */
|
|
||||||
appname,
|
|
||||||
-1, /* section_length */
|
|
||||||
&(global_ld.bytes_written),
|
|
||||||
&global_ld.err);
|
|
||||||
g_string_free(cpu_info_str, TRUE);
|
|
||||||
g_free(appname);
|
|
||||||
|
|
||||||
for (i = 0; successful && (i < capture_opts->ifaces->len); i++) {
|
|
||||||
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
|
|
||||||
pcap_src = g_array_index(global_ld.pcaps, capture_src *, i);
|
|
||||||
successful = pcapng_write_interface_description_block(global_ld.pdh,
|
|
||||||
NULL, /* OPT_COMMENT 1 */
|
|
||||||
interface_opts->name, /* IDB_NAME 2 */
|
|
||||||
interface_opts->descr, /* IDB_DESCRIPTION 3 */
|
|
||||||
interface_opts->cfilter, /* IDB_FILTER 11 */
|
|
||||||
os_info_str->str, /* IDB_OS 12 */
|
|
||||||
pcap_src->linktype,
|
|
||||||
pcap_src->snaplen,
|
|
||||||
&(global_ld.bytes_written),
|
|
||||||
0, /* IDB_IF_SPEED 8 */
|
|
||||||
pcap_src->ts_nsec ? 9 : 6, /* IDB_TSRESOL 9 */
|
|
||||||
&global_ld.err);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_string_free(os_info_str, TRUE);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0);
|
|
||||||
successful = libpcap_write_file_header(global_ld.pdh, pcap_src->linktype, pcap_src->snaplen,
|
|
||||||
pcap_src->ts_nsec, &global_ld.bytes_written, &global_ld.err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!successful) {
|
if (!successful) {
|
||||||
fclose(global_ld.pdh);
|
fclose(global_ld.pdh);
|
||||||
global_ld.pdh = NULL;
|
global_ld.pdh = NULL;
|
||||||
|
@ -4222,6 +4333,15 @@ capture_loop_write_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_he
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bh->block_type == BLOCK_TYPE_SHB && !global_ld.pcapng_passthrough) {
|
||||||
|
/*
|
||||||
|
* capture_loop_init_pcapng_output should've handled this. We need
|
||||||
|
* to write ISBs when they're initially read so we shouldn't skip
|
||||||
|
* them here.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (global_ld.pdh) {
|
if (global_ld.pdh) {
|
||||||
gboolean successful;
|
gboolean successful;
|
||||||
|
|
||||||
|
@ -4242,15 +4362,15 @@ capture_loop_write_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_he
|
||||||
/* count packet only if we actually have an EPB or SPB */
|
/* count packet only if we actually have an EPB or SPB */
|
||||||
#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP)
|
#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP)
|
||||||
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
|
||||||
"Wrote a packet of length %d captured on interface %u.",
|
"Wrote a pcapng block type %u of length %d captured on interface %u.",
|
||||||
bh->block_total_length, pcap_src->interface_id);
|
bh->block_type, bh->block_total_length, pcap_src->interface_id);
|
||||||
#endif
|
#endif
|
||||||
capture_loop_wrote_one_packet(pcap_src);
|
capture_loop_wrote_one_packet(pcap_src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* one packet was captured, process it */
|
/* one pcap packet was captured, process it */
|
||||||
static void
|
static void
|
||||||
capture_loop_write_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr,
|
capture_loop_write_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr,
|
||||||
const u_char *pd)
|
const u_char *pd)
|
||||||
|
@ -4298,7 +4418,7 @@ capture_loop_write_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr,
|
||||||
} else {
|
} else {
|
||||||
#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP)
|
#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP)
|
||||||
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
|
||||||
"Wrote a packet of length %d captured on interface %u.",
|
"Wrote a pcap packet of length %d captured on interface %u.",
|
||||||
phdr->caplen, pcap_src->interface_id);
|
phdr->caplen, pcap_src->interface_id);
|
||||||
#endif
|
#endif
|
||||||
capture_loop_wrote_one_packet(pcap_src);
|
capture_loop_wrote_one_packet(pcap_src);
|
||||||
|
@ -4418,8 +4538,8 @@ capture_loop_queue_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_he
|
||||||
} else {
|
} else {
|
||||||
pcap_src->received++;
|
pcap_src->received++;
|
||||||
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
|
||||||
"Queued a packet of length %d captured on interface %u.",
|
"Queued a block of type 0x%08x of length %d captured on interface %u.",
|
||||||
bh->block_total_length, pcap_src->interface_id);
|
bh->block_type, bh->block_total_length, pcap_src->interface_id);
|
||||||
}
|
}
|
||||||
/* I don't want to hold the mutex over the debug output. So the
|
/* I don't want to hold the mutex over the debug output. So the
|
||||||
output may be wrong */
|
output may be wrong */
|
||||||
|
@ -4689,8 +4809,11 @@ real_main(int argc, char *argv[])
|
||||||
log_flags,
|
log_flags,
|
||||||
console_log_handler, NULL /* user_data */);
|
console_log_handler, NULL /* user_data */);
|
||||||
|
|
||||||
/* Initialize the pcaps list */
|
/* Initialize the pcaps list and IDBs */
|
||||||
global_ld.pcaps = g_array_new(FALSE, FALSE, sizeof(capture_src *));
|
global_ld.pcaps = g_array_new(FALSE, FALSE, sizeof(capture_src *));
|
||||||
|
global_ld.pcapng_passthrough = FALSE;
|
||||||
|
global_ld.saved_shb = NULL;
|
||||||
|
global_ld.saved_idbs = g_array_new(FALSE, TRUE, sizeof(saved_idb_t));
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* Load wpcap if possible. Do this before collecting the run-time version information */
|
/* Load wpcap if possible. Do this before collecting the run-time version information */
|
||||||
|
@ -5382,13 +5505,13 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
|
||||||
static void
|
static void
|
||||||
report_packet_count(unsigned int packet_count)
|
report_packet_count(unsigned int packet_count)
|
||||||
{
|
{
|
||||||
char tmp[SP_DECISIZE+1+1];
|
char count_str[SP_DECISIZE+1+1];
|
||||||
static unsigned int count = 0;
|
static unsigned int count = 0;
|
||||||
|
|
||||||
if (capture_child) {
|
if (capture_child) {
|
||||||
g_snprintf(tmp, sizeof(tmp), "%u", packet_count);
|
g_snprintf(count_str, sizeof(count_str), "%u", packet_count);
|
||||||
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp);
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", count_str);
|
||||||
pipe_write_block(2, SP_PACKET_COUNT, tmp);
|
pipe_write_block(2, SP_PACKET_COUNT, count_str);
|
||||||
} else {
|
} else {
|
||||||
count += packet_count;
|
count += packet_count;
|
||||||
fprintf(stderr, "\rPackets: %u ", count);
|
fprintf(stderr, "\rPackets: %u ", count);
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -9,7 +9,6 @@
|
||||||
#
|
#
|
||||||
'''Subprocess test case superclass'''
|
'''Subprocess test case superclass'''
|
||||||
|
|
||||||
import config
|
|
||||||
import difflib
|
import difflib
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
@ -35,6 +34,19 @@ def cat_dhcp_command(mode):
|
||||||
sd_cmd += os.path.join(this_dir, 'util_dump_dhcp_pcap.py ' + mode)
|
sd_cmd += os.path.join(this_dir, 'util_dump_dhcp_pcap.py ' + mode)
|
||||||
return sd_cmd
|
return sd_cmd
|
||||||
|
|
||||||
|
def cat_cap_file_command(cap_files):
|
||||||
|
'''Create a command string for dumping one or more capture files to stdout'''
|
||||||
|
# XXX Do this in Python in a thread?
|
||||||
|
if isinstance(cap_files, str):
|
||||||
|
cap_files = [ cap_files ]
|
||||||
|
quoted_paths = ' '.join('"{}"'.format(cap_file) for cap_file in cap_files)
|
||||||
|
if sys.platform.startswith('win32'):
|
||||||
|
# https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb491026(v=technet.10)
|
||||||
|
# says that the `type` command "displays the contents of a text
|
||||||
|
# file." Copy to the console instead.
|
||||||
|
return 'copy {} CON'.format(quoted_paths)
|
||||||
|
return 'cat {}'.format(quoted_paths)
|
||||||
|
|
||||||
class LoggingPopen(subprocess.Popen):
|
class LoggingPopen(subprocess.Popen):
|
||||||
'''Run a process using subprocess.Popen. Capture and log its output.
|
'''Run a process using subprocess.Popen. Capture and log its output.
|
||||||
|
|
||||||
|
|
|
@ -9,18 +9,20 @@
|
||||||
#
|
#
|
||||||
'''Capture tests'''
|
'''Capture tests'''
|
||||||
|
|
||||||
|
import fixtures
|
||||||
import glob
|
import glob
|
||||||
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import subprocesstest
|
import subprocesstest
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
import fixtures
|
|
||||||
|
|
||||||
capture_duration = 5
|
capture_duration = 5
|
||||||
|
|
||||||
testout_pcap = 'testout.pcap'
|
testout_pcap = 'testout.pcap'
|
||||||
|
testout_pcapng = 'testout.pcapng'
|
||||||
snapshot_len = 96
|
snapshot_len = 96
|
||||||
|
|
||||||
@fixtures.fixture
|
@fixtures.fixture
|
||||||
|
@ -71,6 +73,7 @@ def traffic_generator():
|
||||||
def wireshark_k(wireshark_command):
|
def wireshark_k(wireshark_command):
|
||||||
return tuple(list(wireshark_command) + ['-k'])
|
return tuple(list(wireshark_command) + ['-k'])
|
||||||
|
|
||||||
|
|
||||||
def capture_command(*cmd_args, shell=False):
|
def capture_command(*cmd_args, shell=False):
|
||||||
if type(cmd_args[0]) != str:
|
if type(cmd_args[0]) != str:
|
||||||
# Assume something like ['wireshark', '-k']
|
# Assume something like ['wireshark', '-k']
|
||||||
|
@ -326,6 +329,165 @@ def check_dumpcap_ringbuffer_stdin(cmd_dumpcap):
|
||||||
return check_dumpcap_ringbuffer_stdin_real
|
return check_dumpcap_ringbuffer_stdin_real
|
||||||
|
|
||||||
|
|
||||||
|
@fixtures.fixture
|
||||||
|
def check_dumpcap_pcapng_sections(cmd_dumpcap, cmd_tshark, capture_file):
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
fixtures.skip('Test requires OS fifo support.')
|
||||||
|
def check_dumpcap_pcapng_sections_real(self, multi_input=False, multi_output=False):
|
||||||
|
# Make sure we always test multiple SHBs in an input.
|
||||||
|
in_files_l = [ [
|
||||||
|
capture_file('many_interfaces.pcapng.1'),
|
||||||
|
capture_file('many_interfaces.pcapng.2')
|
||||||
|
] ]
|
||||||
|
if multi_input:
|
||||||
|
in_files_l.append([ capture_file('many_interfaces.pcapng.3') ])
|
||||||
|
fifo_files = []
|
||||||
|
fifo_procs = []
|
||||||
|
# Default values for our validity tests
|
||||||
|
check_val_d = {
|
||||||
|
'filename': None,
|
||||||
|
'packet_count': 0,
|
||||||
|
'idb_count': 0,
|
||||||
|
'ua_pt1_count': 0,
|
||||||
|
'ua_pt2_count': 0,
|
||||||
|
'ua_pt3_count': 0,
|
||||||
|
'ua_dc_count': 0,
|
||||||
|
}
|
||||||
|
check_vals = [ check_val_d ]
|
||||||
|
|
||||||
|
for in_files in in_files_l:
|
||||||
|
fifo_file = self.filename_from_id('dumpcap_pcapng_sections_{}.fifo'.format(len(fifo_files) + 1))
|
||||||
|
fifo_files.append(fifo_file)
|
||||||
|
# If a previous test left its fifo laying around, e.g. from a failure, remove it.
|
||||||
|
try:
|
||||||
|
os.unlink(fifo_file)
|
||||||
|
except: pass
|
||||||
|
os.mkfifo(fifo_file)
|
||||||
|
cat_cmd = subprocesstest.cat_cap_file_command(in_files)
|
||||||
|
fifo_procs.append(self.startProcess(('{0} > {1}'.format(cat_cmd, fifo_file)), shell=True))
|
||||||
|
|
||||||
|
if multi_output:
|
||||||
|
rb_unique = 'sections_rb_' + uuid.uuid4().hex[:6] # Random ID
|
||||||
|
testout_glob = '{}.{}_*.pcapng'.format(self.id(), rb_unique)
|
||||||
|
testout_file = '{}.{}.pcapng'.format(self.id(), rb_unique)
|
||||||
|
check_vals.append(check_val_d)
|
||||||
|
# check_vals[]['filename'] will be filled in below
|
||||||
|
else:
|
||||||
|
testout_file = self.filename_from_id(testout_pcapng)
|
||||||
|
check_vals[0]['filename'] = testout_file
|
||||||
|
|
||||||
|
# Capture commands
|
||||||
|
if not multi_input and not multi_output:
|
||||||
|
# Passthrough SHBs, single output file
|
||||||
|
capture_cmd_args = (
|
||||||
|
'-i', fifo_files[0],
|
||||||
|
'-w', testout_file
|
||||||
|
)
|
||||||
|
check_vals[0]['packet_count'] = 79
|
||||||
|
check_vals[0]['idb_count'] = 22
|
||||||
|
check_vals[0]['ua_pt1_count'] = 1
|
||||||
|
check_vals[0]['ua_pt2_count'] = 1
|
||||||
|
elif not multi_input and multi_output:
|
||||||
|
# Passthrough SHBs, multiple output files
|
||||||
|
capture_cmd_args = (
|
||||||
|
'-i', fifo_files[0],
|
||||||
|
'-w', testout_file,
|
||||||
|
'-a', 'files:2',
|
||||||
|
'-b', 'packets:53'
|
||||||
|
)
|
||||||
|
check_vals[0]['packet_count'] = 53
|
||||||
|
check_vals[0]['idb_count'] = 22
|
||||||
|
check_vals[0]['ua_pt1_count'] = 1
|
||||||
|
check_vals[1]['packet_count'] = 26
|
||||||
|
check_vals[1]['idb_count'] = 22
|
||||||
|
check_vals[1]['ua_pt1_count'] = 1
|
||||||
|
check_vals[1]['ua_pt2_count'] = 1
|
||||||
|
elif multi_input and not multi_output:
|
||||||
|
# Dumpcap SHBs, single output file
|
||||||
|
capture_cmd_args = (
|
||||||
|
'-i', fifo_files[0],
|
||||||
|
'-i', fifo_files[1],
|
||||||
|
'-w', testout_file
|
||||||
|
)
|
||||||
|
check_vals[0]['packet_count'] = 88
|
||||||
|
check_vals[0]['idb_count'] = 35
|
||||||
|
check_vals[0]['ua_dc_count'] = 1
|
||||||
|
else:
|
||||||
|
# Dumpcap SHBs, multiple output files
|
||||||
|
capture_cmd_args = (
|
||||||
|
'-i', fifo_files[0],
|
||||||
|
'-i', fifo_files[1],
|
||||||
|
'-w', testout_file,
|
||||||
|
'-a', 'files:2',
|
||||||
|
'-b', 'packets:53'
|
||||||
|
)
|
||||||
|
check_vals[0]['packet_count'] = 53
|
||||||
|
check_vals[0]['idb_count'] = 35
|
||||||
|
check_vals[0]['ua_dc_count'] = 1
|
||||||
|
check_vals[1]['packet_count'] = 35
|
||||||
|
check_vals[1]['idb_count'] = 35
|
||||||
|
check_vals[1]['ua_dc_count'] = 1
|
||||||
|
|
||||||
|
capture_cmd = capture_command(cmd_dumpcap, *capture_cmd_args)
|
||||||
|
|
||||||
|
capture_proc = self.runProcess(capture_cmd)
|
||||||
|
for fifo_proc in fifo_procs: fifo_proc.kill()
|
||||||
|
|
||||||
|
rb_files = []
|
||||||
|
if multi_output:
|
||||||
|
rb_files = sorted(glob.glob(testout_glob))
|
||||||
|
self.assertEqual(len(rb_files), 2)
|
||||||
|
check_vals[0]['filename'] = rb_files[0]
|
||||||
|
check_vals[1]['filename'] = rb_files[1]
|
||||||
|
|
||||||
|
for rbf in rb_files:
|
||||||
|
self.cleanup_files.append(rbf)
|
||||||
|
self.assertTrue(os.path.isfile(rbf))
|
||||||
|
|
||||||
|
returncode = capture_proc.returncode
|
||||||
|
self.assertEqual(returncode, 0)
|
||||||
|
if (returncode != 0):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Output tests
|
||||||
|
|
||||||
|
if not multi_input and not multi_output:
|
||||||
|
# Check strict bit-for-bit passthrough.
|
||||||
|
in_hash = hashlib.sha256()
|
||||||
|
out_hash = hashlib.sha256()
|
||||||
|
for in_file in in_files_l[0]:
|
||||||
|
in_cap_file = capture_file(in_file)
|
||||||
|
with open(in_cap_file, 'rb') as f:
|
||||||
|
in_hash.update(f.read())
|
||||||
|
with open(testout_file, 'rb') as f:
|
||||||
|
out_hash.update(f.read())
|
||||||
|
self.assertEqual(in_hash.hexdigest(), out_hash.hexdigest())
|
||||||
|
|
||||||
|
# many_interfaces.pcapng.1 : 64 packets written by "Passthrough test #1"
|
||||||
|
# many_interfaces.pcapng.2 : 15 packets written by "Passthrough test #2"
|
||||||
|
# many_interfaces.pcapng.3 : 9 packets written by "Passthrough test #3"
|
||||||
|
for check_val in check_vals:
|
||||||
|
self.checkPacketCount(check_val['packet_count'], cap_file=check_val['filename'])
|
||||||
|
|
||||||
|
tshark_proc = self.runProcess(capture_command(cmd_tshark,
|
||||||
|
'-r', check_val['filename'],
|
||||||
|
'-V',
|
||||||
|
'-X', 'read_format:MIME Files Format'
|
||||||
|
))
|
||||||
|
# XXX Are there any other sanity checks we should run?
|
||||||
|
self.assertEqual(self.countOutput('Block: Interface Description Block',
|
||||||
|
proc=tshark_proc), check_val['idb_count'])
|
||||||
|
self.assertEqual(self.countOutput('Option: User Application = Passthrough test #1',
|
||||||
|
proc=tshark_proc), check_val['ua_pt1_count'])
|
||||||
|
self.assertEqual(self.countOutput('Option: User Application = Passthrough test #2',
|
||||||
|
proc=tshark_proc), check_val['ua_pt2_count'])
|
||||||
|
self.assertEqual(self.countOutput('Option: User Application = Passthrough test #3',
|
||||||
|
proc=tshark_proc), check_val['ua_pt3_count'])
|
||||||
|
self.assertEqual(self.countOutput('Option: User Application = Dumpcap \(Wireshark\)',
|
||||||
|
proc=tshark_proc), check_val['ua_dc_count'])
|
||||||
|
return check_dumpcap_pcapng_sections_real
|
||||||
|
|
||||||
|
|
||||||
@fixtures.mark_usefixtures('test_env')
|
@fixtures.mark_usefixtures('test_env')
|
||||||
@fixtures.uses_fixtures
|
@fixtures.uses_fixtures
|
||||||
class case_wireshark_capture(subprocesstest.SubprocessTestCase):
|
class case_wireshark_capture(subprocesstest.SubprocessTestCase):
|
||||||
|
@ -416,7 +578,6 @@ class case_dumpcap_autostop(subprocesstest.SubprocessTestCase):
|
||||||
@fixtures.uses_fixtures
|
@fixtures.uses_fixtures
|
||||||
class case_dumpcap_ringbuffer(subprocesstest.SubprocessTestCase):
|
class case_dumpcap_ringbuffer(subprocesstest.SubprocessTestCase):
|
||||||
# duration, interval, filesize, packets, files
|
# duration, interval, filesize, packets, files
|
||||||
# Need a function that finds ringbuffer file names.
|
|
||||||
def test_dumpcap_ringbuffer_filesize(self, check_dumpcap_ringbuffer_stdin):
|
def test_dumpcap_ringbuffer_filesize(self, check_dumpcap_ringbuffer_stdin):
|
||||||
'''Capture from stdin using Dumpcap and write multiple files until we reach a file size limit'''
|
'''Capture from stdin using Dumpcap and write multiple files until we reach a file size limit'''
|
||||||
check_dumpcap_ringbuffer_stdin(self, filesize=15)
|
check_dumpcap_ringbuffer_stdin(self, filesize=15)
|
||||||
|
@ -424,3 +585,23 @@ class case_dumpcap_ringbuffer(subprocesstest.SubprocessTestCase):
|
||||||
def test_dumpcap_ringbuffer_packets(self, check_dumpcap_ringbuffer_stdin):
|
def test_dumpcap_ringbuffer_packets(self, check_dumpcap_ringbuffer_stdin):
|
||||||
'''Capture from stdin using Dumpcap and write multiple files until we reach a packet limit'''
|
'''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.
|
check_dumpcap_ringbuffer_stdin(self, packets=47) # Last prime before 50. Arbitrary.
|
||||||
|
|
||||||
|
|
||||||
|
@fixtures.mark_usefixtures('base_env')
|
||||||
|
@fixtures.uses_fixtures
|
||||||
|
class case_dumpcap_pcapng_sections(subprocesstest.SubprocessTestCase):
|
||||||
|
def test_dumpcap_pcapng_single_in_single_out(self, check_dumpcap_pcapng_sections):
|
||||||
|
'''Capture from a single pcapng source using Dumpcap and write a single file'''
|
||||||
|
check_dumpcap_pcapng_sections(self)
|
||||||
|
|
||||||
|
def test_dumpcap_pcapng_single_in_multi_out(self, check_dumpcap_pcapng_sections):
|
||||||
|
'''Capture from a single pcapng source using Dumpcap and write two files'''
|
||||||
|
check_dumpcap_pcapng_sections(self, multi_output=True)
|
||||||
|
|
||||||
|
def test_dumpcap_pcapng_multi_in_single_out(self, check_dumpcap_pcapng_sections):
|
||||||
|
'''Capture from two pcapng sources using Dumpcap and write a single file'''
|
||||||
|
check_dumpcap_pcapng_sections(self, multi_input=True)
|
||||||
|
|
||||||
|
def test_dumpcap_pcapng_multi_in_multi_out(self, check_dumpcap_pcapng_sections):
|
||||||
|
'''Capture from two pcapng sources using Dumpcap and write two files'''
|
||||||
|
check_dumpcap_pcapng_sections(self, multi_input=True, multi_output=True)
|
||||||
|
|
Loading…
Reference in New Issue