aboutsummaryrefslogtreecommitdiffstats
path: root/dumpcap.c
diff options
context:
space:
mode:
authorJames Ko <jck@exegin.com>2017-11-22 11:05:48 -0800
committerAnders Broman <a.broman58@gmail.com>2017-12-01 08:18:16 +0000
commit8606062cb38373f7e594bbaa812fb19719d7e6ef (patch)
tree3a1ed60dab5f56fde65bdcea268ef321b248753e /dumpcap.c
parent1683dd11e76f01760665ab15cd9204fa19923238 (diff)
dumpcap: enable capture of pcapng from pipe
Reads pcapng blocks from a pipe. Section header blocks are parsed for endianess. All other blocks only have the general block header parsed for type and length, and then endianess converted if necessary. Outputs all blocks using the original endianess format so none of the other block types or options require parsing. Change-Id: I2f4f0175013d8fc2cda42a63e7deacad537951e3 Bug: 11370 Reviewed-on: https://code.wireshark.org/review/24536 Petri-Dish: Dario Lombardo <lomato@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'dumpcap.c')
-rw-r--r--dumpcap.c866
1 files changed, 750 insertions, 116 deletions
diff --git a/dumpcap.c b/dumpcap.c
index 34e4bb5b7c..458e576e5c 100644
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -108,6 +108,7 @@
*/
#include "wiretap/libpcap.h"
#include "wiretap/pcapng_module.h"
+#include "wiretap/pcapng.h"
/**#define DEBUG_DUMPCAP**/
/**#define DEBUG_CHILD_DUMPCAP**/
@@ -250,6 +251,19 @@ typedef enum {
PIPNEXIST
} cap_pipe_err_t;
+typedef struct _pcap_pipe_info {
+ struct pcap_hdr hdr; /**< Pcap header when capturing from a pipe */
+ struct pcaprec_modified_hdr rechdr; /**< Pcap record header when capturing from a pipe */
+} pcap_pipe_info_t;
+
+typedef struct _pcapng_pipe_info {
+ 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 */
+ GList *saved_blocks; /**< Pcapng block list of SHB and IDBs for multi_file_on */
+} pcapng_pipe_info_t;
+
+struct _loop_data; /* forward declaration so we can use it in the cap_pipe_dispatch function pointer */
+
/*
* A source of packets from which we're capturing.
*/
@@ -270,8 +284,11 @@ typedef struct _capture_src {
/**< capture pipe (unix only "input file") */
gboolean from_cap_pipe; /**< TRUE if we are capturing data from a capture pipe */
gboolean from_cap_socket; /**< TRUE if we're capturing from socket */
- struct pcap_hdr cap_pipe_hdr; /**< Pcap header when capturing from a pipe */
- struct pcaprec_modified_hdr cap_pipe_rechdr; /**< Pcap record header when capturing from a pipe */
+ gboolean from_pcapng; /**< TRUE if we're capturing from pcapng format */
+ union {
+ pcap_pipe_info_t pcap; /**< Pcap info when capturing from a pipe */
+ pcapng_pipe_info_t pcapng; /**< Pcapng info when capturing from a pipe */
+ } cap_pipe_info;
#ifdef _WIN32
HANDLE cap_pipe_h; /**< The handle of the capture pipe */
#endif
@@ -289,6 +306,7 @@ typedef struct _capture_src {
size_t cap_pipe_bytes_to_read; /**< Used by cap_pipe_dispatch */
size_t cap_pipe_bytes_read; /**< Used by cap_pipe_dispatch */
#endif
+ int (*cap_pipe_dispatch)(struct _loop_data *, struct _capture_src *, char *, int);
cap_pipe_state_t cap_pipe_state;
cap_pipe_err_t cap_pipe_err;
@@ -321,7 +339,10 @@ typedef struct _loop_data {
typedef struct _pcap_queue_element {
capture_src *pcap_src;
- struct pcap_pkthdr phdr;
+ union {
+ struct pcap_pkthdr phdr;
+ struct pcapng_block_header_s bh;
+ } u;
u_char *pd;
} pcap_queue_element;
@@ -388,6 +409,8 @@ static void capture_loop_write_packet_cb(u_char *pcap_src_p, const struct pcap_p
const u_char *pd);
static void capture_loop_queue_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr,
const u_char *pd);
+static void capture_loop_write_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_header_s *bh, const u_char *pd);
+static void capture_loop_queue_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_header_s *bh, const u_char *pd);
static void capture_loop_get_errmsg(char *errmsg, int errmsglen, const char *fname,
int err, gboolean is_close);
@@ -1452,6 +1475,51 @@ cap_pipe_close(int pipe_fd, gboolean from_socket _U_)
#endif
}
+static int
+cap_pipe_read_data_bytes(capture_src *pcap_src, char *errmsg, int errmsgl)
+{
+ int sel_ret;
+ int fd = pcap_src->cap_pipe_fd;
+#ifdef _WIN32
+ DWORD b, sz, bytes_read = 0;
+#else /* _WIN32 */
+ size_t b, sz, bytes_read = 0;
+#endif /* _WIN32 */
+ sz = pcap_src->cap_pipe_bytes_to_read - pcap_src->cap_pipe_bytes_read;
+ while (bytes_read < sz) {
+ if (fd == -1) {
+ g_snprintf(errmsg, errmsgl, "Invalid file descriptor.");
+ return -1;
+ }
+
+ sel_ret = cap_pipe_select(fd);
+ if (sel_ret < 0) {
+ g_snprintf(errmsg, errmsgl,
+ "Unexpected error from select: %s.", g_strerror(errno));
+ return -1;
+ } else if (sel_ret > 0) {
+ b = cap_pipe_read(fd, pcap_src->cap_pipe_databuf+pcap_src->cap_pipe_bytes_read+bytes_read,
+ sz-bytes_read, pcap_src->from_cap_socket);
+ if (b <= 0) {
+ if (b == 0)
+ g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open.");
+ else
+ g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s.",
+ g_strerror(errno));
+ return -1;
+ }
+ bytes_read += b;
+ }
+ }
+ pcap_src->cap_pipe_bytes_read += bytes_read;
+ return 0;
+}
+
+/* Some forward declarations for breaking up cap_pipe_open_live for pcap and pcapng formats */
+static void pcap_pipe_open_live(int fd, capture_src *pcap_src, struct pcap_hdr *hdr, char *errmsg, int errmsgl);
+static void pcapng_pipe_open_live(int fd, capture_src *pcap_src, char *errmsg, int errmsgl);
+static int pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsgl);
+
/* Mimic pcap_open_live() for pipe captures
* We check if "pipename" is "-" (stdin), a AF_UNIX socket, or a FIFO,
@@ -1462,7 +1530,7 @@ cap_pipe_close(int pipe_fd, gboolean from_socket _U_)
static void
cap_pipe_open_live(char *pipename,
capture_src *pcap_src,
- struct pcap_hdr *hdr,
+ void *hdr,
char *errmsg, int errmsgl)
{
#ifndef _WIN32
@@ -1770,16 +1838,40 @@ cap_pipe_open_live(char *pipename,
pcap_src->cap_pipe_modified = TRUE;
break;
case BLOCK_TYPE_SHB:
- /* This isn't pcap, it's pcapng. We don't yet support
- reading it. */
- g_snprintf(errmsg, errmsgl, "Capturing from a pipe doesn't support pcapng format.");
- goto error;
+ /* This isn't pcap, it's pcapng. */
+ pcap_src->from_pcapng = TRUE;
+ pcap_src->cap_pipe_dispatch = pcapng_pipe_dispatch;
+ global_capture_opts.use_pcapng = TRUE; /* we can only output in pcapng format */
+ pcapng_pipe_open_live(fd, pcap_src, errmsg, errmsgl);
+ return;
default:
/* Not a pcap type we know about, or not pcap at all. */
g_snprintf(errmsg, errmsgl, "Unrecognized libpcap format or not libpcap data.");
goto error;
}
+ pcap_pipe_open_live(fd, pcap_src, (struct pcap_hdr *) hdr, errmsg, errmsgl);
+ return;
+
+error:
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: error %s", errmsg);
+ pcap_src->cap_pipe_err = PIPERR;
+ cap_pipe_close(fd, pcap_src->from_cap_socket);
+ pcap_src->cap_pipe_fd = -1;
+#ifdef _WIN32
+ pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE;
+#endif
+}
+
+static void
+pcap_pipe_open_live(int fd,
+ capture_src *pcap_src,
+ struct pcap_hdr *hdr,
+ char *errmsg, int errmsgl)
+{
+ size_t bytes_read;
+ ssize_t b;
+ int sel_ret;
#ifdef _WIN32
if (pcap_src->from_cap_socket)
#endif
@@ -1846,7 +1938,8 @@ cap_pipe_open_live(char *pipename,
pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_STANDARD;
if (hdr->version_major < 2) {
- g_snprintf(errmsg, errmsgl, "Unable to read old libpcap format");
+ g_snprintf(errmsg, errmsgl, "Unable to read old libpcap format version %d.%d",
+ hdr->version_major, hdr->version_minor);
goto error;
}
@@ -1856,7 +1949,7 @@ cap_pipe_open_live(char *pipename,
return;
error:
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: error %s", errmsg);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcap_pipe_open_live: error %s", errmsg);
pcap_src->cap_pipe_err = PIPERR;
cap_pipe_close(fd, pcap_src->from_cap_socket);
pcap_src->cap_pipe_fd = -1;
@@ -1865,11 +1958,188 @@ error:
#endif
}
+/* Read the pcapng section header block */
+static int
+pcapng_read_shb(capture_src *pcap_src,
+ char *errmsg,
+ int errmsgl)
+{
+ struct pcapng_block_header_s *bh = &pcap_src->cap_pipe_info.pcapng.bh;
+ struct pcapng_section_header_block_s *shb = &pcap_src->cap_pipe_info.pcapng.shb;
+
+#ifdef _WIN32
+ if (pcap_src->from_cap_socket)
+#endif
+ {
+ pcap_src->cap_pipe_bytes_to_read = sizeof(struct pcapng_block_header_s) + sizeof(struct pcapng_section_header_block_s);
+ if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl)) {
+ return -1;
+ }
+ }
+#ifdef _WIN32
+ else {
+ pcap_src->cap_pipe_buf = pcap_src->cap_pipe_databuf + sizeof(struct pcapng_block_header_s);
+ pcap_src->cap_pipe_bytes_read = 0;
+ pcap_src->cap_pipe_bytes_to_read = sizeof(struct pcapng_section_header_block_s);
+ g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf);
+ g_async_queue_pop(pcap_src->cap_pipe_done_q);
+ if (pcap_src->cap_pipe_bytes_read <= 0) {
+ if (pcap_src->cap_pipe_bytes_read == 0)
+ g_snprintf(errmsg, errmsgl, "End of file on pipe section header during open.");
+ else
+ g_snprintf(errmsg, errmsgl, "Error on pipe section header during open: %s.",
+ g_strerror(errno));
+ return -1;
+ }
+ pcap_src->cap_pipe_bytes_read = sizeof(struct pcapng_block_header_s) + sizeof(struct pcapng_section_header_block_s);
+ }
+#endif
+ memcpy(shb, pcap_src->cap_pipe_databuf + sizeof(struct pcapng_block_header_s), sizeof(struct pcapng_section_header_block_s));
+ switch (shb->magic)
+ {
+ case PCAPNG_MAGIC:
+ pcap_src->cap_pipe_byte_swapped = FALSE;
+ break;
+ case PCAPNG_SWAPPED_MAGIC:
+ pcap_src->cap_pipe_byte_swapped = TRUE;
+ break;
+ default:
+ /* Not a pcapng type we know about, or not pcapng at all. */
+ g_snprintf(errmsg, errmsgl, "Unrecognized pcapng format or not pcapng data.");
+ return -1;
+ }
+
+ if (pcap_src->cap_pipe_byte_swapped) {
+ /* Byte-swap the header fields about which we care. */
+ shb->version_major = GUINT16_SWAP_LE_BE(shb->version_major);
+ shb->version_minor = GUINT16_SWAP_LE_BE(shb->version_minor);
+ shb->section_length = GUINT64_SWAP_LE_BE(shb->section_length);
+ bh->block_total_length = GUINT32_SWAP_LE_BE(bh->block_total_length);
+ }
+
+ pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_STANDARD;
+
+ /* Setup state to capture the rest of the section header block */
+ pcap_src->cap_pipe_state = STATE_EXPECT_DATA;
+
+ return 0;
+}
+
+static int
+pcapng_write_saved_block(capture_src *pcap_src, struct pcapng_block_header_s *bh)
+{
+ guint32 length = bh->block_total_length;
+
+ if (pcap_src->cap_pipe_byte_swapped) {
+ length = GUINT32_SWAP_LE_BE(length);
+ }
+
+ return pcapng_write_block(global_ld.pdh,
+ (const guint8 *) bh,
+ length,
+ &global_ld.bytes_written, &global_ld.err);
+}
+
+/* Save SHB and IDB blocks to playback whenever we change output files. */
+/* The list is saved in reverse order of blocks added */
+static gboolean
+pcapng_block_save(capture_src *pcap_src)
+{
+ pcapng_pipe_info_t *pcapng = &pcap_src->cap_pipe_info.pcapng;
+ struct pcapng_block_header_s *bh = &pcapng->bh;
+
+ /* Delete all the old blocks first whenever we get a SHB */
+ if (bh->block_type == BLOCK_TYPE_SHB) {
+ g_list_free_full(pcapng->saved_blocks, g_free);
+ pcapng->saved_blocks = NULL;
+ } else if (bh->block_type != BLOCK_TYPE_IDB) {
+ return TRUE;
+ }
+
+ gpointer data = g_malloc(bh->block_total_length);
+ if (data == NULL) {
+ return FALSE;
+ }
+ memcpy(data, pcap_src->cap_pipe_databuf, bh->block_total_length);
+
+ pcapng->saved_blocks = g_list_prepend(pcapng->saved_blocks, data);
+
+ return TRUE;
+}
+
+static void
+pcapng_pipe_open_live(int fd,
+ capture_src *pcap_src,
+ char *errmsg,
+ int errmsgl)
+{
+ guint32 type = BLOCK_TYPE_SHB;
+ struct pcapng_block_header_s *bh = &pcap_src->cap_pipe_info.pcapng.bh;
+
+#ifdef _WIN32
+ if (pcap_src->from_cap_socket)
+#endif
+ {
+ memcpy(pcap_src->cap_pipe_databuf, &type, sizeof(guint32));
+ /* read the rest of the pcapng general block header */
+ pcap_src->cap_pipe_bytes_read = sizeof(guint32);
+ pcap_src->cap_pipe_bytes_to_read = sizeof(struct pcapng_block_header_s);
+ pcap_src->cap_pipe_err = PIPOK;
+ pcap_src->cap_pipe_fd = fd;
+ if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl)) {
+ goto error;
+ }
+ memcpy(bh, pcap_src->cap_pipe_databuf, sizeof(struct pcapng_block_header_s));
+ }
+#ifdef _WIN32
+ else {
+#if GLIB_CHECK_VERSION(2,31,0)
+ g_thread_new("cap_pipe_open_live", &cap_thread_read, pcap_src);
+#else
+ g_thread_create(&cap_thread_read, pcap_src, FALSE, NULL);
+#endif
+
+ bh->block_type = type;
+ pcap_src->cap_pipe_buf = (char *) &bh->block_total_length;
+ pcap_src->cap_pipe_bytes_read = 0;
+ pcap_src->cap_pipe_bytes_to_read = sizeof(bh->block_total_length);
+ /* We don't have to worry about cap_pipe_read_mtx here */
+ g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf);
+ g_async_queue_pop(pcap_src->cap_pipe_done_q);
+ if (pcap_src->cap_pipe_bytes_read <= 0) {
+ if (pcap_src->cap_pipe_bytes_read == 0)
+ g_snprintf(errmsg, errmsgl, "End of file on pipe block_total_length during open.");
+ else
+ g_snprintf(errmsg, errmsgl, "Error on pipe block_total_length during open: %s.",
+ g_strerror(errno));
+ goto error;
+ }
+ pcap_src->cap_pipe_bytes_read = sizeof(struct pcapng_block_header_s);
+ memcpy(pcap_src->cap_pipe_databuf, bh, sizeof(struct pcapng_block_header_s));
+ pcap_src->cap_pipe_err = PIPOK;
+ pcap_src->cap_pipe_fd = fd;
+ }
+#endif
+ if (pcapng_read_shb(pcap_src, errmsg, errmsgl)) {
+ goto error;
+ }
+
+ return;
+
+error:
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng_pipe_open_live: error %s", errmsg);
+ pcap_src->cap_pipe_err = PIPERR;
+ cap_pipe_close(fd, pcap_src->from_cap_socket);
+ pcap_src->cap_pipe_fd = -1;
+#ifdef _WIN32
+ pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE;
+#endif
+}
/* We read one record from the pipe, take care of byte order in the record
* header, write the record to the capture file, and update capture statistics. */
static int
-cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsgl)
+pcap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsgl)
{
struct pcap_pkthdr phdr;
enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
@@ -1883,9 +2153,10 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
#endif
ssize_t b;
guint new_bufsize;
+ pcap_pipe_info_t *pcap_info = &pcap_src->cap_pipe_info.pcap;
#ifdef LOG_CAPTURE_VERBOSE
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_dispatch");
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcap_pipe_dispatch");
#endif
switch (pcap_src->cap_pipe_state) {
@@ -1901,7 +2172,7 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
pcap_src->cap_pipe_bytes_read = 0;
#ifdef _WIN32
- pcap_src->cap_pipe_buf = (char *) &pcap_src->cap_pipe_rechdr;
+ pcap_src->cap_pipe_buf = (char *) &pcap_info->rechdr;
g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf);
g_mutex_unlock(pcap_src->cap_pipe_read_mtx);
}
@@ -1913,7 +2184,7 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
if (pcap_src->from_cap_socket)
#endif
{
- b = cap_pipe_read(pcap_src->cap_pipe_fd, ((char *)&pcap_src->cap_pipe_rechdr)+pcap_src->cap_pipe_bytes_read,
+ b = cap_pipe_read(pcap_src->cap_pipe_fd, ((char *)&pcap_info->rechdr)+pcap_src->cap_pipe_bytes_read,
pcap_src->cap_pipe_bytes_to_read - pcap_src->cap_pipe_bytes_read, pcap_src->from_cap_socket);
if (b <= 0) {
if (b == 0)
@@ -1956,7 +2227,7 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
#endif
pcap_src->cap_pipe_state = STATE_READ_DATA;
- pcap_src->cap_pipe_bytes_to_read = pcap_src->cap_pipe_rechdr.hdr.incl_len;
+ pcap_src->cap_pipe_bytes_to_read = pcap_info->rechdr.hdr.incl_len;
pcap_src->cap_pipe_bytes_read = 0;
#ifdef _WIN32
@@ -2013,7 +2284,7 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
break;
default:
- g_snprintf(errmsg, errmsgl, "cap_pipe_dispatch: invalid state");
+ g_snprintf(errmsg, errmsgl, "pcap_pipe_dispatch: invalid state");
result = PD_ERR;
} /* switch (pcap_src->cap_pipe_state) */
@@ -2025,9 +2296,9 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
case PD_REC_HDR_READ:
/* We've read the header. Take care of byte order. */
- cap_pipe_adjust_header(pcap_src->cap_pipe_byte_swapped, &pcap_src->cap_pipe_hdr,
- &pcap_src->cap_pipe_rechdr.hdr);
- if (pcap_src->cap_pipe_rechdr.hdr.incl_len > pcap_src->cap_pipe_max_pkt_size) {
+ cap_pipe_adjust_header(pcap_src->cap_pipe_byte_swapped, &pcap_info->hdr,
+ &pcap_info->rechdr.hdr);
+ if (pcap_info->rechdr.hdr.incl_len > pcap_src->cap_pipe_max_pkt_size) {
/*
* The record contains more data than the advertised/allowed in the
* pcap header, do not try to read more data (do not change to
@@ -2035,16 +2306,16 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
* instead stop with an error.
*/
g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
- ld->packet_count+1, pcap_src->cap_pipe_rechdr.hdr.incl_len);
+ ld->packet_count+1, pcap_info->rechdr.hdr.incl_len);
break;
}
- if (pcap_src->cap_pipe_rechdr.hdr.incl_len > pcap_src->cap_pipe_databuf_size) {
+ if (pcap_info->rechdr.hdr.incl_len > pcap_src->cap_pipe_databuf_size) {
/*
* Grow the buffer to the packet size, rounded up to a power of
* 2.
*/
- new_bufsize = pcap_src->cap_pipe_rechdr.hdr.incl_len;
+ new_bufsize = pcap_info->rechdr.hdr.incl_len;
/*
* http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
*/
@@ -2063,7 +2334,7 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
* The record has some data following the header, try to read it next
* time.
*/
- if (pcap_src->cap_pipe_rechdr.hdr.incl_len) {
+ if (pcap_info->rechdr.hdr.incl_len) {
pcap_src->cap_pipe_state = STATE_EXPECT_DATA;
return 0;
}
@@ -2075,10 +2346,10 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
/* FALLTHROUGH */
case PD_DATA_READ:
/* Fill in a "struct pcap_pkthdr", and process the packet. */
- phdr.ts.tv_sec = pcap_src->cap_pipe_rechdr.hdr.ts_sec;
- phdr.ts.tv_usec = pcap_src->cap_pipe_rechdr.hdr.ts_usec;
- phdr.caplen = pcap_src->cap_pipe_rechdr.hdr.incl_len;
- phdr.len = pcap_src->cap_pipe_rechdr.hdr.orig_len;
+ phdr.ts.tv_sec = pcap_info->rechdr.hdr.ts_sec;
+ phdr.ts.tv_usec = pcap_info->rechdr.hdr.ts_usec;
+ phdr.caplen = pcap_info->rechdr.hdr.incl_len;
+ phdr.len = pcap_info->rechdr.hdr.orig_len;
if (use_threads) {
capture_loop_queue_packet_cb((u_char *)pcap_src, &phdr, pcap_src->cap_pipe_databuf);
@@ -2114,6 +2385,239 @@ cap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsg
return -1;
}
+static int
+pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsgl)
+{
+ enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
+ PD_ERR } result;
+#ifdef _WIN32
+#if !GLIB_CHECK_VERSION(2,31,18)
+ GTimeVal wait_time;
+#endif
+ gpointer q_status;
+ wchar_t *err_str;
+#endif
+ guint new_bufsize;
+ struct pcapng_block_header_s *bh = &pcap_src->cap_pipe_info.pcapng.bh;
+
+#ifdef LOG_CAPTURE_VERBOSE
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng_pipe_dispatch");
+#endif
+
+ switch (pcap_src->cap_pipe_state) {
+
+ case STATE_EXPECT_REC_HDR:
+#ifdef _WIN32
+ if (g_mutex_trylock(pcap_src->cap_pipe_read_mtx)) {
+#endif
+
+ pcap_src->cap_pipe_state = STATE_READ_REC_HDR;
+ pcap_src->cap_pipe_bytes_to_read = sizeof(struct pcapng_block_header_s);
+ pcap_src->cap_pipe_bytes_read = 0;
+
+#ifdef _WIN32
+ pcap_src->cap_pipe_buf = pcap_src->cap_pipe_databuf;
+ g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf);
+ g_mutex_unlock(pcap_src->cap_pipe_read_mtx);
+ }
+#endif
+ /* Fall through */
+
+ case STATE_READ_REC_HDR:
+#ifdef _WIN32
+ if (pcap_src->from_cap_socket)
+#endif
+ {
+ if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl)) {
+ return -1;
+ }
+ }
+#ifdef _WIN32
+ else {
+#if GLIB_CHECK_VERSION(2,31,18)
+ q_status = g_async_queue_timeout_pop(pcap_src->cap_pipe_done_q, PIPE_READ_TIMEOUT);
+#else
+ g_get_current_time(&wait_time);
+ g_time_val_add(&wait_time, PIPE_READ_TIMEOUT);
+ q_status = g_async_queue_timed_pop(pcap_src->cap_pipe_done_q, &wait_time);
+#endif
+ if (pcap_src->cap_pipe_err == PIPEOF) {
+ result = PD_PIPE_EOF;
+ break;
+ } else if (pcap_src->cap_pipe_err == PIPERR) {
+ result = PD_PIPE_ERR;
+ break;
+ }
+ if (!q_status) {
+ return 0;
+ }
+ }
+#endif
+ if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read)
+ return 0;
+ memcpy(bh, pcap_src->cap_pipe_databuf, sizeof(struct pcapng_block_header_s));
+ result = PD_REC_HDR_READ;
+ break;
+
+ case STATE_EXPECT_DATA:
+#ifdef _WIN32
+ if (g_mutex_trylock(pcap_src->cap_pipe_read_mtx)) {
+#endif
+ pcap_src->cap_pipe_state = STATE_READ_DATA;
+ pcap_src->cap_pipe_bytes_to_read = bh->block_total_length;
+
+
+#ifdef _WIN32
+ pcap_src->cap_pipe_bytes_to_read -= pcap_src->cap_pipe_bytes_read;
+ pcap_src->cap_pipe_buf = pcap_src->cap_pipe_databuf + pcap_src->cap_pipe_bytes_read;
+ g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf);
+ g_mutex_unlock(pcap_src->cap_pipe_read_mtx);
+ }
+#endif
+ /* Fall through */
+
+ case STATE_READ_DATA:
+#ifdef _WIN32
+ if (pcap_src->from_cap_socket)
+#endif
+ {
+ if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl)) {
+ return -1;
+ }
+ if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read)
+ return 0;
+ }
+#ifdef _WIN32
+ else {
+
+#if GLIB_CHECK_VERSION(2,31,18)
+ q_status = g_async_queue_timeout_pop(pcap_src->cap_pipe_done_q, PIPE_READ_TIMEOUT);
+#else
+ g_get_current_time(&wait_time);
+ g_time_val_add(&wait_time, PIPE_READ_TIMEOUT);
+ q_status = g_async_queue_timed_pop(pcap_src->cap_pipe_done_q, &wait_time);
+#endif /* GLIB_CHECK_VERSION(2,31,18) */
+ if (pcap_src->cap_pipe_err == PIPEOF) {
+ result = PD_PIPE_EOF;
+ break;
+ } else if (pcap_src->cap_pipe_err == PIPERR) {
+ result = PD_PIPE_ERR;
+ break;
+ }
+ if (!q_status) {
+ return 0;
+ }
+ if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read) {
+ return 0;
+ }
+ pcap_src->cap_pipe_bytes_read = bh->block_total_length;
+ }
+#endif /* _WIN32 */
+ result = PD_DATA_READ;
+ break;
+
+ default:
+ g_snprintf(errmsg, errmsgl, "pcapng_pipe_dispatch: invalid state");
+ result = PD_ERR;
+
+ } /* switch (pcap_src->cap_pipe_state) */
+
+ /*
+ * We've now read as much data as we were expecting, so process it.
+ */
+ switch (result) {
+
+ case PD_REC_HDR_READ:
+ if (bh->block_type == BLOCK_TYPE_SHB) {
+ /* we need to read ahead to get the endianess before getting the block type and length */
+ pcapng_read_shb(pcap_src, errmsg, errmsgl);
+ return 1;
+ }
+
+ /* We've read the header. Take care of byte order. */
+ if (pcap_src->cap_pipe_byte_swapped) {
+ /* Byte-swap the record header fields. */
+ bh->block_type = GUINT32_SWAP_LE_BE(bh->block_type);
+ bh->block_total_length = GUINT32_SWAP_LE_BE(bh->block_total_length);
+ }
+ if (bh->block_total_length > pcap_src->cap_pipe_max_pkt_size) {
+ /*
+ * The record contains more data than the advertised/allowed in the
+ * pcapng header, do not try to read more data (do not change to
+ * STATE_EXPECT_DATA) as that would not fit in the buffer and
+ * instead stop with an error.
+ */
+ g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
+ ld->packet_count+1, bh->block_total_length);
+ break;
+ }
+
+ if (bh->block_total_length > pcap_src->cap_pipe_databuf_size) {
+ /*
+ * Grow the buffer to the packet size, rounded up to a power of
+ * 2.
+ */
+ new_bufsize = bh->block_total_length;
+ /*
+ * http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ */
+ new_bufsize--;
+ new_bufsize |= new_bufsize >> 1;
+ new_bufsize |= new_bufsize >> 2;
+ new_bufsize |= new_bufsize >> 4;
+ new_bufsize |= new_bufsize >> 8;
+ new_bufsize |= new_bufsize >> 16;
+ new_bufsize++;
+ pcap_src->cap_pipe_databuf = (guchar*)g_realloc(pcap_src->cap_pipe_databuf, new_bufsize);
+ pcap_src->cap_pipe_databuf_size = new_bufsize;
+ }
+
+ /* The record always has at least the block total length following the header */
+ if (bh->block_total_length < sizeof(struct pcapng_block_header_s)+sizeof(guint32)) {
+ g_snprintf(errmsg, errmsgl, "malformed pcapng block_total_length < minimum");
+ pcap_src->cap_pipe_err = PIPEOF;
+ return -1;
+ }
+ pcap_src->cap_pipe_state = STATE_EXPECT_DATA;
+ return 0;
+
+ case PD_DATA_READ:
+ if (!pcapng_block_save(pcap_src)) {
+ return -1;
+ }
+ if (use_threads) {
+ capture_loop_queue_pcapng_cb(pcap_src, bh, pcap_src->cap_pipe_databuf);
+ } else {
+ capture_loop_write_pcapng_cb(pcap_src, bh, pcap_src->cap_pipe_databuf);
+ }
+ pcap_src->cap_pipe_state = STATE_EXPECT_REC_HDR;
+ return 1;
+
+ case PD_PIPE_EOF:
+ pcap_src->cap_pipe_err = PIPEOF;
+ return -1;
+
+ case PD_PIPE_ERR:
+#ifdef _WIN32
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
+ g_snprintf(errmsg, errmsgl,
+ "Error reading from pipe: %s (error %d)",
+ utf_16to8(err_str), GetLastError());
+ LocalFree(err_str);
+#else
+ g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
+ g_strerror(errno));
+#endif
+ /* Fall through */
+ case PD_ERR:
+ break;
+ }
+
+ pcap_src->cap_pipe_err = PIPERR;
+ /* Return here rather than inside the switch to prevent GCC warning */
+ return -1;
+}
/** Open the capture input file (pcap or capture pipe).
* Returns TRUE if it succeeds, FALSE otherwise. */
@@ -2195,34 +2699,17 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
"Could not allocate memory.");
return FALSE;
}
- pcap_src->received = 0;
- pcap_src->dropped = 0;
- pcap_src->flushed = 0;
- pcap_src->pcap_h = NULL;
+ memset(pcap_src, 0, sizeof(capture_src));
#ifdef MUST_DO_SELECT
pcap_src->pcap_fd = -1;
#endif
- pcap_src->pcap_err = FALSE;
pcap_src->interface_id = i;
- pcap_src->tid = NULL;
- pcap_src->snaplen = 0;
pcap_src->linktype = -1;
- pcap_src->ts_nsec = FALSE;
- pcap_src->from_cap_pipe = FALSE;
- pcap_src->from_cap_socket = FALSE;
- memset(&pcap_src->cap_pipe_hdr, 0, sizeof(struct pcap_hdr));
- memset(&pcap_src->cap_pipe_rechdr, 0, sizeof(struct pcaprec_modified_hdr));
#ifdef _WIN32
pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE;
#endif
pcap_src->cap_pipe_fd = -1;
- pcap_src->cap_pipe_modified = FALSE;
- pcap_src->cap_pipe_byte_swapped = FALSE;
-#ifdef _WIN32
- pcap_src->cap_pipe_buf = NULL;
-#endif
- pcap_src->cap_pipe_bytes_to_read = 0;
- pcap_src->cap_pipe_bytes_read = 0;
+ pcap_src->cap_pipe_dispatch = pcap_pipe_dispatch;
pcap_src->cap_pipe_state = STATE_EXPECT_REC_HDR;
pcap_src->cap_pipe_err = PIPOK;
#ifdef _WIN32
@@ -2291,7 +2778,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
} else {
/* We couldn't open "iface" as a network device. */
/* Try to open it as a pipe */
- cap_pipe_open_live(interface_opts->name, pcap_src, &pcap_src->cap_pipe_hdr, errmsg, (int) errmsg_len);
+ cap_pipe_open_live(interface_opts->name, pcap_src, &pcap_src->cap_pipe_info.pcap.hdr, errmsg, (int) errmsg_len);
#ifndef _WIN32
if (pcap_src->cap_pipe_fd == -1) {
@@ -2385,6 +2872,10 @@ static void capture_loop_close_input(loop_data *ld)
g_free(pcap_src->cap_pipe_databuf);
pcap_src->cap_pipe_databuf = NULL;
}
+ if (pcap_src->from_pcapng) {
+ g_list_free_full(pcap_src->cap_pipe_info.pcapng.saved_blocks, g_free);
+ pcap_src->cap_pipe_info.pcapng.saved_blocks = NULL;
+ }
} else {
/* Capture device. If open, close the pcap_t. */
if (pcap_src->pcap_h != NULL) {
@@ -2466,6 +2957,11 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err
}
}
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) {
char *appname;
GString *cpu_info_str;
@@ -2492,22 +2988,22 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err
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_hdr.snaplen;
+ 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);
+ 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);
@@ -2515,12 +3011,12 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err
} else {
pcap_src = g_array_index(ld->pcaps, capture_src *, 0);
if (pcap_src->from_cap_pipe) {
- pcap_src->snaplen = pcap_src->cap_pipe_hdr.snaplen;
+ pcap_src->snaplen = pcap_src->cap_pipe_info.pcap.hdr.snaplen;
} else {
pcap_src->snaplen = pcap_snapshot(pcap_src->pcap_h);
}
successful = libpcap_write_file_header(ld->pdh, pcap_src->linktype, pcap_src->snaplen,
- pcap_src->ts_nsec, &ld->bytes_written, &err);
+ pcap_src->ts_nsec, &ld->bytes_written, &err);
}
if (!successful) {
fclose(ld->pdh);
@@ -2645,7 +3141,7 @@ capture_loop_dispatch(loop_data *ld,
* "select()" says we can read from the pipe without blocking
*/
#endif
- inpkts = cap_pipe_dispatch(ld, pcap_src, errmsg, errmsg_len);
+ inpkts = pcap_src->cap_pipe_dispatch(ld, pcap_src, errmsg, errmsg_len);
if (inpkts < 0) {
ld->go = FALSE;
}
@@ -2974,51 +3470,65 @@ do_file_switch_or_stop(capture_options *capture_opts,
/* File switch succeeded: reset the conditions */
global_ld.bytes_written = 0;
- if (capture_opts->use_pcapng) {
- char *appname;
- 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(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);
+ pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0);
+ if (pcap_src->from_pcapng) {
+ /* Write the saved SHB and all IDBs to start of next file */
+ /* 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) {
+ successful = pcapng_write_saved_block(pcap_src, (struct pcapng_block_header_s *) list->data);
+ list = g_list_next(list);
}
+ pcap_src->cap_pipe_info.pcapng.saved_blocks = g_list_reverse(rlist);
+ } else {
+ if (capture_opts->use_pcapng) {
+ char *appname;
+ 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(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);
+ 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);
+ } 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) {
fclose(global_ld.pdh);
@@ -3255,18 +3765,33 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
queue_element = (pcap_queue_element *)g_async_queue_timed_pop_unlocked(pcap_queue, &write_thread_time);
#endif
if (queue_element) {
- pcap_queue_bytes -= queue_element->phdr.caplen;
- pcap_queue_packets -= 1;
+ if (queue_element->pcap_src->from_pcapng) {
+ pcap_queue_bytes -= queue_element->u.bh.block_total_length;
+ pcap_queue_packets -= 1;
+ } else {
+ pcap_queue_bytes -= queue_element->u.phdr.caplen;
+ pcap_queue_packets -= 1;
+ }
}
g_async_queue_unlock(pcap_queue);
if (queue_element) {
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
- "Dequeued a packet of length %d captured on interface %d.",
- queue_element->phdr.caplen, queue_element->pcap_src->interface_id);
+ if (queue_element->pcap_src->from_pcapng) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+ "Dequeued a block of length %d captured on interface %d.",
+ queue_element->u.bh.block_total_length, queue_element->pcap_src->interface_id);
- capture_loop_write_packet_cb((u_char *) queue_element->pcap_src,
- &queue_element->phdr,
- queue_element->pd);
+ capture_loop_write_pcapng_cb(queue_element->pcap_src,
+ &queue_element->u.bh,
+ queue_element->pd);
+ } else {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+ "Dequeued a packet of length %d captured on interface %d.",
+ queue_element->u.phdr.caplen, queue_element->pcap_src->interface_id);
+
+ capture_loop_write_packet_cb((u_char *) queue_element->pcap_src,
+ &queue_element->u.phdr,
+ queue_element->pd);
+ }
g_free(queue_element->pd);
g_free(queue_element);
inpkts = 1;
@@ -3395,7 +3920,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
g_async_queue_lock(pcap_queue);
queue_element = (pcap_queue_element *)g_async_queue_try_pop_unlocked(pcap_queue);
if (queue_element) {
- pcap_queue_bytes -= queue_element->phdr.caplen;
+ pcap_queue_bytes -= queue_element->u.phdr.caplen;
pcap_queue_packets -= 1;
}
g_async_queue_unlock(pcap_queue);
@@ -3404,9 +3929,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
}
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
"Dequeued a packet of length %d captured on interface %d.",
- queue_element->phdr.caplen, queue_element->pcap_src->interface_id);
+ queue_element->u.phdr.caplen, queue_element->pcap_src->interface_id);
capture_loop_write_packet_cb((u_char *)queue_element->pcap_src,
- &queue_element->phdr,
+ &queue_element->u.phdr,
queue_element->pd);
g_free(queue_element->pd);
g_free(queue_element);
@@ -3645,6 +4170,55 @@ capture_loop_get_errmsg(char *errmsg, int errmsglen, const char *fname,
}
}
+/* one pcapng block was captured, process it */
+static void
+capture_loop_write_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_header_s *bh, const u_char *pd)
+{
+ int err;
+
+ if (!global_capture_opts.use_pcapng) {
+ return;
+ }
+ /* We may be called multiple times from pcap_dispatch(); if we've set
+ the "stop capturing" flag, ignore this packet, as we're not
+ supposed to be saving any more packets. */
+ if (!global_ld.go) {
+ pcap_src->flushed++;
+ return;
+ }
+
+ if (global_ld.pdh) {
+ gboolean successful;
+
+ /* We're supposed to write the packet to a file; do so.
+ If this fails, set "ld->go" to FALSE, to stop the capture, and set
+ "ld->err" to the error. */
+ successful = pcapng_write_block(global_ld.pdh,
+ pd,
+ bh->block_total_length,
+ &global_ld.bytes_written, &err);
+
+ fflush(global_ld.pdh);
+ if (!successful) {
+ global_ld.go = FALSE;
+ global_ld.err = err;
+ pcap_src->dropped++;
+ } else if (bh->block_type == BLOCK_TYPE_EPB || bh->block_type == BLOCK_TYPE_SPB) {
+ /* count packet only if we actually have an EPB or SPB */
+#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP)
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+ "Wrote a packet of length %d captured on interface %u.",
+ phdr->caplen, pcap_src->interface_id);
+#endif
+ global_ld.packet_count++;
+ 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)) {
+ global_ld.go = FALSE;
+ }
+ }
+ }
+}
/* one packet was captured, process it */
static void
@@ -3728,7 +4302,7 @@ capture_loop_queue_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr,
return;
}
queue_element->pcap_src = pcap_src;
- queue_element->phdr = *phdr;
+ queue_element->u.phdr = *phdr;
queue_element->pd = (u_char *)g_malloc(phdr->caplen);
if (queue_element->pd == NULL) {
pcap_src->dropped++;
@@ -3767,6 +4341,66 @@ capture_loop_queue_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr,
pcap_queue_bytes, pcap_queue_packets);
}
+/* one pcapng block was captured, queue it */
+static void
+capture_loop_queue_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_header_s *bh, const u_char *pd)
+{
+ pcap_queue_element *queue_element;
+ gboolean limit_reached;
+
+ /* We may be called multiple times from pcap_dispatch(); if we've set
+ the "stop capturing" flag, ignore this packet, as we're not
+ supposed to be saving any more packets. */
+ if (!global_ld.go) {
+ pcap_src->flushed++;
+ return;
+ }
+
+ queue_element = (pcap_queue_element *)g_malloc(sizeof(pcap_queue_element));
+ if (queue_element == NULL) {
+ pcap_src->dropped++;
+ return;
+ }
+ queue_element->pcap_src = pcap_src;
+ queue_element->u.bh = *bh;
+ queue_element->pd = (u_char *)g_malloc(bh->block_total_length);
+ if (queue_element->pd == NULL) {
+ pcap_src->dropped++;
+ g_free(queue_element);
+ return;
+ }
+ memcpy(queue_element->pd, pd, bh->block_total_length);
+ g_async_queue_lock(pcap_queue);
+ if (((pcap_queue_byte_limit == 0) || (pcap_queue_bytes < pcap_queue_byte_limit)) &&
+ ((pcap_queue_packet_limit == 0) || (pcap_queue_packets < pcap_queue_packet_limit))) {
+ limit_reached = FALSE;
+ g_async_queue_push_unlocked(pcap_queue, queue_element);
+ pcap_queue_bytes += bh->block_total_length;
+ pcap_queue_packets += 1;
+ } else {
+ limit_reached = TRUE;
+ }
+ g_async_queue_unlock(pcap_queue);
+ if (limit_reached) {
+ pcap_src->dropped++;
+ g_free(queue_element->pd);
+ g_free(queue_element);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+ "Dropped a packet of length %d captured on interface %u.",
+ bh->block_total_length, pcap_src->interface_id);
+ } else {
+ pcap_src->received++;
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+ "Queued a packet of length %d captured on interface %u.",
+ bh->block_total_length, pcap_src->interface_id);
+ }
+ /* I don't want to hold the mutex over the debug output. So the
+ output may be wrong */
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+ "Queue size is now %" G_GINT64_MODIFIER "d bytes (%" G_GINT64_MODIFIER "d packets)",
+ pcap_queue_bytes, pcap_queue_packets);
+}
+
static int
set_80211_channel(const char *iface, const char *opt)
{