#include <signal.h>
#include <errno.h>
-#include <wsutil/cmdarg_err.h>
-#include <wsutil/crash_info.h>
+#include <ui/cmdarg_err.h>
#include <wsutil/strtoi.h>
+#include <cli_main.h>
#include <version_info.h>
#ifndef HAVE_GETOPT_LONG
#include "writecap/pcapio.h"
-#ifdef _WIN32
-#include <wsutil/unicode-utils.h>
-#endif
-
#ifndef _WIN32
#include <sys/un.h>
#endif
-#include <wsutil/clopts_common.h>
+#include <ui/clopts_common.h>
#include <wsutil/privileges.h>
#include "sync_pipe.h"
#include <capchild/capture_session.h>
#include <capchild/capture_sync.h>
-#include "conditions.h"
-#include "capture_stop_conditions.h"
-
#include "wsutil/tempfile.h"
#include "log.h"
#include "wsutil/file_util.h"
/** Stop a low-level capture (stops the capture child). */
static void capture_loop_stop(void);
/** Close a pipe, or socket if \a from_socket is TRUE */
-static void cap_pipe_close(int pipe_fd, gboolean from_socket _U_);
+static void cap_pipe_close(int pipe_fd, gboolean from_socket);
#if !defined (__linux__)
#ifndef HAVE_PCAP_BREAKLOOP
} 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 */
+ gboolean byte_swapped; /**< TRUE if data in the pipe is byte swapped. */
+ 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 */
+ GArray *src_iface_to_global; /**< Int array mapping local IDB numbers to global_ld.interface_data */
} pcapng_pipe_info_t;
struct _loop_data; /* forward declaration so we can use it in the cap_pipe_dispatch function pointer */
#endif
int cap_pipe_fd; /**< the file descriptor of the capture pipe */
gboolean cap_pipe_modified; /**< TRUE if data in the pipe uses modified pcap headers */
- gboolean cap_pipe_byte_swapped; /**< TRUE if data in the pipe is byte swapped */
char * cap_pipe_databuf; /**< Pointer to the data buffer we've allocated */
size_t cap_pipe_databuf_size; /**< Current size of the data buffer */
guint cap_pipe_max_pkt_size; /**< Maximum packet size allowed */
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);
+ int (*cap_pipe_dispatch)(struct _loop_data *, struct _capture_src *, char *, size_t);
cap_pipe_state_t cap_pipe_state;
cap_pipe_err_t cap_pipe_err;
#endif
} 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.
*/
/* common */
gboolean go; /**< TRUE as long as we're supposed to keep capturing */
int err; /**< if non-zero, error seen while capturing */
- gint packet_count; /**< Number of packets we have already captured */
- gint packet_max; /**< Number of packets we're supposed to capture - 0 means infinite */
+ gint packets_captured; /**< Number of packets we have already captured */
guint inpkts_to_sync_pipe; /**< Packets not already send out to the sync_pipe */
#ifdef SIGINFO
gboolean report_packet_count; /**< Set by SIGINFO handler; print packet count */
#endif
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) */
FILE *pdh;
int save_file_fd;
- guint64 bytes_written;
- guint32 autostop_files;
+ guint64 bytes_written; /**< Bytes written for the current file. */
+ /* autostop conditions */
+ int packets_written; /**< Packets written for the current file. */
+ int file_count;
+ /* ring buffer conditions */
+ GTimer *file_duration_timer;
+ time_t next_interval_time;
+ int interval_s;
} loop_data;
typedef struct _pcap_queue_element {
/*
* 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;
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_write_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_header_s *bh, u_char *pd);
+static void capture_loop_queue_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_header_s *bh, u_char *pd);
static void capture_loop_get_errmsg(char *errmsg, size_t errmsglen,
char *secondary_errmsg,
size_t secondary_errmsglen,
fprintf(output, "Stop conditions:\n");
fprintf(output, " -c <packet count> stop after n packets (def: infinite)\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, " packets:NUM - stop after NUM packets\n");
/*fprintf(output, "\n");*/
fprintf(output, "Output (files):\n");
fprintf(output, " -w <filename> name of file to save (def: tempfile)\n");
fprintf(output, " -g enable group read access on the output file(s)\n");
fprintf(output, " -b <ringbuffer opt.> ... duration:NUM - switch to next file after 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, " packets:NUM - ringbuffer: replace after NUM packets\n");
fprintf(output, " -n use pcapng format instead of pcap (default)\n");
fprintf(output, " -P use libpcap format instead of pcapng\n");
fprintf(output, " --capture-comment <comment>\n");
"%s: EUID: %d Capabilities: %s", pfx,
geteuid(), cap_to_text(caps, NULL));
cap_free(caps);
+}
#else
print_caps(const char *pfx _U_) {
-#endif
}
+#endif
static void
relinquish_all_capabilities(void)
#define PLATFORM_PERMISSIONS_SUGGESTION \
"\n\n" \
"On Debian and Debian derivatives such as Ubuntu, if you have " \
- "installed Wireshark from a package, try running " \
- "\"dpkg-reconfigure wireshark-common\"."
+ "installed Wireshark from a package, try running" \
+ "\n\n" \
+ " sudo dpkg-reconfigure wireshark-common" \
+ "\n\n" \
+ "selecting \"<Yes>\" in response to the question" \
+ "\n\n" \
+ " Should non-superusers be able to capture packets?" \
+ "\n\n" \
+ "adding yourself to the \"wireshark\" group by running" \
+ "\n\n" \
+ " sudo usermod -a -G wireshark {your username}" \
+ "\n\n" \
+ "and then logging out and logging back in again."
+#elif defined(__APPLE__)
+ #define PLATFORM_PERMISSIONS_SUGGESTION \
+ "\n\n" \
+ "If you installed Wireshark using the package from wireshark.org, "\
+ "Try re-installing it and checking the box for the \"Set capture " \
+ "permissions on startup\" item."
#else
#define PLATFORM_PERMISSIONS_SUGGESTION
#endif
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
"Console: Control signal");
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "Console: Control signal, CtrlType: %u", dwCtrlType);
+ "Console: Control signal, CtrlType: %lu", dwCtrlType);
/* Keep capture running if we're a service and a user logs off */
if (capture_child || (dwCtrlType != CTRL_LOGOFF_EVENT)) {
{
/* Don't print this if we're a capture child. */
if (!capture_child && reportit) {
- fprintf(stderr, "\rPackets captured: %d\n", global_ld.packet_count);
+ fprintf(stderr, "\rPackets captured: %d\n", global_ld.packets_captured);
/* stderr could be line buffered */
fflush(stderr);
}
/* Take care of byte order in the libpcap headers read from pipes.
* (function taken from wiretap/libpcap.c) */
static void
-cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
+cap_pipe_adjust_pcap_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
{
if (byte_swapped) {
/* Byte-swap the record header fields. */
#else /* _WIN32 */
size_t bytes_read;
#endif /* _WIN32 */
- ssize_t b;
pcap_src = (capture_src *)arg;
while (pcap_src->cap_pipe_err == PIPOK) {
#endif
)
{
+ ssize_t b;
b = cap_pipe_read(pcap_src->cap_pipe_fd, pcap_src->cap_pipe_buf+bytes_read,
pcap_src->cap_pipe_bytes_to_read - bytes_read, pcap_src->from_cap_socket);
if (b <= 0) {
/* If we try to use read() on a named pipe on Windows with partial
* data it appears to return EOF.
*/
+ DWORD b;
res = ReadFile(pcap_src->cap_pipe_h, pcap_src->cap_pipe_buf+bytes_read,
pcap_src->cap_pipe_bytes_to_read - bytes_read,
&b, NULL);
#define DEF_TCP_PORT 19000
static int
-cap_open_socket(char *pipename, capture_src *pcap_src, char *errmsg, int errmsgl)
+cap_open_socket(char *pipename, capture_src *pcap_src, char *errmsg, size_t errmsgl)
{
char *sockname = pipename + 4;
struct sockaddr_in sa;
NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorText, 0, NULL);
#endif
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated due to the socket error: \n"
#ifdef _WIN32
- " %d: %S", lastError, errorText ? (char *)errorText : "Unknown");
+ " %d: %s", lastError, errorText ? (char *)errorText : "Unknown");
if (errorText)
LocalFree(errorText);
#else
return fd;
fail_invalid:
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated because\n"
"\"%s\" is not a valid socket specification", pipename);
pcap_src->cap_pipe_err = PIPERR;
* otherwise.
*/
static void
-cap_pipe_close(int pipe_fd, gboolean from_socket _U_)
+cap_pipe_close(int pipe_fd, gboolean from_socket)
{
#ifdef _WIN32
if (from_socket) {
closesocket(pipe_fd);
}
#else
+ (void) from_socket; /* Mark unused, similar to Q_UNUSED */
ws_close(pipe_fd);
#endif
}
-static int
-cap_pipe_read_data_bytes(capture_src *pcap_src, char *errmsg, int errmsgl)
+/** Read bytes from a capture source, which is assumed to be a pipe.
+ *
+ * Returns -1, or the number of bytes read similar to read(2).
+ * Sets pcap_src->cap_pipe_err on error or EOF.
+ */
+static ssize_t
+cap_pipe_read_data_bytes(capture_src *pcap_src, char *errmsg, size_t errmsgl)
{
int sel_ret;
int fd = pcap_src->cap_pipe_fd;
#ifdef _WIN32
DWORD sz, bytes_read = 0;
#else /* _WIN32 */
- size_t sz, bytes_read = 0;
+ ssize_t sz, bytes_read = 0;
#endif /* _WIN32 */
ssize_t b;
+#ifdef LOG_CAPTURE_VERBOSE
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_read_data_bytes read %lu of %lu",
+ pcap_src->cap_pipe_bytes_read, pcap_src->cap_pipe_bytes_to_read);
+#endif
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.");
+ g_snprintf(errmsg, (gulong)errmsgl, "Invalid file descriptor.");
+ pcap_src->cap_pipe_err = PIPNEXIST;
return -1;
}
sel_ret = cap_pipe_select(fd);
if (sel_ret < 0) {
- g_snprintf(errmsg, errmsgl,
- "Unexpected error from select: %s.", g_strerror(errno));
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Unexpected error from select: %s.", g_strerror(errno));
+ pcap_src->cap_pipe_err = PIPERR;
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));
+ if (b == 0) {
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "End of file on pipe during cap_pipe_read.");
+ pcap_src->cap_pipe_err = PIPEOF;
+ } else {
+#ifdef _WIN32
+ LPTSTR errorText = NULL;
+ int lastError = WSAGetLastError();
+ errno = lastError;
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&errorText, 0, NULL);
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error on pipe data during cap_pipe_read: "
+ " %d: %s", lastError,
+ errorText ? (char *)errorText : "Unknown");
+ if (errorText)
+ LocalFree(errorText);
+#else
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error on pipe data during cap_pipe_read: %s.",
+ g_strerror(errno));
+#endif
+ pcap_src->cap_pipe_err = PIPERR;
+ }
return -1;
}
bytes_read += b;
}
}
pcap_src->cap_pipe_bytes_read += bytes_read;
- return 0;
+#ifdef LOG_CAPTURE_VERBOSE
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_read_data_bytes read %lu of %lu",
+ pcap_src->cap_pipe_bytes_read, pcap_src->cap_pipe_bytes_to_read);
+#endif
+ return bytes_read;
}
/* 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);
+static void pcap_pipe_open_live(int fd, capture_src *pcap_src,
+ struct pcap_hdr *hdr,
+ char *errmsg, size_t errmsgl,
+ char *secondary_errmsg, size_t secondary_errmsgl);
+static void pcapng_pipe_open_live(int fd, capture_src *pcap_src,
+ char *errmsg, size_t errmsgl);
+static int pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src,
+ char *errmsg, size_t errmsgl);
+
+/* For problems that are probably Not Our Fault. */
+static char not_our_bug[] =
+ "Please report this to the developers of the program writing to the pipe.";
/* Mimic pcap_open_live() for pipe captures
cap_pipe_open_live(char *pipename,
capture_src *pcap_src,
void *hdr,
- char *errmsg, int errmsgl)
+ char *errmsg, size_t errmsgl,
+ char *secondary_errmsg, size_t secondary_errmsgl)
{
#ifndef _WIN32
ws_statb64 pipe_stat;
if (errno == ENOENT || errno == ENOTDIR)
pcap_src->cap_pipe_err = PIPNEXIST;
else {
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated "
"due to error getting information on pipe/socket: %s.", g_strerror(errno));
pcap_src->cap_pipe_err = PIPERR;
if (S_ISFIFO(pipe_stat.st_mode)) {
fd = ws_open(pipename, O_RDONLY | O_NONBLOCK, 0000 /* no creation so don't matter */);
if (fd == -1) {
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated "
"due to error on pipe open: %s.", g_strerror(errno));
pcap_src->cap_pipe_err = PIPERR;
} else if (S_ISSOCK(pipe_stat.st_mode)) {
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated "
"due to error on socket create: %s.", g_strerror(errno));
pcap_src->cap_pipe_err = PIPERR;
*/
if (g_strlcpy(sa.sun_path, pipename, sizeof sa.sun_path) > sizeof sa.sun_path) {
/* Path name too long */
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session coud not be initiated "
"due to error on socket connect: Path name too long.");
pcap_src->cap_pipe_err = PIPERR;
}
b = connect(fd, (struct sockaddr *)&sa, sizeof sa);
if (b == -1) {
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session coud not be initiated "
"due to error on socket connect: %s.", g_strerror(errno));
pcap_src->cap_pipe_err = PIPERR;
*/
pcap_src->cap_pipe_err = PIPNEXIST;
} else {
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated because\n"
"\"%s\" is neither an interface nor a socket nor a pipe.", pipename);
pcap_src->cap_pipe_err = PIPERR;
g_free(pncopy);
if (!pos) {
- g_snprintf(errmsg, errmsgl,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session could not be initiated because\n"
"\"%s\" is neither an interface nor a pipe.", pipename);
pcap_src->cap_pipe_err = PIPNEXIST;
if (GetLastError() != ERROR_PIPE_BUSY) {
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,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session on \"%s\" could not be started "
- "due to error on pipe open: %s (error %d).",
+ "due to error on pipe open: %s (error %lu).",
pipename, utf_16to8(err_str), GetLastError());
LocalFree(err_str);
pcap_src->cap_pipe_err = PIPERR;
if (!WaitNamedPipe(utf_8to16(pipename), 30 * 1000)) {
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,
+ g_snprintf(errmsg, (gulong)errmsgl,
"The capture session on \"%s\" timed out during "
- "pipe open: %s (error %d).",
+ "pipe open: %s (error %lu).",
pipename, utf_16to8(err_str), GetLastError());
LocalFree(err_str);
pcap_src->cap_pipe_err = PIPERR;
* large enough for most regular network packets. We increase it,
* up to the maximum size we allow, as necessary.
*/
- pcap_src->cap_pipe_databuf = (guchar*)g_malloc(2048);
+ pcap_src->cap_pipe_databuf = (char*)g_malloc(2048);
pcap_src->cap_pipe_databuf_size = 2048;
#ifdef _WIN32
while (bytes_read < sizeof magic) {
sel_ret = cap_pipe_select(fd);
if (sel_ret < 0) {
- g_snprintf(errmsg, errmsgl,
- "Unexpected error from select: %s.", g_strerror(errno));
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Unexpected error from select: %s.",
+ g_strerror(errno));
goto error;
} else if (sel_ret > 0) {
b = cap_pipe_read(fd, ((char *)&magic)+bytes_read,
if (b <= 0) {
if (b == 0)
- g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open.");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "End of file on pipe magic during open.");
else
- g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s.",
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error on pipe magic during open: %s.",
g_strerror(errno));
goto error;
}
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 magic during open.");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "End of file on pipe magic during open.");
else
- g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s.",
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error on pipe magic during open: %s.",
g_strerror(errno));
goto error;
}
case PCAP_NSEC_MAGIC:
/* Host that wrote it has our byte order, and was running
a program using either standard or ss990417 libpcap. */
- pcap_src->cap_pipe_byte_swapped = FALSE;
+ pcap_src->cap_pipe_info.pcap.byte_swapped = FALSE;
pcap_src->cap_pipe_modified = FALSE;
pcap_src->ts_nsec = magic == PCAP_NSEC_MAGIC;
break;
case PCAP_MODIFIED_MAGIC:
/* Host that wrote it has our byte order, but was running
a program using either ss990915 or ss991029 libpcap. */
- pcap_src->cap_pipe_byte_swapped = FALSE;
+ pcap_src->cap_pipe_info.pcap.byte_swapped = FALSE;
pcap_src->cap_pipe_modified = TRUE;
break;
case PCAP_SWAPPED_MAGIC:
/* Host that wrote it has a byte order opposite to ours,
and was running a program using either standard or
ss990417 libpcap. */
- pcap_src->cap_pipe_byte_swapped = TRUE;
+ pcap_src->cap_pipe_info.pcap.byte_swapped = TRUE;
pcap_src->cap_pipe_modified = FALSE;
pcap_src->ts_nsec = magic == PCAP_SWAPPED_NSEC_MAGIC;
break;
/* Host that wrote it out has a byte order opposite to
ours, and was running a program using either ss990915
or ss991029 libpcap. */
- pcap_src->cap_pipe_byte_swapped = TRUE;
+ pcap_src->cap_pipe_info.pcap.byte_swapped = TRUE;
pcap_src->cap_pipe_modified = TRUE;
break;
case BLOCK_TYPE_SHB:
/* This isn't pcap, it's pcapng. */
pcap_src->from_pcapng = TRUE;
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 */
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.");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Data written to the pipe is neither in a supported pcap format nor in pcapng format.");
+ g_snprintf(secondary_errmsg, (gulong)secondary_errmsgl, "%s",
+ not_our_bug);
goto error;
}
- pcap_pipe_open_live(fd, pcap_src, (struct pcap_hdr *) hdr, errmsg, errmsgl);
+ pcap_pipe_open_live(fd, pcap_src, (struct pcap_hdr *) hdr, errmsg, errmsgl,
+ secondary_errmsg, secondary_errmsgl);
return;
error:
pcap_pipe_open_live(int fd,
capture_src *pcap_src,
struct pcap_hdr *hdr,
- char *errmsg, int errmsgl)
+ char *errmsg, size_t errmsgl,
+ char *secondary_errmsg, size_t secondary_errmsgl)
{
size_t bytes_read;
ssize_t b;
while (bytes_read < sizeof(struct pcap_hdr)) {
sel_ret = cap_pipe_select(fd);
if (sel_ret < 0) {
- g_snprintf(errmsg, errmsgl,
- "Unexpected error from select: %s.", g_strerror(errno));
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Unexpected error from select: %s.",
+ g_strerror(errno));
goto error;
} else if (sel_ret > 0) {
b = cap_pipe_read(fd, ((char *)hdr)+bytes_read,
pcap_src->from_cap_socket);
if (b <= 0) {
if (b == 0)
- g_snprintf(errmsg, errmsgl, "End of file on pipe header during open.");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "End of file on pipe header during open.");
else
- g_snprintf(errmsg, errmsgl, "Error on pipe header during open: %s.",
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error on pipe header during open: %s.",
g_strerror(errno));
+ g_snprintf(secondary_errmsg, (gulong)secondary_errmsgl,
+ "%s", not_our_bug);
goto error;
}
bytes_read += b;
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 header during open.");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "End of file on pipe header during open.");
else
- g_snprintf(errmsg, errmsgl, "Error on pipe header header during open: %s.",
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error on pipe header header during open: %s.",
g_strerror(errno));
+ g_snprintf(secondary_errmsg, (gulong)secondary_errmsgl, "%s",
+ not_our_bug);
goto error;
}
}
#endif
- if (pcap_src->cap_pipe_byte_swapped) {
+ if (pcap_src->cap_pipe_info.pcap.byte_swapped) {
/* Byte-swap the header fields about which we care. */
hdr->version_major = GUINT16_SWAP_LE_BE(hdr->version_major);
hdr->version_minor = GUINT16_SWAP_LE_BE(hdr->version_minor);
pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_DBUS;
} else
#endif
+ if (pcap_src->linktype == 279) { /* DLT_EBHSCR */
+ /*
+ * The maximum EBHSCR message size is 8MB, so allow packets up
+ * to that size.
+ */
+ pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_EBHSCR;
+ }
+ else {
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 version %d.%d",
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "The old pcap format version %d.%d is not supported.",
hdr->version_major, hdr->version_minor);
+ g_snprintf(secondary_errmsg, (gulong)secondary_errmsgl, "%s",
+ not_our_bug);
goto error;
}
- pcap_src->cap_pipe_state = STATE_EXPECT_REC_HDR;
- pcap_src->cap_pipe_err = PIPOK;
pcap_src->cap_pipe_fd = fd;
return;
static int
pcapng_read_shb(capture_src *pcap_src,
char *errmsg,
- int errmsgl)
+ size_t 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;
+ struct pcapng_section_header_block_s 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)) {
+ if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl) < 0) {
return -1;
}
}
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.");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "End of file on pipe section header during open.");
else
- g_snprintf(errmsg, errmsgl, "Error on pipe section header during open: %s.",
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error on pipe section header during open: %s.",
g_strerror(errno));
return -1;
}
+ /* Continuing with STATE_EXPECT_DATA requires reading into cap_pipe_databuf at offset cap_pipe_bytes_read */
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)
+ 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;
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng SHB MAGIC");
break;
case PCAPNG_SWAPPED_MAGIC:
- pcap_src->cap_pipe_byte_swapped = TRUE;
- break;
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng SHB SWAPPED MAGIC");
+ /*
+ * pcapng sources can contain all sorts of block types. Rather than add a bunch of
+ * complexity to this code (which is often privileged), punt and tell the user to
+ * swap bytes elsewhere.
+ */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define OUR_ENDIAN "big"
+#define IFACE_ENDIAN "little"
+#else
+#define OUR_ENDIAN "little"
+#define IFACE_ENDIAN "big"
+#endif
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Interface %u is " IFACE_ENDIAN " endian but we're " OUR_ENDIAN " endian.",
+ pcap_src->interface_id);
+ return -1;
default:
/* Not a pcapng type we know about, or not pcapng at all. */
- g_snprintf(errmsg, errmsgl, "Unrecognized pcapng format or not pcapng data.");
+ g_snprintf(errmsg, (gulong)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 */
+ /* Setup state to capture any options following 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)
+/*
+ * Save IDB blocks for playback whenever we change output files.
+ * Rewrite EPB and ISB interface IDs.
+ */
+static gboolean
+pcapng_adjust_block(capture_src *pcap_src, const struct pcapng_block_header_s *bh, u_char *pd)
{
- guint32 length = bh->block_total_length;
+ switch(bh->block_type) {
+ case BLOCK_TYPE_SHB:
+ {
+ if (global_ld.pcapng_passthrough) {
+ /*
+ * 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(global_ld.saved_shb);
+ global_ld.saved_shb = (guint8 *) g_memdup(pd, bh->block_total_length);
- if (pcap_src->cap_pipe_byte_swapped) {
- length = GUINT32_SWAP_LE_BE(length);
+ /*
+ * We're dealing with one section at a time, so we can (and must)
+ * get rid of our old IDBs.
+ */
+ for (unsigned i = 0; i < global_ld.saved_idbs->len; i++) {
+ saved_idb_t *idb_source = &g_array_index(global_ld.saved_idbs, saved_idb_t, i);
+ g_free(idb_source->idb);
+ }
+ g_array_set_size(global_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(global_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_array_set_size(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, 0);
}
-
- 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;
+ 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(pd, idb_source.idb_len);
+ g_array_append_val(global_ld.saved_idbs, idb_source);
+ guint32 iface_id = global_ld.saved_idbs->len - 1;
+ 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: mapped 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);
}
-
- gpointer data = g_malloc(bh->block_total_length);
- if (data == NULL) {
- return FALSE;
+ break;
+ case BLOCK_TYPE_EPB:
+ case BLOCK_TYPE_ISB:
+ {
+ if (global_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, pd + sizeof(struct pcapng_block_header_s), 4);
+ if (iface_id < pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len) {
+ memcpy(pd + 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;
}
- memcpy(data, pcap_src->cap_pipe_databuf, bh->block_total_length);
-
- pcapng->saved_blocks = g_list_prepend(pcapng->saved_blocks, data);
return TRUE;
}
pcapng_pipe_open_live(int fd,
capture_src *pcap_src,
char *errmsg,
- int errmsgl)
+ size_t errmsgl)
{
guint32 type = BLOCK_TYPE_SHB;
struct pcapng_block_header_s *bh = &pcap_src->cap_pipe_info.pcapng.bh;
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng_pipe_open_live: fd %d", fd);
#ifdef _WIN32
if (pcap_src->from_cap_socket)
#endif
/* 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)) {
+ if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl) < 0) {
goto error;
}
memcpy(bh, pcap_src->cap_pipe_databuf, sizeof(struct pcapng_block_header_s));
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.");
+ g_snprintf(errmsg, (gulong)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_snprintf(errmsg, (gulong)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
/* 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
-pcap_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, size_t errmsgl)
{
struct pcap_pkthdr phdr;
enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
break;
default:
- g_snprintf(errmsg, errmsgl, "pcap_pipe_dispatch: invalid state");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "pcap_pipe_dispatch: invalid state");
result = PD_ERR;
} /* switch (pcap_src->cap_pipe_state) */
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_info->hdr,
+ cap_pipe_adjust_pcap_header(pcap_src->cap_pipe_info.pcap.byte_swapped, &pcap_info->hdr,
&pcap_info->rechdr.hdr);
if (pcap_info->rechdr.hdr.incl_len > pcap_src->cap_pipe_max_pkt_size) {
/*
* 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, pcap_info->rechdr.hdr.incl_len);
+ g_snprintf(errmsg, (gulong)errmsgl, "Frame %u too long (%d bytes)",
+ ld->packets_captured+1, pcap_info->rechdr.hdr.incl_len);
break;
}
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 = (char*)g_realloc(pcap_src->cap_pipe_databuf, new_bufsize);
pcap_src->cap_pipe_databuf_size = new_bufsize;
}
#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)",
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error reading from pipe: %s (error %lu)",
utf_16to8(err_str), GetLastError());
LocalFree(err_str);
#else
- g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
+ g_snprintf(errmsg, (gulong)errmsgl, "Error reading from pipe: %s",
g_strerror(errno));
#endif
/* Fall through */
}
static int
-pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, int errmsgl)
+pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, size_t errmsgl)
{
enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
PD_ERR } result;
switch (pcap_src->cap_pipe_state) {
case STATE_EXPECT_REC_HDR:
+#ifdef LOG_CAPTURE_VERBOSE
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng_pipe_dispatch STATE_EXPECT_REC_HDR");
+#endif
#ifdef _WIN32
if (g_mutex_trylock(pcap_src->cap_pipe_read_mtx)) {
#endif
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);
+ if (!pcap_src->from_cap_socket) {
+ 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 LOG_CAPTURE_VERBOSE
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng_pipe_dispatch STATE_READ_REC_HDR");
+#endif
#ifdef _WIN32
- if (pcap_src->from_cap_socket)
+ if (pcap_src->from_cap_socket) {
#endif
- {
- if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl)) {
+ if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl) < 0) {
return -1;
}
- }
#ifdef _WIN32
- else {
+ } else {
q_status = g_async_queue_timeout_pop(pcap_src->cap_pipe_done_q, PIPE_READ_TIMEOUT);
if (pcap_src->cap_pipe_err == PIPEOF) {
result = PD_PIPE_EOF;
}
}
#endif
- if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read)
+ 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 LOG_CAPTURE_VERBOSE
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng_pipe_dispatch STATE_EXPECT_DATA");
+#endif
#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);
+ if (!pcap_src->from_cap_socket) {
+ 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;
+ pcap_src->cap_pipe_bytes_read = 0;
+ 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 LOG_CAPTURE_VERBOSE
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcapng_pipe_dispatch STATE_READ_DATA");
+#endif
#ifdef _WIN32
- if (pcap_src->from_cap_socket)
+ if (pcap_src->from_cap_socket) {
#endif
- {
- if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl)) {
+ if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl) < 0) {
return -1;
}
- if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read)
- return 0;
- }
#ifdef _WIN32
- else {
+ } else {
q_status = g_async_queue_timeout_pop(pcap_src->cap_pipe_done_q, PIPE_READ_TIMEOUT);
if (pcap_src->cap_pipe_err == PIPEOF) {
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 */
+ if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read) {
+ return 0;
+ }
result = PD_DATA_READ;
break;
default:
- g_snprintf(errmsg, errmsgl, "pcapng_pipe_dispatch: invalid state");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "pcapng_pipe_dispatch: invalid state");
result = PD_ERR;
} /* switch (pcap_src->cap_pipe_state) */
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
* 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);
+ g_snprintf(errmsg, (gulong)errmsgl, "Frame %u too long (%d bytes)",
+ ld->packets_captured+1, bh->block_total_length);
break;
}
/* 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");
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "malformed pcapng block_total_length < minimum");
pcap_src->cap_pipe_err = PIPEOF;
return -1;
}
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 {
#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)",
+ g_snprintf(errmsg, (gulong)errmsgl,
+ "Error reading from pipe: %s (error %lu)",
utf_16to8(err_str), GetLastError());
LocalFree(err_str);
#else
- g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
+ g_snprintf(errmsg, (gulong)errmsgl, "Error reading from pipe: %s",
g_strerror(errno));
#endif
/* Fall through */
return FALSE;
}
+ int pcapng_src_count = 0;
for (i = 0; i < capture_opts->ifaces->len; i++) {
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
- pcap_src = (capture_src *)g_malloc(sizeof (capture_src));
+ pcap_src = (capture_src *)g_malloc0(sizeof (capture_src));
if (pcap_src == NULL) {
g_snprintf(errmsg, (gulong) errmsg_len,
"Could not allocate memory.");
return FALSE;
}
- memset(pcap_src, 0, sizeof(capture_src));
+
+ /*
+ * 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
pcap_src->pcap_fd = -1;
#endif
} 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_info.pcap.hdr, errmsg, (int) errmsg_len);
+ gboolean pipe_err = FALSE;
+ cap_pipe_open_live(interface_opts->name, pcap_src,
+ &pcap_src->cap_pipe_info.pcap.hdr,
+ errmsg, errmsg_len,
+ secondary_errmsg, secondary_errmsg_len);
-#ifndef _WIN32
- if (pcap_src->cap_pipe_fd == -1) {
-#else
- if (pcap_src->cap_pipe_h == INVALID_HANDLE_VALUE) {
+#ifdef _WIN32
+ if (pcap_src->from_cap_socket) {
#endif
+ if (pcap_src->cap_pipe_fd == -1) {
+ pipe_err = TRUE;
+ }
+#ifdef _WIN32
+ } else {
+ if (pcap_src->cap_pipe_h == INVALID_HANDLE_VALUE) {
+ pipe_err = TRUE;
+ }
+ }
+#endif
+
+ if (pipe_err) {
if (pcap_src->cap_pipe_err == PIPNEXIST) {
/*
* We tried opening as an interface, and that failed,
report_capture_error(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 */
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;
+ g_array_free(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, TRUE);
+ pcap_src->cap_pipe_info.pcapng.src_iface_to_global = NULL;
}
} else {
/* Capture device. If open, close the pcap_t. */
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);
+
+ successful = pcapng_write_section_header_block(ld->pdh,
+ (const char *)capture_opts->capture_comment, /* Comment */
+ cpu_info_str->str, /* HW */
+ os_info_str->str, /* OS */
+ get_appname_and_version(),
+ -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);
+ }
+
+ 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 */
static gboolean
capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len)
{
int err;
- guint i;
- capture_src *pcap_src;
- interface_options *interface_opts;
gboolean successful;
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_init_output");
}
}
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;
- 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);
-
+ successful = capture_loop_init_pcapng_output(capture_opts, ld);
} else {
+ capture_src *pcap_src;
pcap_src = g_array_index(ld->pcaps, capture_src *, 0);
if (pcap_src->from_cap_pipe) {
pcap_src->snaplen = pcap_src->cap_pipe_info.pcap.hdr.snaplen;
capture_loop_dispatch(loop_data *ld,
char *errmsg, int errmsg_len, capture_src *pcap_src)
{
- int inpkts;
+ int inpkts = 0;
gint packet_count_before;
-#ifndef _WIN32
int sel_ret;
-#endif
- packet_count_before = ld->packet_count;
+ packet_count_before = ld->packets_captured;
if (pcap_src->from_cap_pipe) {
/* dispatch from capture pipe */
#ifdef LOG_CAPTURE_VERBOSE
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe");
#endif
-#ifndef _WIN32
- sel_ret = cap_pipe_select(pcap_src->cap_pipe_fd);
- if (sel_ret <= 0) {
- if (sel_ret < 0 && errno != EINTR) {
- g_snprintf(errmsg, errmsg_len,
- "Unexpected error from select: %s", g_strerror(errno));
- report_capture_error(errmsg, please_report);
- ld->go = FALSE;
+#ifdef _WIN32
+ if (pcap_src->from_cap_socket) {
+#endif
+ sel_ret = cap_pipe_select(pcap_src->cap_pipe_fd);
+ if (sel_ret <= 0) {
+ if (sel_ret < 0 && errno != EINTR) {
+ g_snprintf(errmsg, errmsg_len,
+ "Unexpected error from select: %s", g_strerror(errno));
+ report_capture_error(errmsg, please_report);
+ ld->go = FALSE;
+ }
}
+#ifdef _WIN32
} else {
+ /* Windows does not have select() for pipes. */
+ /* Proceed with _dispatch() which waits for cap_pipe_done_q
+ * notification from cap_thread_read() when ReadFile() on
+ * the pipe has read enough bytes. */
+ sel_ret = 1;
+ }
+#endif
+ if (sel_ret > 0) {
/*
* "select()" says we can read from the pipe without blocking
*/
-#endif
inpkts = pcap_src->cap_pipe_dispatch(ld, pcap_src, errmsg, errmsg_len);
if (inpkts < 0) {
- ld->go = FALSE;
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "%s: src %u pipe reached EOF or err, rcv: %u drop: %u flush: %u",
+ G_STRFUNC, pcap_src->interface_id, pcap_src->received, pcap_src->dropped, pcap_src->flushed);
+ g_assert(pcap_src->cap_pipe_err != PIPOK);
}
-#ifndef _WIN32
}
-#endif
}
else
{
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: %d new packet%s", inpkts, plurality(inpkts, "", "s"));
#endif
- return ld->packet_count - packet_count_before;
+ return ld->packets_captured - packet_count_before;
}
#ifdef _WIN32
} else {
/* Choose a random name for the temporary capture buffer */
if (global_capture_opts.ifaces->len > 1) {
+ /*
+ * More than one interface; just use the number of interfaces
+ * to generate the temporary file name prefix.
+ */
prefix = g_strdup_printf("wireshark_%d_interfaces", global_capture_opts.ifaces->len);
- if (capture_opts->use_pcapng) {
- suffix = ".pcapng";
- }else{
- suffix = ".pcap";
- }
} else {
+ /*
+ * One interface; use its description, if it has one, to generate
+ * the temporary file name, otherwise use its name.
+ */
gchar *basename;
- basename = g_path_get_basename((&g_array_index(global_capture_opts.ifaces, interface_options, 0))->console_display_name);
+ const interface_options *interface_opts;
+
+ interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, 0);
+
+ /*
+ * Do we have a description?
+ */
+ if (interface_opts->descr) {
+ /*
+ * Yes - use it.
+ *
+ * Strip off any stuff we shouldn't use in the file name,
+ * by getting the last component of what would be a file
+ * name.
+ */
+ basename = g_path_get_basename(interface_opts->descr);
+ } else {
+ /*
+ * No - use the name.
+ *
+ * Strip off any stuff we shouldn't use in the file name,
+ * by getting the last component of what would be a file
+ * name.
+ */
+ basename = g_path_get_basename(interface_opts->name);
#ifdef _WIN32
- /* use the generic portion of the interface guid to form the basis of the filename */
- if (strncmp("NPF_{", basename, 5)==0)
- {
- /* we have a windows guid style device name, extract the guid digits as the basis of the filename */
- GString *iface;
- iface = isolate_uuid(basename);
- g_free(basename);
- basename = g_strdup(iface->str);
- g_string_free(iface, TRUE);
- }
+ /*
+ * This is Windows, where we might have an ugly GUID-based
+ * interface name.
+ *
+ * If it's an ugly GUID-based name, use the generic portion
+ * of the interface GUID to form the basis of the filename.
+ */
+ if (strncmp("NPF_{", basename, 5) == 0) {
+ /*
+ * We have a GUID-based name; extract the GUID digits
+ * as the basis of the filename.
+ */
+ GString *iface;
+ iface = isolate_uuid(basename);
+ g_free(basename);
+ basename = g_strdup(iface->str);
+ g_string_free(iface, TRUE);
+ }
#endif
- /* generate the temp file name prefix and suffix */
- if (capture_opts->use_pcapng) {
- prefix = g_strconcat("wireshark_", basename, NULL);
- suffix = ".pcapng";
- }else{
- prefix = g_strconcat("wireshark_", basename, NULL);
- suffix = ".pcap";
}
+ /* generate the temp file name prefix */
+ prefix = g_strconcat("wireshark_", basename, NULL);
g_free(basename);
}
+
+ /* Generate the appropriate suffix. */
+ if (capture_opts->use_pcapng) {
+ suffix = ".pcapng";
+ } else {
+ suffix = ".pcap";
+ }
*save_file_fd = create_tempfile(&tmpname, prefix, suffix);
g_free(prefix);
capfile_name = g_strdup(tmpname);
return TRUE;
}
+static time_t get_next_time_interval(int interval_s) {
+ time_t next_time = time(NULL);
+ next_time -= next_time % interval_s;
+ next_time += interval_s;
+ return next_time;
+}
/* Do the work of handling either the file size or file duration capture
conditions being reached, and switching files or stopping. */
static gboolean
-do_file_switch_or_stop(capture_options *capture_opts,
- condition *cnd_autostop_files,
- condition *cnd_autostop_size,
- condition *cnd_file_duration,
- condition *cnd_file_interval)
+do_file_switch_or_stop(capture_options *capture_opts)
{
- guint i;
- capture_src *pcap_src;
- interface_options *interface_opts;
gboolean successful;
if (capture_opts->multi_files_on) {
- if (cnd_autostop_files != NULL &&
- cnd_eval(cnd_autostop_files, (guint64)++global_ld.autostop_files)) {
+ if (capture_opts->has_autostop_files &&
+ ++global_ld.file_count >= capture_opts->autostop_files) {
/* no files left: stop here */
global_ld.go = FALSE;
return FALSE;
/* File switch succeeded: reset the conditions */
global_ld.bytes_written = 0;
- pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0);
- if (pcap_src->from_pcapng) {
- /* Write the saved SHB and all IDBs to start of next file */
- /* 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);
+ global_ld.packets_written = 0;
+ if (capture_opts->use_pcapng) {
+ successful = capture_loop_init_pcapng_output(capture_opts, &global_ld);
} 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);
-
- } 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);
- }
+ capture_src *pcap_src;
+ 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);
global_ld.pdh = NULL;
global_ld.go = FALSE;
return FALSE;
}
- if (cnd_autostop_size)
- cnd_reset(cnd_autostop_size);
- if (cnd_file_duration)
- cnd_reset(cnd_file_duration);
- if (cnd_file_interval)
- cnd_reset(cnd_file_interval);
+ if (global_ld.file_duration_timer) {
+ g_timer_reset(global_ld.file_duration_timer);
+ }
+ if (global_ld.next_interval_time) {
+ global_ld.next_interval_time = get_next_time_interval(global_ld.interval_s);
+ }
fflush(global_ld.pdh);
if (!quiet)
report_packet_count(global_ld.inpkts_to_sync_pipe);
static void *
pcap_read_handler(void* arg)
{
- capture_src *pcap_src;
+ capture_src *pcap_src = (capture_src *)arg;
char errmsg[MSG_MAX_LENGTH+1];
- pcap_src = (capture_src *)arg;
-
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Started thread for interface %d.",
pcap_src->interface_id);
- while (global_ld.go) {
+ /* If this is a pipe input it might finish early. */
+ while (global_ld.go && pcap_src->cap_pipe_err == PIPOK) {
/* dispatch incoming packets */
capture_loop_dispatch(&global_ld, errmsg, sizeof(errmsg), pcap_src);
}
+
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Stopped thread for interface %d.",
pcap_src->interface_id);
g_thread_exit(NULL);
return (NULL);
}
+/* Try to pop an item off the packet queue and if it exists, write it */
+static gboolean
+capture_loop_dequeue_packet(void) {
+ pcap_queue_element *queue_element;
+
+ g_async_queue_lock(pcap_queue);
+ queue_element = (pcap_queue_element *)g_async_queue_timeout_pop_unlocked(pcap_queue, WRITER_THREAD_TIMEOUT);
+ if (queue_element) {
+ if (queue_element->pcap_src->from_pcapng) {
+ pcap_queue_bytes -= queue_element->u.bh.block_total_length;
+ } else {
+ pcap_queue_bytes -= queue_element->u.phdr.caplen;
+ }
+ pcap_queue_packets -= 1;
+ }
+ g_async_queue_unlock(pcap_queue);
+ if (queue_element) {
+ if (queue_element->pcap_src->from_pcapng) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
+ "Dequeued a block of type 0x%08x of length %d captured on interface %d.",
+ queue_element->u.bh.block_type, queue_element->u.bh.block_total_length,
+ queue_element->pcap_src->interface_id);
+
+ 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);
+ return TRUE;
+ }
+ return FALSE;
+}
+
/* Do the low-level work of a capture.
Returns TRUE if it succeeds, FALSE otherwise. */
static gboolean
#endif
int err_close;
int inpkts;
- condition *cnd_file_duration = NULL;
- condition *cnd_file_interval = NULL;
- condition *cnd_autostop_files = NULL;
- condition *cnd_autostop_size = NULL;
- condition *cnd_autostop_duration = NULL;
+ GTimer *autostop_duration_timer = NULL;
gboolean write_ok;
gboolean close_ok;
gboolean cfilter_error = FALSE;
/* init the loop data */
global_ld.go = TRUE;
- global_ld.packet_count = 0;
+ global_ld.packets_captured = 0;
#ifdef SIGINFO
global_ld.report_packet_count = FALSE;
#endif
- if (capture_opts->has_autostop_packets)
- global_ld.packet_max = capture_opts->autostop_packets;
- else
- global_ld.packet_max = 0; /* no limit */
global_ld.inpkts_to_sync_pipe = 0;
global_ld.err = 0; /* no error seen yet */
global_ld.pdh = NULL;
- global_ld.autostop_files = 0;
global_ld.save_file_fd = -1;
+ global_ld.file_count = 0;
+ global_ld.file_duration_timer = NULL;
+ global_ld.next_interval_time = 0;
+ global_ld.interval_s = 0;
/* We haven't yet gotten the capture statistics. */
*stats_known = FALSE;
report_new_capture_file(capture_opts->save_file);
}
- /* initialize capture stop (and alike) conditions */
- init_capture_stop_conditions();
+ if (capture_opts->has_file_interval) {
+ global_ld.interval_s = capture_opts->file_interval;
+ global_ld.next_interval_time = get_next_time_interval(global_ld.interval_s);
+ }
/* create stop conditions */
if (capture_opts->has_autostop_filesize) {
if (capture_opts->autostop_filesize > (((guint32)INT_MAX + 1) / 1000)) {
capture_opts->autostop_filesize = ((guint32)INT_MAX + 1) / 1000;
}
- cnd_autostop_size =
- cnd_new(CND_CLASS_CAPTURESIZE, (guint64)capture_opts->autostop_filesize * 1000);
}
- if (capture_opts->has_autostop_duration)
- cnd_autostop_duration =
- cnd_new(CND_CLASS_TIMEOUT,(gint32)capture_opts->autostop_duration);
+ if (capture_opts->has_autostop_duration) {
+ autostop_duration_timer = g_timer_new();
+ }
if (capture_opts->multi_files_on) {
- if (capture_opts->has_file_duration)
- cnd_file_duration =
- cnd_new(CND_CLASS_TIMEOUT, capture_opts->file_duration);
-
- if (capture_opts->has_autostop_files)
- cnd_autostop_files =
- cnd_new(CND_CLASS_CAPTURESIZE, (guint64)capture_opts->autostop_files);
-
- if (capture_opts->has_file_interval)
- cnd_file_interval =
- cnd_new(CND_CLASS_INTERVAL, capture_opts->file_interval);
+ if (capture_opts->has_file_duration) {
+ global_ld.file_duration_timer = g_timer_new();
+ }
}
/* init the time values */
while (global_ld.go) {
/* dispatch incoming packets */
if (use_threads) {
- pcap_queue_element *queue_element;
-
- g_async_queue_lock(pcap_queue);
- queue_element = (pcap_queue_element *)g_async_queue_timeout_pop_unlocked(pcap_queue, WRITER_THREAD_TIMEOUT);
- if (queue_element) {
- 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) {
- 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);
+ gboolean dequeued = capture_loop_dequeue_packet();
- 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);
+ if (dequeued) {
inpkts = 1;
} else {
inpkts = 0;
inpkts = capture_loop_dispatch(&global_ld, errmsg,
sizeof(errmsg), pcap_src);
}
+ if (inpkts == 0) {
+ /* Stop capturing if all of our sources are pipes and none of them are open. */
+ gboolean open_interfaces = FALSE;
+ for (i = 0; i < global_ld.pcaps->len; i++) {
+ pcap_src = g_array_index(global_ld.pcaps, capture_src *, i);
+ if (pcap_src->cap_pipe_err == PIPOK) {
+ /* True for both non-pipes and open pipes. */
+ open_interfaces = TRUE;
+ }
+ }
+ if (!open_interfaces) {
+ global_ld.go = FALSE;
+ }
+ }
#ifdef SIGINFO
/* Were we asked to print packet counts by the SIGINFO handler? */
if (global_ld.report_packet_count) {
- fprintf(stderr, "%u packet%s captured\n", global_ld.packet_count,
- plurality(global_ld.packet_count, "", "s"));
+ fprintf(stderr, "%u packet%s captured\n", global_ld.packets_captured,
+ plurality(global_ld.packets_captured, "", "s"));
global_ld.report_packet_count = FALSE;
}
#endif
if (inpkts > 0) {
global_ld.inpkts_to_sync_pipe += inpkts;
- /* check capture size condition */
- if (cnd_autostop_size != NULL &&
- cnd_eval(cnd_autostop_size, global_ld.bytes_written)) {
- /* Capture size limit reached, do we have another file? */
- if (!do_file_switch_or_stop(capture_opts,
- cnd_autostop_files,
- cnd_autostop_size,
- cnd_file_duration,
- cnd_file_interval))
- continue;
- } /* cnd_autostop_size */
if (capture_opts->output_to_pipe) {
fflush(global_ld.pdh);
}
#ifdef _WIN32
cur_time = GetTickCount(); /* Note: wraps to 0 if sys runs for 49.7 days */
- if ((cur_time - upd_time) > DUMPCAP_UPD_TIME) { /* wrap just causes an extra update */
+ if ((cur_time - upd_time) > DUMPCAP_UPD_TIME) /* wrap just causes an extra update */
#else
gettimeofday(&cur_time, NULL);
if (((guint64)cur_time.tv_sec * 1000000 + cur_time.tv_usec) >
- ((guint64)upd_time.tv_sec * 1000000 + upd_time.tv_usec + DUMPCAP_UPD_TIME*1000)) {
+ ((guint64)upd_time.tv_sec * 1000000 + upd_time.tv_usec + DUMPCAP_UPD_TIME*1000))
#endif
+ {
upd_time = cur_time;
}
/* check capture duration condition */
- if (cnd_autostop_duration != NULL && cnd_eval(cnd_autostop_duration)) {
+ if (autostop_duration_timer != NULL && g_timer_elapsed(autostop_duration_timer, NULL) >= capture_opts->autostop_duration) {
/* The maximum capture time has elapsed; stop the capture. */
global_ld.go = FALSE;
continue;
}
/* check capture file duration condition */
- if (cnd_file_duration != NULL && cnd_eval(cnd_file_duration)) {
+ if (global_ld.file_duration_timer != NULL && g_timer_elapsed(global_ld.file_duration_timer, NULL) >= capture_opts->file_duration) {
/* duration limit reached, do we have another file? */
- if (!do_file_switch_or_stop(capture_opts,
- cnd_autostop_files,
- cnd_autostop_size,
- cnd_file_duration,
- cnd_file_interval))
+ if (!do_file_switch_or_stop(capture_opts))
continue;
} /* cnd_file_duration */
/* check capture file interval condition */
- if (cnd_file_interval != NULL && cnd_eval(cnd_file_interval)) {
+ if (global_ld.interval_s && time(NULL) >= global_ld.next_interval_time) {
/* end of interval reached, do we have another file? */
- if (!do_file_switch_or_stop(capture_opts,
- cnd_autostop_files,
- cnd_autostop_size,
- cnd_file_duration,
- cnd_file_interval))
+ if (!do_file_switch_or_stop(capture_opts))
continue;
} /* cnd_file_interval */
}
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop stopping ...");
if (use_threads) {
- pcap_queue_element *queue_element;
for (i = 0; i < global_ld.pcaps->len; i++) {
pcap_src = g_array_index(global_ld.pcaps, capture_src *, i);
pcap_src->interface_id);
}
while (1) {
- 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->u.phdr.caplen;
- pcap_queue_packets -= 1;
- }
- g_async_queue_unlock(pcap_queue);
- if (queue_element == NULL) {
+ gboolean dequeued = capture_loop_dequeue_packet();
+ if (!dequeued) {
break;
}
- 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);
global_ld.inpkts_to_sync_pipe += 1;
if (capture_opts->output_to_pipe) {
fflush(global_ld.pdh);
/* delete stop conditions */
- if (cnd_file_duration != NULL)
- cnd_delete(cnd_file_duration);
- if (cnd_file_interval != NULL)
- cnd_delete(cnd_file_interval);
- if (cnd_autostop_files != NULL)
- cnd_delete(cnd_autostop_files);
- if (cnd_autostop_size != NULL)
- cnd_delete(cnd_autostop_size);
- if (cnd_autostop_duration != NULL)
- cnd_delete(cnd_autostop_duration);
+ if (global_ld.file_duration_timer != NULL)
+ g_timer_destroy(global_ld.file_duration_timer);
+ if (autostop_duration_timer != NULL)
+ g_timer_destroy(autostop_duration_timer);
/* did we have a pcap (input) error? */
for (i = 0; i < capture_opts->ifaces->len; i++) {
report_capture_error(errmsg, please_report);
}
}
- report_packet_drops(received, pcap_dropped, pcap_src->dropped, pcap_src->flushed, stats->ps_ifdrop, interface_opts->console_display_name);
+ report_packet_drops(received, pcap_dropped, pcap_src->dropped, pcap_src->flushed, stats->ps_ifdrop, interface_opts->display_name);
}
/* close the input file (pcap or capture pipe) */
}
}
+/*
+ * We wrote one packet. Update some statistics and check if we've met any
+ * autostop or ring buffer conditions.
+ */
+static void
+capture_loop_wrote_one_packet(capture_src *pcap_src) {
+ global_ld.packets_captured++;
+ global_ld.packets_written++;
+ pcap_src->received++;
+
+ /* check -c NUM / -a packets:NUM */
+ if (global_capture_opts.has_autostop_packets && global_ld.packets_captured >= global_capture_opts.autostop_packets) {
+ fflush(global_ld.pdh);
+ global_ld.go = FALSE;
+ return;
+ }
+ /* check -b packets:NUM */
+ if (global_capture_opts.has_file_packets && global_ld.packets_written >= global_capture_opts.file_packets) {
+ do_file_switch_or_stop(&global_capture_opts);
+ return;
+ }
+ /* check -a filesize:NUM */
+ if (global_capture_opts.has_autostop_filesize &&
+ global_capture_opts.autostop_filesize > 0 &&
+ global_ld.bytes_written / 1000 >= global_capture_opts.autostop_filesize) {
+ /* Capture size limit reached, do we have another file? */
+ do_file_switch_or_stop(&global_capture_opts);
+ return;
+ }
+}
+
/* 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)
+capture_loop_write_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_header_s *bh, u_char *pd)
{
int err;
- if (!global_capture_opts.use_pcapng) {
- return;
- }
+ /*
+ * This should never be called if we're not writing pcapng.
+ */
+ g_assert(global_capture_opts.use_pcapng);
+
/* 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. */
return;
}
+ if (!pcapng_adjust_block(pcap_src, bh, pd)) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "%s failed to adjust pcapng block.", G_STRFUNC);
+ g_assert_not_reached();
+ 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) {
gboolean 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) {
+ } else if (bh->block_type == BLOCK_TYPE_EPB || bh->block_type == BLOCK_TYPE_SPB || bh->block_type == BLOCK_TYPE_SYSTEMD_JOURNAL) {
/* 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);
+ "Wrote a pcapng block type %u of length %d captured on interface %u.",
+ bh->block_type, bh->block_total_length, 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;
- }
+ capture_loop_wrote_one_packet(pcap_src);
}
}
}
-/* one packet was captured, process it */
+/* one pcap packet was captured, process it */
static void
capture_loop_write_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr,
const u_char *pd)
int err;
guint ts_mul = pcap_src->ts_nsec ? 1000000000 : 1000000;
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_write_packet_cb");
+
/* 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. */
} else {
#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.",
+ "Wrote a pcap 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;
- }
+ capture_loop_wrote_one_packet(pcap_src);
}
}
}
/* 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)
+capture_loop_queue_pcapng_cb(capture_src *pcap_src, const struct pcapng_block_header_s *bh, u_char *pd)
{
pcap_queue_element *queue_element;
gboolean limit_reached;
} 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);
+ "Queued a block of type 0x%08x of length %d captured on interface %u.",
+ 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
output may be wrong */
int
main(int argc, char *argv[])
{
- GString *comp_info_str;
- GString *runtime_info_str;
int opt;
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
cmdarg_err_init(dumpcap_cmdarg_err, dumpcap_cmdarg_err_cont);
- /* Get the compile-time version information string */
- comp_info_str = get_compiled_version_info(NULL, get_dumpcap_compiled_info);
-
- /* Get the run-time version information string */
- runtime_info_str = get_runtime_version_info(get_dumpcap_runtime_info);
-
- /* Add it to the information to be reported on a crash. */
- ws_add_crash_info("Dumpcap (Wireshark) %s\n"
- "\n"
- "%s"
- "\n"
- "%s",
- get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
- g_string_free(comp_info_str, TRUE);
- g_string_free(runtime_info_str, TRUE);
+ /* Initialize the version information. */
+ ws_init_version_info("Dumpcap (Wireshark)", NULL, get_dumpcap_compiled_info,
+ get_dumpcap_runtime_info);
#ifdef _WIN32
- arg_list_utf_16to8(argc, argv);
create_app_running_mutex();
/*
log_flags,
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.pcapng_passthrough = FALSE;
+ global_ld.saved_shb = NULL;
+ global_ld.saved_idbs = g_array_new(FALSE, TRUE, sizeof(saved_idb_t));
#ifdef _WIN32
/* Load wpcap if possible. Do this before collecting the run-time version information */
while ((opt = getopt_long(argc, argv, OPTSTRING, long_options, NULL)) != -1) {
switch (opt) {
case 'h': /* Print help and exit */
- printf("Dumpcap (Wireshark) %s\n"
- "Capture network packets and dump them into a pcapng or pcap file.\n"
- "See https://www.wireshark.org for more information.\n",
- get_ws_vcs_version_info());
+ show_help_header("Capture network packets and dump them into a pcapng or pcap file.");
print_usage(stdout);
exit_main(0);
break;
case 'v': /* Show version and exit */
- comp_info_str = get_compiled_version_info(NULL, get_dumpcap_compiled_info);
- runtime_info_str = get_runtime_version_info(get_dumpcap_runtime_info);
- show_version("Dumpcap (Wireshark)", comp_info_str, runtime_info_str);
- g_string_free(comp_info_str, TRUE);
- g_string_free(runtime_info_str, TRUE);
+ show_version();
exit_main(0);
break;
/*** capture option specific ***/
}
if (!global_capture_opts.has_autostop_filesize &&
!global_capture_opts.has_file_duration &&
- !global_capture_opts.has_file_interval) {
- cmdarg_err("Ring buffer requested, but no maximum capture file size, duration"
- "or interval were specified.");
+ !global_capture_opts.has_file_interval &&
+ !global_capture_opts.has_file_packets) {
+ cmdarg_err("Ring buffer requested, but no maximum capture file size, duration "
+ "interval, or packets were specified.");
#if 0
/* XXX - this must be redesigned as the conditions changed */
global_capture_opts.multi_files_on = FALSE;
g_string_append_printf(str, "and ");
}
}
- g_string_append_printf(str, "'%s'", interface_opts->console_display_name);
+ g_string_append_printf(str, "'%s'", interface_opts->display_name);
}
} else {
g_string_append_printf(str, "%u interfaces", global_capture_opts.ifaces->len);
return 0; /* never here, make compiler happy */
}
-
static void
console_log_handler(const char *log_domain, GLogLevelFlags log_level,
const char *message, gpointer user_data _U_)
static void
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;
if (capture_child) {
- g_snprintf(tmp, sizeof(tmp), "%u", packet_count);
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp);
- pipe_write_block(2, SP_PACKET_COUNT, tmp);
+ g_snprintf(count_str, sizeof(count_str), "%u", packet_count);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", count_str);
+ pipe_write_block(2, SP_PACKET_COUNT, count_str);
} else {
count += packet_count;
fprintf(stderr, "\rPackets: %u ", count);
static void
report_packet_drops(guint32 received, guint32 pcap_drops, guint32 drops, guint32 flushed, guint32 ps_ifdrop, gchar *name)
{
- char tmp[SP_DECISIZE+1+1];
guint32 total_drops = pcap_drops + drops + flushed;
- g_snprintf(tmp, sizeof(tmp), "%u", total_drops);
-
if (capture_child) {
+ char* tmp = g_strdup_printf("%u:%s", total_drops, name);
+
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
"Packets received/dropped on interface '%s': %u/%u (pcap:%u/dumpcap:%u/flushed:%u/ps_ifdrop:%u)",
name, received, total_drops, pcap_drops, drops, flushed, ps_ifdrop);
- /* XXX: Need to provide interface id, changes to consumers required. */
pipe_write_block(2, SP_DROPS, tmp);
+ g_free(tmp);
} else {
fprintf(stderr,
"Packets received/dropped on interface '%s': %u/%u (pcap:%u/dumpcap:%u/flushed:%u/ps_ifdrop:%u) (%.1f%%)\n",
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO,
"Signal pipe: Stop capture: %s", sig_pipe_name);
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "Signal pipe: %s (%p) result: %u avail: %u", sig_pipe_name,
+ "Signal pipe: %s (%p) result: %u avail: %lu", sig_pipe_name,
sig_pipe_handle, result, avail);
return FALSE;
} else {