summaryrefslogtreecommitdiffstats
path: root/capture/capture_sync.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-19 04:14:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-19 04:14:33 +0000
commit9f153fbfec0fb9c9ce38e749a7c6f4a5e115d4e9 (patch)
tree2784370cda9bbf2da9114d70f05399c0b229d28c /capture/capture_sync.c
parentAdding debian version 4.2.6-1. (diff)
downloadwireshark-9f153fbfec0fb9c9ce38e749a7c6f4a5e115d4e9.tar.xz
wireshark-9f153fbfec0fb9c9ce38e749a7c6f4a5e115d4e9.zip
Merging upstream version 4.4.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'capture/capture_sync.c')
-rw-r--r--capture/capture_sync.c805
1 files changed, 483 insertions, 322 deletions
diff --git a/capture/capture_sync.c b/capture/capture_sync.c
index 1af14187..2a5db8bc 100644
--- a/capture/capture_sync.c
+++ b/capture/capture_sync.c
@@ -21,6 +21,8 @@
#include <signal.h>
+#include <ws_exit_codes.h>
+
#include <wsutil/strtoi.h>
#include <wsutil/ws_assert.h>
@@ -101,6 +103,11 @@ static char *dummy_control_id;
static const char *sync_pipe_signame(int);
#endif
+/* We use this pipe buffer size for both the sync message pipe and the
+ * data pipe. Ensure that it's large enough for the indicator and header
+ * plus maximum message size.
+ */
+#define PIPE_BUF_SIZE (SP_MAX_MSG_LEN+4)
static gboolean sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session);
static int sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp);
@@ -108,15 +115,7 @@ static void pipe_convert_header(const unsigned char *header, int header_len, cha
static ssize_t pipe_read_block(GIOChannel *pipe_io, char *indicator, int len, char *msg,
char **err_msg);
-static void (*fetch_dumpcap_pid)(ws_process_id) = NULL;
-
-static void free_argv(char** argv, int argc)
-{
- int i;
- for (i = 0; i < argc; i++)
- g_free(argv[i]);
- g_free(argv);
-}
+static void (*fetch_dumpcap_pid)(ws_process_id);
void
capture_session_init(capture_session *cap_session, capture_file *cf,
@@ -156,7 +155,7 @@ void capture_process_finished(capture_session *cap_session)
unsigned i;
if (!extcap_session_stop(cap_session)) {
- /* Atleast one extcap process did not fully finish yet, wait for it */
+ /* At least one extcap process did not fully finish yet, wait for it */
return;
}
@@ -189,7 +188,7 @@ void capture_process_finished(capture_session *cap_session)
}
cap_session->closed(cap_session, message->str);
- g_string_free(message, true);
+ g_string_free(message, TRUE);
g_free(capture_opts->closed_msg);
capture_opts->closed_msg = NULL;
capture_opts->stop_after_extcaps = false;
@@ -197,6 +196,8 @@ void capture_process_finished(capture_session *cap_session)
/* Append an arg (realloc) to an argc/argv array */
/* (add a string pointer to a NULL-terminated array of string pointers) */
+/* XXX: For glib >= 2.68 we could use a GStrvBuilder.
+ */
static char **
sync_pipe_add_arg(char **args, int *argc, const char *arg)
{
@@ -219,6 +220,23 @@ sync_pipe_add_arg(char **args, int *argc, const char *arg)
return args;
}
+/* Take a buffer from an SP_LOG_MSG from dumpcap and send it to our
+ * current logger. Keep this in sync with the format used in
+ * dumpcap_log_writer. (We might want to do more proper serialization
+ * of more than just the log level.)
+ */
+static void
+sync_pipe_handle_log_msg(const char *buffer) {
+ const char *log_msg = NULL;
+ const char* end;
+ uint32_t level = 0;
+
+ if (ws_strtou32(buffer, &end, &level) && end[0] == ':') {
+ log_msg = end + 1;
+ }
+ ws_log(LOG_DOMAIN_CAPCHILD, level, "%s", log_msg);
+}
+
/* Initialize an argument list and add dumpcap to it. */
static char **
init_pipe_args(int *argc) {
@@ -240,6 +258,18 @@ init_pipe_args(int *argc) {
/* Make that the first argument in the argument list (argv[0]). */
argv = sync_pipe_add_arg(argv, argc, exename);
+ /* Tell dumpcap to log at the lowest level its domain (Capchild) is
+ * set to log in the main program. (It might be in the special noisy
+ * or debug filter, so we can't just check the overall level.)
+ */
+ for (enum ws_log_level level = LOG_LEVEL_NOISY; level != _LOG_LEVEL_LAST; level++) {
+ if (ws_log_msg_is_active(LOG_DOMAIN_CAPCHILD, level)) {
+ argv = sync_pipe_add_arg(argv, argc, "--log-level");
+ argv = sync_pipe_add_arg(argv, argc, ws_log_level_to_string(level));
+ break;
+ }
+ }
+
/* sync_pipe_add_arg strdupes exename, so we should free our copy */
g_free(exename);
@@ -269,17 +299,15 @@ pipe_io_cb(GIOChannel *pipe_io, GIOCondition condition _U_, void * user_data)
* On failure, *msg points to an error message for the failure, and -1 is
* returned, in which case *msg must be freed with g_free().
*/
-/* XXX - assumes PIPE_BUF_SIZE > SP_MAX_MSG_LEN */
#define ARGV_NUMBER_LEN 24
-#define PIPE_BUF_SIZE 5120
static int
#ifdef _WIN32
-sync_pipe_open_command(char* const argv[], int *data_read_fd,
+sync_pipe_open_command(char **argv, int *data_read_fd,
GIOChannel **message_read_io, int *signal_write_fd,
ws_process_id *fork_child, GArray *ifaces,
char **msg, void(*update_cb)(void))
#else
-sync_pipe_open_command(char* const argv[], int *data_read_fd,
+sync_pipe_open_command(char **argv, int *data_read_fd,
GIOChannel **message_read_io, int *signal_write_fd _U_,
ws_process_id *fork_child, GArray *ifaces _U_,
char **msg, void(*update_cb)(void))
@@ -287,6 +315,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
{
enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
int message_read_fd = -1;
+ char sync_id[ARGV_NUMBER_LEN];
#ifdef _WIN32
HANDLE sync_pipe[2]; /* pipe used to send messages from child to parent */
HANDLE data_pipe[2]; /* pipe used to send data from child to parent */
@@ -317,8 +346,9 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
if (!msg) {
/* We can't return anything */
+ g_strfreev(argv);
#ifdef _WIN32
- g_string_free(args, true);
+ g_string_free(args, TRUE);
#endif
return -1;
}
@@ -335,6 +365,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
/* Couldn't create the message pipe between parent and child. */
*msg = ws_strdup_printf("Couldn't create sync pipe: %s",
win32strerror(GetLastError()));
+ g_strfreev(argv);
return -1;
}
@@ -348,6 +379,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
if (message_read_fd == -1) {
*msg = ws_strdup_printf("Couldn't get C file handle for message read pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
CloseHandle(sync_pipe[PIPE_READ]);
CloseHandle(sync_pipe[PIPE_WRITE]);
return -1;
@@ -360,6 +392,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
/* Couldn't create the message pipe between parent and child. */
*msg = ws_strdup_printf("Couldn't create data pipe: %s",
win32strerror(GetLastError()));
+ g_strfreev(argv);
ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
CloseHandle(sync_pipe[PIPE_WRITE]);
return -1;
@@ -375,6 +408,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
*data_read_fd = _open_osfhandle( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
if (*data_read_fd == -1) {
*msg = ws_strdup_printf("Couldn't get C file handle for data read pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
CloseHandle(data_pipe[PIPE_READ]);
CloseHandle(data_pipe[PIPE_WRITE]);
ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
@@ -395,6 +429,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
/* Couldn't create the signal pipe between parent and child. */
*msg = ws_strdup_printf("Couldn't create signal pipe: %s",
win32strerror(GetLastError()));
+ g_strfreev(argv);
ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
CloseHandle(sync_pipe[PIPE_WRITE]);
return -1;
@@ -411,6 +446,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
if (signal_pipe_write_fd == -1) {
/* Couldn't create the pipe between parent and child. */
*msg = ws_strdup_printf("Couldn't get C file handle for sync pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
CloseHandle(sync_pipe[PIPE_WRITE]);
CloseHandle(signal_pipe);
@@ -436,7 +472,25 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
si.hStdInput = NULL; /* handle for named pipe*/
si.hStdOutput = data_pipe[PIPE_WRITE];
}
- si.hStdError = sync_pipe[PIPE_WRITE];
+ si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+ /* On Windows, "[a]n inherited handle refers to the same object in the child
+ * process as it does in the parent process. It also has the same value."
+ * https://learn.microsoft.com/en-us/windows/win32/procthread/inheritance
+ * When converted to a file descriptor (via _open_osfhandle), the fd
+ * value is not necessarily the same in the two processes, but the handle
+ * value can be shared.
+ * A HANDLE is a void* though "64-bit versions of Windows use 32-bit handles
+ * for interoperability... only the lower 32 bits are significant, so it is
+ * safe to truncate the handle... or sign-extend the handle"
+ * https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
+ * So it should be fine to call PtrToLong instead of casting to intptr_t.
+ * https://learn.microsoft.com/en-us/windows/win32/WinProg64/rules-for-using-pointers
+ */
+ int argc = g_strv_length(argv);
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+ snprintf(sync_id, ARGV_NUMBER_LEN, "%ld", PtrToLong(sync_pipe[PIPE_WRITE]));
+ argv = sync_pipe_add_arg(argv, &argc, sync_id);
#endif
if (ifaces) {
@@ -455,7 +509,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
if (si.hStdOutput && (si.hStdOutput != si.hStdInput)) {
handles[i_handles++] = si.hStdOutput;
}
- handles[i_handles++] = si.hStdError;
+ handles[i_handles++] = sync_pipe[PIPE_WRITE];
if (ifaces) {
for (j = 0; j < ifaces->len; j++) {
interface_opts = &g_array_index(ifaces, interface_options, j);
@@ -488,14 +542,16 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
}
ws_close(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
CloseHandle(sync_pipe[PIPE_WRITE]);
- g_string_free(args, true);
+ g_strfreev(argv);
+ g_string_free(args, TRUE);
g_free(handles);
return -1;
}
*fork_child = pi.hProcess;
/* We may need to store this and close it later */
CloseHandle(pi.hThread);
- g_string_free(args, true);
+ g_strfreev(argv);
+ g_string_free(args, TRUE);
g_free(handles);
if (signal_write_fd != NULL) {
@@ -506,6 +562,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
if (pipe(sync_pipe) < 0) {
/* Couldn't create the message pipe between parent and child. */
*msg = ws_strdup_printf("Couldn't create sync pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
return -1;
}
@@ -514,6 +571,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
if (pipe(data_pipe) < 0) {
/* Couldn't create the data pipe between parent and child. */
*msg = ws_strdup_printf("Couldn't create data pipe: %s", g_strerror(errno));
+ g_strfreev(argv);
ws_close(sync_pipe[PIPE_READ]);
ws_close(sync_pipe[PIPE_WRITE]);
return -1;
@@ -530,11 +588,16 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
ws_close(data_pipe[PIPE_READ]);
ws_close(data_pipe[PIPE_WRITE]);
}
- dup2(sync_pipe[PIPE_WRITE], 2);
ws_close(sync_pipe[PIPE_READ]);
- ws_close(sync_pipe[PIPE_WRITE]);
+ /* dumpcap should be running in capture child mode (hidden feature) */
+#ifndef DEBUG_CHILD
+ int argc = g_strv_length(argv);
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+ snprintf(sync_id, ARGV_NUMBER_LEN, "%d", sync_pipe[PIPE_WRITE]);
+ argv = sync_pipe_add_arg(argv, &argc, sync_id);
+#endif
execv(argv[0], argv);
- sync_pipe_write_int_msg(2, SP_EXEC_FAILED, errno);
+ sync_pipe_write_int_msg(sync_pipe[PIPE_WRITE], SP_EXEC_FAILED, errno);
/* Exit with "_exit()", so that we don't close the connection
to the X server (and cause stuff buffered up by our parent but
@@ -546,6 +609,8 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
_exit(1);
}
+ g_strfreev(argv);
+
if (fetch_dumpcap_pid && *fork_child > 0)
fetch_dumpcap_pid(*fork_child);
@@ -553,6 +618,7 @@ sync_pipe_open_command(char* const argv[], int *data_read_fd,
*data_read_fd = data_pipe[PIPE_READ];
}
message_read_fd = sync_pipe[PIPE_READ];
+
#endif
/* Parent process - read messages from the child process over the
@@ -643,10 +709,11 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
if (capture_opts->ifaces->len > 1)
argv = sync_pipe_add_arg(argv, &argc, "-t");
+ argv = sync_pipe_add_arg(argv, &argc, "-F");
if (capture_opts->use_pcapng)
- argv = sync_pipe_add_arg(argv, &argc, "-n");
+ argv = sync_pipe_add_arg(argv, &argc, "pcapng");
else
- argv = sync_pipe_add_arg(argv, &argc, "-P");
+ argv = sync_pipe_add_arg(argv, &argc, "pcap");
if (capture_comments != NULL) {
for (j = 0; j < capture_comments->len; j++) {
@@ -696,6 +763,13 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
}
+ if (capture_opts->print_file_names) {
+ char *print_name = g_strdup_printf("printname:%s", capture_opts->print_name_to);
+ argv = sync_pipe_add_arg(argv, &argc, "-b");
+ argv = sync_pipe_add_arg(argv, &argc, print_name);
+ g_free(print_name);
+ }
+
if (capture_opts->has_nametimenum) {
char nametimenum[ARGV_NUMBER_LEN];
argv = sync_pipe_add_arg(argv, &argc, "-b");
@@ -767,16 +841,18 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
/* Add a name for the interface, to put into an IDB. */
argv = sync_pipe_add_arg(argv, &argc, "--ifname");
argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
- if (interface_opts->descr != NULL)
- {
- /* Add a description for the interface, to put into an IDB. */
- argv = sync_pipe_add_arg(argv, &argc, "--ifdescr");
- argv = sync_pipe_add_arg(argv, &argc, interface_opts->descr);
- }
}
else
argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
+ if (interface_opts->descr != NULL)
+ {
+ /* Add a description for the interface to put into an IDB and
+ * use for the temporary filename. */
+ argv = sync_pipe_add_arg(argv, &argc, "--ifdescr");
+ argv = sync_pipe_add_arg(argv, &argc, interface_opts->descr);
+ }
+
if (interface_opts->cfilter != NULL && strlen(interface_opts->cfilter) != 0) {
argv = sync_pipe_add_arg(argv, &argc, "-f");
argv = sync_pipe_add_arg(argv, &argc, interface_opts->cfilter);
@@ -853,14 +929,12 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
}
}
- /* dumpcap should be running in capture child mode (hidden feature) */
#ifndef DEBUG_CHILD
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
#ifdef _WIN32
+ /* pass process id to dumpcap for named signal pipe */
+ argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
snprintf(control_id, ARGV_NUMBER_LEN, "%ld", GetCurrentProcessId());
argv = sync_pipe_add_arg(argv, &argc, control_id);
-#else
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
#endif
#endif
@@ -889,13 +963,11 @@ sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
if (ret == -1) {
report_failure("%s", msg);
g_free(msg);
- free_argv(argv, argc);
return false;
}
/* Parent process - read messages from the child process over the
sync pipe. */
- free_argv(argv, argc);
cap_session->fork_child_status = 0;
cap_session->cap_data_info = cap_data;
@@ -953,10 +1025,8 @@ sync_pipe_close_command(int *data_read_fd, GIOChannel *message_read_io,
* NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
* must be freed with g_free().
*/
-/* XXX - assumes PIPE_BUF_SIZE > SP_MAX_MSG_LEN */
-#define PIPE_BUF_SIZE 5120
static int
-sync_pipe_run_command_actual(char* const argv[], char **data, char **primary_msg,
+sync_pipe_run_command_actual(char **argv, char **data, char **primary_msg,
char **secondary_msg, void(*update_cb)(void))
{
char *msg;
@@ -964,7 +1034,7 @@ sync_pipe_run_command_actual(char* const argv[], char **data, char **primary_msg
GIOChannel *sync_pipe_read_io;
ws_process_id fork_child;
char *wait_msg;
- char buffer[PIPE_BUF_SIZE+1] = {0};
+ char *buffer = g_malloc(PIPE_BUF_SIZE + 1);
ssize_t nread;
char indicator;
int32_t exec_errno = 0;
@@ -982,6 +1052,7 @@ sync_pipe_run_command_actual(char* const argv[], char **data, char **primary_msg
*primary_msg = msg;
*secondary_msg = NULL;
*data = NULL;
+ g_free(buffer);
return -1;
}
@@ -990,177 +1061,190 @@ sync_pipe_run_command_actual(char* const argv[], char **data, char **primary_msg
*
* First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
*/
- nread = pipe_read_block(sync_pipe_read_io, &indicator, SP_MAX_MSG_LEN,
- buffer, primary_msg);
- if(nread <= 0) {
- /* We got a read error from the sync pipe, or we got no data at
- all from the sync pipe, so we're not going to be getting any
- data or error message from the child process. Pick up its
- exit status, and complain.
-
- We don't have to worry about killing the child, if the sync pipe
- returned an error. Usually this error is caused as the child killed
- itself while going down. Even in the rare cases that this isn't the
- case, the child will get an error when writing to the broken pipe
- the next time, cleaning itself up then. */
- ret = sync_pipe_wait_for_child(fork_child, &wait_msg);
- if(nread == 0) {
- /* We got an EOF from the sync pipe. That means that it exited
- before giving us any data to read. If ret is -1, we report
- that as a bad exit (e.g., exiting due to a signal); otherwise,
- we report it as a premature exit. */
- if (ret == -1)
- *primary_msg = wait_msg;
- else
- *primary_msg = g_strdup("Child dumpcap closed sync pipe prematurely");
- } else {
- /* We got an error from the sync pipe. If ret is -1, report
- both the sync pipe I/O error and the wait error. */
- if (ret == -1) {
- combined_msg = ws_strdup_printf("%s\n\n%s", *primary_msg, wait_msg);
- g_free(*primary_msg);
- g_free(wait_msg);
- *primary_msg = combined_msg;
+ do {
+ nread = pipe_read_block(sync_pipe_read_io, &indicator, SP_MAX_MSG_LEN,
+ buffer, primary_msg);
+ if(nread <= 0) {
+ /* We got a read error from the sync pipe, or we got no data at
+ all from the sync pipe, so we're not going to be getting any
+ data or error message from the child process. Pick up its
+ exit status, and complain.
+
+ We don't have to worry about killing the child, if the sync pipe
+ returned an error. Usually this error is caused as the child killed
+ itself while going down. Even in the rare cases that this isn't the
+ case, the child will get an error when writing to the broken pipe
+ the next time, cleaning itself up then. */
+ g_io_channel_unref(sync_pipe_read_io);
+ ret = sync_pipe_wait_for_child(fork_child, &wait_msg);
+ if(nread == 0) {
+ /* We got an EOF from the sync pipe. That means that it exited
+ before giving us any data to read. If ret is -1, we report
+ that as a bad exit (e.g., exiting due to a signal); otherwise,
+ we report it as a premature exit. */
+ if (ret == -1)
+ *primary_msg = wait_msg;
+ else
+ *primary_msg = g_strdup("Child dumpcap closed sync pipe prematurely");
+ } else {
+ /* We got an error from the sync pipe. If ret is -1, report
+ both the sync pipe I/O error and the wait error. */
+ if (ret == -1) {
+ combined_msg = ws_strdup_printf("%s\n\n%s", *primary_msg, wait_msg);
+ g_free(*primary_msg);
+ g_free(wait_msg);
+ *primary_msg = combined_msg;
+ }
}
- }
- *secondary_msg = NULL;
- *data = NULL;
-
- return -1;
- }
-
- /* we got a valid message block from the child, process it */
- switch(indicator) {
+ *secondary_msg = NULL;
+ *data = NULL;
+ g_free(buffer);
- case SP_EXEC_FAILED:
- /*
- * Exec of dumpcap failed. Get the errno for the failure.
- */
- if (!ws_strtoi32(buffer, NULL, &exec_errno)) {
- ws_warning("Invalid errno: %s", buffer);
+ return -1;
}
- /*
- * Pick up the child status.
- */
- ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
- &fork_child, &msg);
- if (ret == -1) {
- /*
- * Child process failed unexpectedly, or wait failed; msg is the
- * error message.
- */
- *primary_msg = msg;
- *secondary_msg = NULL;
- } else {
+ /* we got a valid message block from the child, process it */
+ switch(indicator) {
+
+ case SP_EXEC_FAILED:
/*
- * Child process failed, but returned the expected exit status.
- * Return the messages it gave us, and indicate failure.
+ * Exec of dumpcap failed. Get the errno for the failure.
*/
- *primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",
- g_strerror(exec_errno));
- *secondary_msg = NULL;
- ret = -1;
- }
- *data = NULL;
- break;
-
- case SP_ERROR_MSG:
- /*
- * Error from dumpcap; there will be a primary message and a
- * secondary message.
- */
-
- /* convert primary message */
- pipe_convert_header((unsigned char*)buffer, 4, &indicator, &primary_msg_len);
- primary_msg_text = buffer+4;
- /* convert secondary message */
- pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, 4, &indicator,
- &secondary_msg_len);
- secondary_msg_text = primary_msg_text + primary_msg_len + 4;
- /* the capture child will close the sync_pipe, nothing to do */
+ if (!ws_strtoi32(buffer, NULL, &exec_errno)) {
+ ws_warning("Invalid errno: %s", buffer);
+ }
- /*
- * Pick up the child status.
- */
- ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
- &fork_child, &msg);
- if (ret == -1) {
/*
- * Child process failed unexpectedly, or wait failed; msg is the
- * error message.
+ * Pick up the child status.
*/
- *primary_msg = msg;
- *secondary_msg = NULL;
- } else {
+ ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
+ &fork_child, &msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ } else {
+ /*
+ * Child process failed, but returned the expected exit status.
+ * Return the messages it gave us, and indicate failure.
+ */
+ *primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",
+ g_strerror(exec_errno));
+ *secondary_msg = NULL;
+ ret = -1;
+ }
+ *data = NULL;
+ break;
+
+ case SP_ERROR_MSG:
/*
- * Child process failed, but returned the expected exit status.
- * Return the messages it gave us, and indicate failure.
+ * Error from dumpcap; there will be a primary message and a
+ * secondary message.
*/
- *primary_msg = g_strdup(primary_msg_text);
- *secondary_msg = g_strdup(secondary_msg_text);
- ret = -1;
- }
- *data = NULL;
- break;
- case SP_SUCCESS:
- /* read the output from the command */
- data_buf = g_string_new("");
- while ((count = ws_read(data_pipe_read_fd, buffer, PIPE_BUF_SIZE)) > 0) {
- buffer[count] = '\0';
- g_string_append(data_buf, buffer);
- }
+ /* convert primary message */
+ pipe_convert_header((unsigned char*)buffer, 4, &indicator, &primary_msg_len);
+ primary_msg_text = buffer+4;
+ /* convert secondary message */
+ pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, 4, &indicator,
+ &secondary_msg_len);
+ secondary_msg_text = primary_msg_text + primary_msg_len + 4;
+ /* the capture child will close the sync_pipe, nothing to do */
- /*
- * Pick up the child status.
- */
- ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
- &fork_child, &msg);
- if (ret == -1) {
/*
- * Child process failed unexpectedly, or wait failed; msg is the
- * error message.
+ * Pick up the child status.
*/
- *primary_msg = msg;
- *secondary_msg = NULL;
- g_string_free(data_buf, true);
+ ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
+ &fork_child, &msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ } else {
+ /*
+ * Child process failed, but returned the expected exit status.
+ * Return the messages it gave us, and indicate failure.
+ */
+ *primary_msg = g_strdup(primary_msg_text);
+ *secondary_msg = g_strdup(secondary_msg_text);
+ ret = -1;
+ }
*data = NULL;
- } else {
+ break;
+
+ case SP_LOG_MSG:
/*
- * Child process succeeded.
+ * Log from dumpcap; pass to our log
*/
- *primary_msg = NULL;
- *secondary_msg = NULL;
- *data = g_string_free(data_buf, false);
- }
- break;
+ sync_pipe_handle_log_msg(buffer);
+ break;
+
+ case SP_SUCCESS:
+ /* read the output from the command */
+ data_buf = g_string_new("");
+ while ((count = ws_read(data_pipe_read_fd, buffer, PIPE_BUF_SIZE)) > 0) {
+ buffer[count] = '\0';
+ g_string_append(data_buf, buffer);
+ }
- default:
- /*
- * Pick up the child status.
- */
- ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
- &fork_child, &msg);
- if (ret == -1) {
/*
- * Child process failed unexpectedly, or wait failed; msg is the
- * error message.
+ * Pick up the child status.
*/
- *primary_msg = msg;
- *secondary_msg = NULL;
- } else {
+ ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
+ &fork_child, &msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ g_string_free(data_buf, TRUE);
+ *data = NULL;
+ } else {
+ /*
+ * Child process succeeded.
+ */
+ *primary_msg = NULL;
+ *secondary_msg = NULL;
+ *data = g_string_free(data_buf, FALSE);
+ }
+ break;
+
+ default:
/*
- * Child process returned an unknown status.
+ * Pick up the child status.
*/
- *primary_msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
- indicator);
- *secondary_msg = NULL;
- ret = -1;
+ ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
+ &fork_child, &msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ } else {
+ /*
+ * Child process returned an unknown status.
+ */
+ *primary_msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
+ indicator);
+ *secondary_msg = NULL;
+ ret = -1;
+ }
+ *data = NULL;
+ break;
}
- *data = NULL;
- break;
- }
+ } while (indicator != SP_SUCCESS && ret != -1);
+
+ g_free(buffer);
return ret;
}
@@ -1168,7 +1252,7 @@ sync_pipe_run_command_actual(char* const argv[], char **data, char **primary_msg
* redirects to sync_pipe_run_command_actual()
*/
static int
-sync_pipe_run_command(char* const argv[], char **data, char **primary_msg,
+sync_pipe_run_command(char **argv, char **data, char **primary_msg,
char **secondary_msg, void (*update_cb)(void))
{
int ret, i;
@@ -1233,22 +1317,14 @@ sync_interface_set_80211_chan(const char *iface, const char *freq, const char *t
*primary_msg = g_strdup("Out of mem.");
*secondary_msg = NULL;
*data = NULL;
- free_argv(argv, argc);
return -1;
}
argv = sync_pipe_add_arg(argv, &argc, "-k");
argv = sync_pipe_add_arg(argv, &argc, opt);
-#ifndef DEBUG_CHILD
- /* Run dumpcap in capture child mode */
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
-#endif
-
ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
g_free(opt);
- free_argv(argv, argc);
return ret;
}
@@ -1286,13 +1362,7 @@ sync_interface_list_open(char **data, char **primary_msg,
/* Ask for the interface list */
argv = sync_pipe_add_arg(argv, &argc, "-D");
-#ifndef DEBUG_CHILD
- /* Run dumpcap in capture child mode */
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
-#endif
ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
- free_argv(argv, argc);
return ret;
}
@@ -1340,13 +1410,51 @@ sync_if_capabilities_open(const char *ifname, bool monitor_mode, const char* aut
argv = sync_pipe_add_arg(argv, &argc, auth);
}
-#ifndef DEBUG_CHILD
- /* Run dumpcap in capture child mode */
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
-#endif
ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
- free_argv(argv, argc);
+ return ret;
+}
+
+int
+sync_if_list_capabilities_open(GList *if_queries,
+ char **data, char **primary_msg,
+ char **secondary_msg, void (*update_cb)(void))
+{
+ int argc;
+ char **argv;
+ int ret;
+ if_cap_query_t *if_cap_query;
+
+ ws_debug("sync_if_list_capabilities_open");
+
+ argv = init_pipe_args(&argc);
+
+ if (!argv) {
+ *primary_msg = g_strdup("We don't know where to find dumpcap.");
+ *secondary_msg = NULL;
+ *data = NULL;
+ return -1;
+ }
+
+ for (GList *li = if_queries; li != NULL; li = g_list_next(li)) {
+ if_cap_query = (if_cap_query_t*)li->data;
+ /* Ask for the interface capabilities */
+ argv = sync_pipe_add_arg(argv, &argc, "-i");
+ argv = sync_pipe_add_arg(argv, &argc, if_cap_query->name);
+ if (if_cap_query->monitor_mode)
+ argv = sync_pipe_add_arg(argv, &argc, "-I");
+ if (if_cap_query->auth_username && if_cap_query->auth_password) {
+ char sauth[256];
+ argv = sync_pipe_add_arg(argv, &argc, "-A");
+ snprintf(sauth, sizeof(sauth), "%s:%s",
+ if_cap_query->auth_username,
+ if_cap_query->auth_password);
+ argv = sync_pipe_add_arg(argv, &argc, sauth);
+ }
+ }
+ argv = sync_pipe_add_arg(argv, &argc, "-L");
+ argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
+
+ ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
return ret;
}
@@ -1355,16 +1463,18 @@ sync_if_capabilities_open(const char *ifname, bool monitor_mode, const char* aut
* contains the file descriptor for the pipe's stdout, *msg is unchanged,
* and zero is returned. On failure, *msg will point to an error message
* that must be g_free()d, and -1 will be returned.
+ * If data is not NULL, then it will also be set to point to a JSON
+ * serialization of the list of local interfaces and their capabilities.
*/
int
-sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, char **msg, void (*update_cb)(void))
+sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, char **data, char **msg, void (*update_cb)(void))
{
int argc;
char **argv;
int ret;
GIOChannel *message_read_io;
char *wait_msg;
- char buffer[PIPE_BUF_SIZE+1] = {0};
+ char *buffer = g_malloc(PIPE_BUF_SIZE + 1);
ssize_t nread;
char indicator;
int32_t exec_errno = 0;
@@ -1380,28 +1490,34 @@ sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, char **m
if (!argv) {
*msg = g_strdup("We don't know where to find dumpcap.");
+ g_free(buffer);
return -1;
}
/* Ask for the interface statistics */
argv = sync_pipe_add_arg(argv, &argc, "-S");
+ /* If requested, ask for the interface list and capabilities. */
+ if (data) {
+ argv = sync_pipe_add_arg(argv, &argc, "-D");
+ argv = sync_pipe_add_arg(argv, &argc, "-L");
+ }
+
#ifndef DEBUG_CHILD
- argv = sync_pipe_add_arg(argv, &argc, "-Z");
#ifdef _WIN32
+ argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
ret = create_dummy_signal_pipe(msg);
if (ret == -1) {
+ g_free(buffer);
return -1;
}
argv = sync_pipe_add_arg(argv, &argc, dummy_control_id);
-#else
- argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
#endif
#endif
ret = sync_pipe_open_command(argv, data_read_fd, &message_read_io, NULL,
fork_child, NULL, msg, update_cb);
- free_argv(argv, argc);
if (ret == -1) {
+ g_free(buffer);
return -1;
}
@@ -1410,126 +1526,163 @@ sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, char **m
*
* First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
*/
- nread = pipe_read_block(message_read_io, &indicator, SP_MAX_MSG_LEN,
- buffer, msg);
- if(nread <= 0) {
- /* We got a read error from the sync pipe, or we got no data at
- all from the sync pipe, so we're not going to be getting any
- data or error message from the child process. Pick up its
- exit status, and complain.
-
- We don't have to worry about killing the child, if the sync pipe
- returned an error. Usually this error is caused as the child killed
- itself while going down. Even in the rare cases that this isn't the
- case, the child will get an error when writing to the broken pipe
- the next time, cleaning itself up then. */
- ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
- g_io_channel_unref(message_read_io);
- ws_close(*data_read_fd);
- if(nread == 0) {
- /* We got an EOF from the sync pipe. That means that it exited
- before giving us any data to read. If ret is -1, we report
- that as a bad exit (e.g., exiting due to a signal); otherwise,
- we report it as a premature exit. */
- if (ret == -1)
- *msg = wait_msg;
- else
- *msg = g_strdup("Child dumpcap closed sync pipe prematurely");
- } else {
- /* We got an error from the sync pipe. If ret is -1, report
- both the sync pipe I/O error and the wait error. */
- if (ret == -1) {
- combined_msg = ws_strdup_printf("%s\n\n%s", *msg, wait_msg);
- g_free(*msg);
- g_free(wait_msg);
- *msg = combined_msg;
+ do {
+ nread = pipe_read_block(message_read_io, &indicator, SP_MAX_MSG_LEN,
+ buffer, msg);
+ if(nread <= 0) {
+ /* We got a read error from the sync pipe, or we got no data at
+ all from the sync pipe, so we're not going to be getting any
+ data or error message from the child process. Pick up its
+ exit status, and complain.
+
+ We don't have to worry about killing the child, if the sync pipe
+ returned an error. Usually this error is caused as the child killed
+ itself while going down. Even in the rare cases that this isn't the
+ case, the child will get an error when writing to the broken pipe
+ the next time, cleaning itself up then. */
+ g_io_channel_unref(message_read_io);
+ ws_close(*data_read_fd);
+ ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
+ if(nread == 0) {
+ /* We got an EOF from the sync pipe. That means that it exited
+ before giving us any data to read. If ret is -1, we report
+ that as a bad exit (e.g., exiting due to a signal); otherwise,
+ we report it as a premature exit. */
+ if (ret == -1)
+ *msg = wait_msg;
+ else
+ *msg = g_strdup("Child dumpcap closed sync pipe prematurely");
+ } else {
+ /* We got an error from the sync pipe. If ret is -1, report
+ both the sync pipe I/O error and the wait error. */
+ if (ret == -1) {
+ combined_msg = ws_strdup_printf("%s\n\n%s", *msg, wait_msg);
+ g_free(*msg);
+ g_free(wait_msg);
+ *msg = combined_msg;
+ }
}
+ g_free(buffer);
+ return -1;
}
- return -1;
- }
- /* we got a valid message block from the child, process it */
- switch(indicator) {
+ /* we got a valid message block from the child, process it */
+ switch(indicator) {
- case SP_EXEC_FAILED:
- /*
- * Exec of dumpcap failed. Get the errno for the failure.
- */
- if (!ws_strtoi32(buffer, NULL, &exec_errno)) {
- ws_warning("Invalid errno: %s", buffer);
- }
- *msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",
- g_strerror(exec_errno));
+ case SP_EXEC_FAILED:
+ /*
+ * Exec of dumpcap failed. Get the errno for the failure.
+ */
+ if (!ws_strtoi32(buffer, NULL, &exec_errno)) {
+ ws_warning("Invalid errno: %s", buffer);
+ }
+ *msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",
+ g_strerror(exec_errno));
- /*
- * Pick up the child status.
- */
- sync_pipe_close_command(data_read_fd, message_read_io,
- fork_child, msg);
- ret = -1;
- break;
+ /*
+ * Pick up the child status.
+ */
+ char *close_msg = NULL;
+ sync_pipe_close_command(data_read_fd, message_read_io,
+ fork_child, &close_msg);
+ /*
+ * Ignore the error from sync_pipe_close_command, presumably the one
+ * returned by the child is more pertinent to what went wrong.
+ */
+ g_free(close_msg);
+ ret = -1;
+ break;
- case SP_ERROR_MSG:
- /*
- * Error from dumpcap; there will be a primary message and a
- * secondary message.
- */
+ case SP_ERROR_MSG:
+ /*
+ * Error from dumpcap; there will be a primary message and a
+ * secondary message.
+ */
- /* convert primary message */
- pipe_convert_header((unsigned char*)buffer, 4, &indicator, &primary_msg_len);
- primary_msg_text = buffer+4;
- /* convert secondary message */
- pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, 4, &indicator,
- &secondary_msg_len);
- /*secondary_msg_text = primary_msg_text + primary_msg_len + 4;*/
- /* the capture child will close the sync_pipe, nothing to do */
+ /* convert primary message */
+ pipe_convert_header((unsigned char*)buffer, 4, &indicator, &primary_msg_len);
+ primary_msg_text = buffer+4;
+ /* convert secondary message */
+ pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, 4, &indicator,
+ &secondary_msg_len);
+ /*secondary_msg_text = primary_msg_text + primary_msg_len + 4;*/
+ /* the capture child will close the sync_pipe, nothing to do */
- /*
- * Pick up the child status.
- */
- ret = sync_pipe_close_command(data_read_fd, message_read_io,
- fork_child, msg);
- if (ret == -1) {
/*
- * Child process failed unexpectedly, or wait failed; msg is the
- * error message.
+ * Pick up the child status.
*/
- } else {
+ ret = sync_pipe_close_command(data_read_fd, message_read_io,
+ fork_child, msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ } else if (ret == WS_EXIT_NO_INTERFACES) {
+ /*
+ * No interfaces were found. If that's not the
+ * result of an error when fetching the local
+ * interfaces, let the user know.
+ */
+ *msg = g_strdup(primary_msg_text);
+ } else {
+ /*
+ * Child process failed, but returned the expected exit status.
+ * Return the messages it gave us, and indicate failure.
+ */
+ *msg = g_strdup(primary_msg_text);
+ ret = -1;
+ }
+ g_free(buffer);
+ return ret;
+
+ case SP_LOG_MSG:
/*
- * Child process failed, but returned the expected exit status.
- * Return the messages it gave us, and indicate failure.
+ * Log from dumpcap; pass to our log
*/
- *msg = g_strdup(primary_msg_text);
- ret = -1;
- }
- break;
-
- case SP_SUCCESS:
- /* Close the message pipe. */
- g_io_channel_unref(message_read_io);
- break;
+ sync_pipe_handle_log_msg(buffer);
+ break;
- default:
- /*
- * Pick up the child status.
- */
- ret = sync_pipe_close_command(data_read_fd, message_read_io,
- fork_child, msg);
- if (ret == -1) {
+ case SP_IFACE_LIST:
/*
- * Child process failed unexpectedly, or wait failed; msg is the
- * error message.
+ * Dumpcap giving us the interface list
*/
- } else {
+
+ /* convert primary message */
+ if (data) {
+ *data = g_strdup(buffer);
+ }
+ break;
+
+ case SP_SUCCESS:
+ /* Close the message pipe. */
+ g_io_channel_unref(message_read_io);
+ break;
+
+ default:
/*
- * Child process returned an unknown status.
+ * Pick up the child status.
*/
- *msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
- indicator);
- ret = -1;
+ ret = sync_pipe_close_command(data_read_fd, message_read_io,
+ fork_child, msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ } else {
+ /*
+ * Child process returned an unknown status.
+ */
+ *msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
+ indicator);
+ ret = -1;
+ }
+ break;
}
- break;
- }
+ } while (indicator != SP_SUCCESS && ret != -1);
+
+ g_free(buffer);
return ret;
}
@@ -1680,14 +1833,13 @@ pipe_read_block(GIOChannel *pipe_io, char *indicator, int len, char *msg,
header[0], header[1], header[2], header[3]);
/* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */
- memcpy(msg, header, sizeof(header));
- g_io_channel_read_chars(pipe_io, &msg[sizeof(header)], len-sizeof(header), &bytes_read, &err);
+ g_io_channel_read_chars(pipe_io, msg, len, &bytes_read, &err);
if (err != NULL) { /* error */
ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message);
g_clear_error(&err);
}
- *err_msg = ws_strdup_printf("Unknown message from dumpcap reading header, try to show it as a string: %s",
- msg);
+ *err_msg = ws_strdup_printf("Message %c from dumpcap with length %d > buffer size %d! Partial message: %s",
+ *indicator, required, len, msg);
return -1;
}
len = required;
@@ -1716,7 +1868,7 @@ static gboolean
sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
{
int ret;
- char buffer[SP_MAX_MSG_LEN+1] = {0};
+ char *buffer = g_malloc(SP_MAX_MSG_LEN + 1);
ssize_t nread;
char indicator;
int32_t exec_errno = 0;
@@ -1775,6 +1927,7 @@ sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
} else {
extcap_request_stop(cap_session);
}
+ g_free(buffer);
return false;
}
@@ -1801,6 +1954,7 @@ sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
"standard output", as the capture file. */
sync_pipe_stop(cap_session);
cap_session->closed(cap_session, NULL);
+ g_free(buffer);
return false;
}
break;
@@ -1837,6 +1991,12 @@ sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
/* the capture child will close the sync_pipe, nothing to do for now */
/* (an error message doesn't mean we have to stop capturing) */
break;
+ case SP_LOG_MSG:
+ /*
+ * Log from dumpcap; pass to our log
+ */
+ sync_pipe_handle_log_msg(buffer);
+ break;
case SP_BAD_FILTER: {
const char *message=NULL;
uint32_t indx = 0;
@@ -1870,6 +2030,7 @@ sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
break;
}
+ g_free(buffer);
return true;
}