Bug Summary

File:builds/wireshark/wireshark/capture/capture_sync.c
Warning:line 1617, column 9
Potential leak of memory pointed to by 'argv'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name capture_sync.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-04-23-100342-3640-1 -x c /builds/wireshark/wireshark/capture/capture_sync.c
1/* capture_sync.c
2 * Synchronisation between Wireshark capture parent and child instances
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <[email protected]>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11#include "config.h"
12#define WS_LOG_DOMAIN"Capture" LOG_DOMAIN_CAPTURE"Capture"
13
14#include <wireshark.h>
15
16#ifdef HAVE_LIBPCAP1
17
18#include <glib.h>
19#include <stdio.h>
20#include <stdlib.h>
21
22#include <signal.h>
23
24#include <ws_exit_codes.h>
25
26#include <wsutil/strtoi.h>
27#include <wsutil/ws_assert.h>
28#include <wsutil/pint.h>
29
30#ifdef _WIN32
31#include <wsutil/unicode-utils.h>
32#include <wsutil/win32-utils.h>
33#include <wsutil/ws_pipe.h>
34#else
35#include <glib-unix1.h>
36#endif
37
38#ifdef HAVE_SYS_WAIT_H1
39# include <sys/wait.h>
40#endif
41
42#include "capture/capture-pcap-util.h"
43
44#ifndef _WIN32
45/*
46 * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
47 * macros) on UNIX systems that don't have them.
48 */
49#ifndef WIFEXITED
50# define WIFEXITED(status)(((status) & 0x7f) == 0) (((status) & 0177) == 0)
51#endif
52#ifndef WIFSTOPPED
53# define WIFSTOPPED(status)(((status) & 0xff) == 0x7f) (((status) & 0177) == 0177)
54#endif
55#ifndef WIFSIGNALED
56# define WIFSIGNALED(status)(((signed char) (((status) & 0x7f) + 1) >> 1) > 0
)
(!WIFSTOPPED(status)(((status) & 0xff) == 0x7f) && !WIFEXITED(status)(((status) & 0x7f) == 0))
57#endif
58#ifndef WEXITSTATUS
59# define WEXITSTATUS(status)(((status) & 0xff00) >> 8) ((status) >> 8)
60#endif
61#ifndef WTERMSIG
62# define WTERMSIG(status)((status) & 0x7f) ((status) & 0177)
63#endif
64#ifndef WCOREDUMP
65# define WCOREDUMP(status)((status) & 0x80) ((status) & 0200)
66#endif
67#ifndef WSTOPSIG
68# define WSTOPSIG(status)(((status) & 0xff00) >> 8) ((status) >> 8)
69#endif
70#endif /* _WIN32 */
71
72#include <epan/packet.h>
73#include <epan/prefs.h>
74
75#include "file.h"
76
77#include "ui/capture.h"
78#include <capture/capture_sync.h>
79#include <capture/sync_pipe.h>
80
81#ifdef _WIN32
82#include "capture/capture-wpcap.h"
83#endif
84
85#include "ui/ws_ui_util.h"
86
87#include <wsutil/filesystem.h>
88#include <wsutil/file_util.h>
89#include <wsutil/report_message.h>
90#include "extcap.h"
91
92#ifdef _WIN32
93#include <process.h> /* For spawning child process */
94#endif
95
96#include <wsutil/ws_pipe.h>
97
98#ifdef _WIN32
99static int create_dummy_signal_pipe(char **msg);
100static HANDLE dummy_signal_pipe; /* Dummy named pipe which lets the child check for a dropped connection */
101static char *dummy_control_id;
102#else
103static const char *sync_pipe_signame(int);
104#endif
105
106/* We use this pipe buffer size for both the sync message pipe and the
107 * data pipe. Ensure that it's large enough for the indicator and header
108 * plus maximum message size.
109 */
110#define PIPE_BUF_SIZE((512 * 1000)+4) (SP_MAX_MSG_LEN(512 * 1000)+4)
111
112static gboolean sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session);
113static int sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp);
114static void pipe_convert_header(const unsigned char *header, char *indicator, unsigned *block_len);
115static ssize_t pipe_read_block(GIOChannel *pipe_io, char *indicator, unsigned len, char *msg,
116 char **err_msg);
117
118static void (*fetch_dumpcap_pid)(ws_process_id);
119
120void
121capture_session_init(capture_session *cap_session, capture_file *cf,
122 new_file_fn new_file, new_packets_fn new_packets,
123 drops_fn drops, error_fn error,
124 cfilter_error_fn cfilter_error, closed_fn closed)
125{
126 cap_session->cf = cf;
127 cap_session->fork_child = WS_INVALID_PID-1; /* invalid process handle */
128 cap_session->pipe_input_id = 0;
129#ifdef _WIN32
130 cap_session->signal_pipe_write_fd = -1;
131#endif
132 cap_session->state = CAPTURE_STOPPED;
133#ifndef _WIN32
134 cap_session->owner = getuid();
135 cap_session->group = getgid();
136#endif
137 cap_session->count = 0;
138 cap_session->count_pending = 0;
139 cap_session->session_will_restart = false0;
140
141 cap_session->new_file = new_file;
142 cap_session->new_packets = new_packets;
143 cap_session->drops = drops;
144 cap_session->error = error;
145 cap_session->cfilter_error = cfilter_error;
146 cap_session->closed = closed;
147 cap_session->frame_cksum = NULL((void*)0);
148}
149
150void capture_process_finished(capture_session *cap_session)
151{
152 capture_options *capture_opts = cap_session->capture_opts;
153 interface_options *interface_opts;
154 GString *message;
155 unsigned i;
156
157 if (!extcap_session_stop(cap_session)) {
158 /* At least one extcap process did not fully finish yet, wait for it */
159 return;
160 }
161
162 if (cap_session->fork_child != WS_INVALID_PID-1) {
163 if (capture_opts->stop_after_extcaps) {
164 /* User has requested capture stop and all extcaps are gone now */
165 capture_opts->stop_after_extcaps = false0;
166 sync_pipe_stop(cap_session);
167 }
168 /* Wait for child process to end, session is not closed yet */
169 return;
170 }
171
172 /* Construct message and close session */
173 message = g_string_new(capture_opts->closed_msg);
174 for (i = 0; i < capture_opts->ifaces->len; i++) {
175 interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i)(((interface_options*) (void *) (capture_opts->ifaces)->
data) [(i)])
;
176 if (interface_opts->if_type != IF_EXTCAP) {
177 continue;
178 }
179
180 if ((interface_opts->extcap_stderr != NULL((void*)0)) &&
181 (interface_opts->extcap_stderr->len > 0)) {
182 if (message->len > 0) {
183 g_string_append(message, "\n")(__builtin_constant_p ("\n") ? __extension__ ({ const char * const
__val = ("\n"); g_string_append_len_inline (message, __val, (
__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val)))
: (gssize) -1); }) : g_string_append_len_inline (message, "\n"
, (gssize) -1))
;
184 }
185 g_string_append(message, "Error from extcap pipe: ")(__builtin_constant_p ("Error from extcap pipe: ") ? __extension__
({ const char * const __val = ("Error from extcap pipe: "); g_string_append_len_inline
(message, __val, (__val != ((void*)0)) ? (gssize) strlen (((
__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(message, "Error from extcap pipe: ", (gssize) -1))
;
186 g_string_append(message, interface_opts->extcap_stderr->str)(__builtin_constant_p (interface_opts->extcap_stderr->str
) ? __extension__ ({ const char * const __val = (interface_opts
->extcap_stderr->str); g_string_append_len_inline (message
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (message
, interface_opts->extcap_stderr->str, (gssize) -1))
;
187 }
188 }
189
190 cap_session->closed(cap_session, message->str);
191 g_string_free(message, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(message), ((!(0)))) : g_string_free_and_steal (message)) : (
g_string_free) ((message), ((!(0)))))
;
192 g_free(capture_opts->closed_msg);
193 capture_opts->closed_msg = NULL((void*)0);
194 capture_opts->stop_after_extcaps = false0;
195}
196
197/* Append an arg (realloc) to an argc/argv array */
198/* (add a string pointer to a NULL-terminated array of string pointers) */
199/* XXX: For glib >= 2.68 we could use a GStrvBuilder.
200 */
201static char **
202sync_pipe_add_arg(char **args, int *argc, const char *arg)
203{
204 /* Grow the array; "*argc" currently contains the number of string
205 pointers, *not* counting the NULL pointer at the end, so we have
206 to add 2 in order to get the new size of the array, including the
207 new pointer and the terminating NULL pointer. */
208 args = (char **)g_realloc( (void *) args, (*argc + 2) * sizeof (char *));
8
Memory is allocated
209
210 /* Stuff the pointer into the penultimate element of the array, which
211 is the one at the index specified by "*argc". */
212 args[*argc] = g_strdup(arg)g_strdup_inline (arg);
213 /* Now bump the count. */
214 (*argc)++;
215
216 /* We overwrite the NULL pointer; put it back right after the
217 element we added. */
218 args[*argc] = NULL((void*)0);
219
220 return args;
221}
222
223/* Take a buffer from an SP_LOG_MSG from dumpcap and send it to our
224 * current logger. Keep this in sync with the format used in
225 * dumpcap_log_writer. (We might want to do more proper serialization
226 * of more than just the log level.)
227 */
228static void
229sync_pipe_handle_log_msg(const char *buffer) {
230 const char *log_msg = NULL((void*)0);
231 const char* end;
232 uint32_t level = 0;
233
234 if (ws_strtou32(buffer, &end, &level) && end[0] == ':') {
235 log_msg = end + 1;
236 }
237 ws_log(LOG_DOMAIN_CAPCHILD"Capchild", level, "%s", log_msg);
238}
239
240/* Initialize an argument list and add dumpcap to it. */
241static char **
242init_pipe_args(const char* app_name, int *argc) {
243 char *exename;
244 char **argv;
245
246 /* Find the absolute path of the dumpcap executable. */
247 exename = get_executable_path("dumpcap");
248 if (exename == NULL((void*)0)) {
249 return NULL((void*)0);
250 }
251
252 /* Allocate the string pointer array with enough space for the
253 terminating NULL pointer. */
254 *argc = 0;
255 argv = (char **)g_malloc(sizeof (char *));
256 *argv = NULL((void*)0);
257
258 /* Make that the first argument in the argument list (argv[0]). */
259 argv = sync_pipe_add_arg(argv, argc, exename);
260
261 /* Tell dumpcap to log at the lowest level its domain (Capchild) is
262 * set to log in the main program. (It might be in the special noisy
263 * or debug filter, so we can't just check the overall level.)
264 */
265 for (enum ws_log_level level = LOG_LEVEL_NOISY; level != _LOG_LEVEL_LAST; level++) {
266 if (ws_log_msg_is_active(LOG_DOMAIN_CAPCHILD"Capchild", level)) {
267 argv = sync_pipe_add_arg(argv, argc, "--log-level");
268 argv = sync_pipe_add_arg(argv, argc, ws_log_level_to_string(level));
269 break;
270 }
271 }
272
273 argv = sync_pipe_add_arg(argv, argc, "--application-flavor");
274 argv = sync_pipe_add_arg(argv, argc, app_name);
275
276 /* sync_pipe_add_arg strdupes exename, so we should free our copy */
277 g_free(exename);
278
279 return argv;
280}
281
282static gboolean
283pipe_io_cb(GIOChannel *pipe_io, GIOCondition condition _U___attribute__((unused)), void * user_data)
284{
285 capture_session *cap_session = (capture_session *)user_data;
286 if (!sync_pipe_input_cb(pipe_io, cap_session)) {
287 cap_session->pipe_input_id = 0;
288 return G_SOURCE_REMOVE(0);
289 }
290 return G_SOURCE_CONTINUE(!(0));
291}
292
293/*
294 * Open two pipes to dumpcap with the supplied arguments, one for its
295 * standard output and one for its standard error.
296 *
297 * On success, *msg is unchanged and 0 is returned; data_read_fd,
298 * message_read_fd, and fork_child point to the standard output pipe's
299 * file descriptor, the standard error pipe's file descriptor, and
300 * the child's PID/handle, respectively.
301 *
302 * On failure, *msg points to an error message for the failure, and -1 is
303 * returned, in which case *msg must be freed with g_free().
304 */
305#define ARGV_NUMBER_LEN24 24
306static int
307#ifdef _WIN32
308sync_pipe_open_command(char **argv, int *data_read_fd,
309 GIOChannel **message_read_io, int *signal_write_fd,
310 ws_process_id *fork_child, GArray *ifaces,
311 char **msg, void(*update_cb)(void))
312#else
313sync_pipe_open_command(char **argv, int *data_read_fd,
314 GIOChannel **message_read_io, int *signal_write_fd _U___attribute__((unused)),
315 ws_process_id *fork_child, GArray *ifaces _U___attribute__((unused)),
316 char **msg, void(*update_cb)(void))
317#endif
318{
319 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
320 int message_read_fd = -1;
321 char sync_id[ARGV_NUMBER_LEN24];
322#ifdef _WIN32
323 HANDLE sync_pipe[2]; /* pipe used to send messages from child to parent */
324 HANDLE data_pipe[2]; /* pipe used to send data from child to parent */
325 int signal_pipe_write_fd = -1;
326 HANDLE signal_pipe; /* named pipe used to send messages from parent to child (currently only stop) */
327 char control_id[ARGV_NUMBER_LEN24];
328 char *signal_pipe_name;
329 size_t i_handles = 0;
330 HANDLE *handles;
331 GString *args = g_string_sized_new(200);
332 char *quoted_arg;
333 SECURITY_ATTRIBUTES sa;
334 STARTUPINFO si;
335 PROCESS_INFORMATION pi;
336 int i;
337 unsigned j;
338 interface_options *interface_opts;
339#else
340 int sync_pipe[2]; /* pipe used to send messages from child to parent */
341 int data_pipe[2]; /* pipe used to send data from child to parent */
342#endif
343 *fork_child = WS_INVALID_PID-1;
344 if (data_read_fd != NULL((void*)0)) {
345 *data_read_fd = -1;
346 }
347 *message_read_io = NULL((void*)0);
348 ws_debug("sync_pipe_open_command")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 348, __func__, "sync_pipe_open_command"); } } while (0)
;
349
350 if (!msg) {
351 /* We can't return anything */
352 g_strfreev(argv);
353#ifdef _WIN32
354 g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free
) ((args), ((!(0)))))
;
355#endif
356 return -1;
357 }
358
359#ifdef _WIN32
360 /* init SECURITY_ATTRIBUTES */
361 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
362 sa.bInheritHandle = false0;
363 sa.lpSecurityDescriptor = NULL((void*)0);
364
365 /* Create a pipe for the child process to send us messages */
366 /* (increase this value if you have trouble while fast capture file switches) */
367 if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, PIPE_BUF_SIZE((512 * 1000)+4))) {
368 /* Couldn't create the message pipe between parent and child. */
369 *msg = ws_strdup_printf("Couldn't create sync pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s"
, win32strerror(GetLastError()))
370 win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s"
, win32strerror(GetLastError()))
;
371 g_strfreev(argv);
372 return -1;
373 }
374
375 /*
376 * Associate a C run-time file handle with the Windows HANDLE for the
377 * read side of the message pipe.
378 *
379 * (See http://www.flounder.com/handles.htm for information on various
380 * types of file handle in C/C++ on Windows.)
381 */
382 message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
383 if (message_read_fd == -1) {
384 *msg = ws_strdup_printf("Couldn't get C file handle for message read pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for message read pipe: %s"
, g_strerror((*__errno_location ())))
;
385 g_strfreev(argv);
386 CloseHandle(sync_pipe[PIPE_READ]);
387 CloseHandle(sync_pipe[PIPE_WRITE]);
388 return -1;
389 }
390
391 if (data_read_fd != NULL((void*)0)) {
392 /* Create a pipe for the child process to send us data */
393 /* (increase this value if you have trouble while fast capture file switches) */
394 if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, PIPE_BUF_SIZE((512 * 1000)+4))) {
395 /* Couldn't create the message pipe between parent and child. */
396 *msg = ws_strdup_printf("Couldn't create data pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s"
, win32strerror(GetLastError()))
397 win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s"
, win32strerror(GetLastError()))
;
398 g_strfreev(argv);
399 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
400 CloseHandle(sync_pipe[PIPE_WRITE]);
401 return -1;
402 }
403
404 /*
405 * Associate a C run-time file handle with the Windows HANDLE for the
406 * read side of the data pipe.
407 *
408 * (See http://www.flounder.com/handles.htm for information on various
409 * types of file handle in C/C++ on Windows.)
410 */
411 *data_read_fd = _open_osfhandle( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
412 if (*data_read_fd == -1) {
413 *msg = ws_strdup_printf("Couldn't get C file handle for data read pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for data read pipe: %s"
, g_strerror((*__errno_location ())))
;
414 g_strfreev(argv);
415 CloseHandle(data_pipe[PIPE_READ]);
416 CloseHandle(data_pipe[PIPE_WRITE]);
417 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
418 CloseHandle(sync_pipe[PIPE_WRITE]);
419 return -1;
420 }
421 }
422
423 if (signal_write_fd != NULL((void*)0)) {
424 /* Create the signal pipe */
425 snprintf(control_id, ARGV_NUMBER_LEN24, "%ld", GetCurrentProcessId());
426 signal_pipe_name = ws_strdup_printf(SIGNAL_PIPE_FORMAT, control_id)wmem_strdup_printf(((void*)0), SIGNAL_PIPE_FORMAT, control_id
)
;
427 signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name),
428 PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL((void*)0));
429 g_free(signal_pipe_name);
430
431 if (signal_pipe == INVALID_HANDLE_VALUE) {
432 /* Couldn't create the signal pipe between parent and child. */
433 *msg = ws_strdup_printf("Couldn't create signal pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s"
, win32strerror(GetLastError()))
434 win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s"
, win32strerror(GetLastError()))
;
435 g_strfreev(argv);
436 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
437 CloseHandle(sync_pipe[PIPE_WRITE]);
438 return -1;
439 }
440
441 /*
442 * Associate a C run-time file handle with the Windows HANDLE for the
443 * read side of the message pipe.
444 *
445 * (See http://www.flounder.com/handles.htm for information on various
446 * types of file handle in C/C++ on Windows.)
447 */
448 signal_pipe_write_fd = _open_osfhandle( (intptr_t) signal_pipe, _O_BINARY);
449 if (signal_pipe_write_fd == -1) {
450 /* Couldn't create the pipe between parent and child. */
451 *msg = ws_strdup_printf("Couldn't get C file handle for sync pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for sync pipe: %s"
, g_strerror((*__errno_location ())))
;
452 g_strfreev(argv);
453 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
454 CloseHandle(sync_pipe[PIPE_WRITE]);
455 CloseHandle(signal_pipe);
456 return -1;
457 }
458 }
459
460 /* init STARTUPINFO & PROCESS_INFORMATION */
461 memset(&si, 0, sizeof(si));
462 si.cb = sizeof(si);
463 memset(&pi, 0, sizeof(pi));
464#ifdef DEBUG_CHILD
465 si.dwFlags = STARTF_USESHOWWINDOW;
466 si.wShowWindow = SW_SHOW;
467#else
468 si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
469 si.wShowWindow = SW_HIDE; /* this hides the console window */
470
471 if (data_read_fd == NULL((void*)0)) {
472 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
473 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
474 } else {
475 si.hStdInput = NULL((void*)0); /* handle for named pipe*/
476 si.hStdOutput = data_pipe[PIPE_WRITE];
477 }
478 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
479
480 /* On Windows, "[a]n inherited handle refers to the same object in the child
481 * process as it does in the parent process. It also has the same value."
482 * https://learn.microsoft.com/en-us/windows/win32/procthread/inheritance
483 * When converted to a file descriptor (via _open_osfhandle), the fd
484 * value is not necessarily the same in the two processes, but the handle
485 * value can be shared.
486 * A HANDLE is a void* though "64-bit versions of Windows use 32-bit handles
487 * for interoperability... only the lower 32 bits are significant, so it is
488 * safe to truncate the handle... or sign-extend the handle"
489 * https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
490 * So it should be fine to call PtrToLong instead of casting to intptr_t.
491 * https://learn.microsoft.com/en-us/windows/win32/WinProg64/rules-for-using-pointers
492 */
493 int argc = g_strv_length(argv);
494 argv = sync_pipe_add_arg(argv, &argc, "-Z");
495 snprintf(sync_id, ARGV_NUMBER_LEN24, "%ld", PtrToLong(sync_pipe[PIPE_WRITE]));
496 argv = sync_pipe_add_arg(argv, &argc, sync_id);
497#endif
498
499 if (ifaces) {
500 for (j = 0; j < ifaces->len; j++) {
501 interface_opts = &g_array_index(ifaces, interface_options, j)(((interface_options*) (void *) (ifaces)->data) [(j)]);
502 if (interface_opts->extcap_fifo != NULL((void*)0)) {
503 i_handles++;
504 }
505 }
506 }
507 handles = g_new(HANDLE, 3 + i_handles)((HANDLE *) g_malloc_n ((3 + i_handles), sizeof (HANDLE)));
508 i_handles = 0;
509 if (si.hStdInput) {
510 handles[i_handles++] = si.hStdInput;
511 }
512 if (si.hStdOutput && (si.hStdOutput != si.hStdInput)) {
513 handles[i_handles++] = si.hStdOutput;
514 }
515 handles[i_handles++] = sync_pipe[PIPE_WRITE];
516 if (ifaces) {
517 for (j = 0; j < ifaces->len; j++) {
518 interface_opts = &g_array_index(ifaces, interface_options, j)(((interface_options*) (void *) (ifaces)->data) [(j)]);
519 if (interface_opts->extcap_fifo != NULL((void*)0)) {
520 handles[i_handles++] = interface_opts->extcap_pipe_h;
521 }
522 }
523 }
524
525 /* convert args array into a single string */
526 /* XXX - could change sync_pipe_add_arg() instead */
527 /* there is a drawback here: the length is internally limited to 1024 bytes */
528 for(i=0; argv[i] != 0; i++) {
529 if(i != 0) g_string_append_c(args, ' ')g_string_append_c_inline (args, ' '); /* don't prepend a space before the path!!! */
530 quoted_arg = protect_arg(argv[i]);
531 g_string_append(args, quoted_arg)(__builtin_constant_p (quoted_arg) ? __extension__ ({ const char
* const __val = (quoted_arg); g_string_append_len_inline (args
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (args
, quoted_arg, (gssize) -1))
;
532 g_free(quoted_arg);
533 }
534
535 /* call dumpcap */
536 if(!win32_create_process(argv[0], args->str, NULL((void*)0), NULL((void*)0), i_handles, handles,
537 CREATE_NEW_CONSOLE, NULL((void*)0), NULL((void*)0), &si, &pi)) {
538 *msg = ws_strdup_printf("Couldn't run %s in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run %s in child process: %s"
, args->str, win32strerror(GetLastError()))
539 args->str, win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't run %s in child process: %s"
, args->str, win32strerror(GetLastError()))
;
540 if (data_read_fd) {
541 ws_closeclose(*data_read_fd); /* Should close data_pipe[PIPE_READ] */
542 CloseHandle(data_pipe[PIPE_WRITE]);
543 } else {
544 ws_closeclose(signal_pipe_write_fd);
545 }
546 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
547 CloseHandle(sync_pipe[PIPE_WRITE]);
548 g_strfreev(argv);
549 g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free
) ((args), ((!(0)))))
;
550 g_free(handles);
551 return -1;
552 }
553 *fork_child = pi.hProcess;
554 /* We may need to store this and close it later */
555 CloseHandle(pi.hThread);
556 g_strfreev(argv);
557 g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free
) ((args), ((!(0)))))
;
558 g_free(handles);
559
560 if (signal_write_fd != NULL((void*)0)) {
561 *signal_write_fd = signal_pipe_write_fd;
562 }
563#else /* _WIN32 */
564 /* Create a pipe for the child process to send us messages */
565 if (pipe(sync_pipe) < 0) {
566 /* Couldn't create the message pipe between parent and child. */
567 *msg = ws_strdup_printf("Couldn't create sync pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s"
, g_strerror((*__errno_location ())))
;
568 g_strfreev(argv);
569 return -1;
570 }
571
572 if (data_read_fd != NULL((void*)0)) {
573 /* Create a pipe for the child process to send us data */
574 if (pipe(data_pipe) < 0) {
575 /* Couldn't create the data pipe between parent and child. */
576 *msg = ws_strdup_printf("Couldn't create data pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s"
, g_strerror((*__errno_location ())))
;
577 g_strfreev(argv);
578 ws_closeclose(sync_pipe[PIPE_READ]);
579 ws_closeclose(sync_pipe[PIPE_WRITE]);
580 return -1;
581 }
582 }
583
584 if ((*fork_child = fork()) == 0) {
585 /*
586 * Child process - run dumpcap with the right arguments to make
587 * it just capture with the specified capture parameters
588 */
589 if (data_read_fd != NULL((void*)0)) {
590 dup2(data_pipe[PIPE_WRITE], 1);
591 ws_closeclose(data_pipe[PIPE_READ]);
592 ws_closeclose(data_pipe[PIPE_WRITE]);
593 }
594 ws_closeclose(sync_pipe[PIPE_READ]);
595 /* dumpcap should be running in capture child mode (hidden feature) */
596#ifndef DEBUG_CHILD
597 int argc = g_strv_length(argv);
598 argv = sync_pipe_add_arg(argv, &argc, "-Z");
599 snprintf(sync_id, ARGV_NUMBER_LEN24, "%d", sync_pipe[PIPE_WRITE]);
600 argv = sync_pipe_add_arg(argv, &argc, sync_id);
601#endif
602 execv(argv[0], argv);
603 sync_pipe_write_int_msg(sync_pipe[PIPE_WRITE], SP_EXEC_FAILED'X', errno(*__errno_location ()));
604
605 /* Exit with "_exit()", so that we don't close the connection
606 to the X server (and cause stuff buffered up by our parent but
607 not yet sent to be sent, as that stuff should only be sent by
608 our parent). We've sent an error message to the parent, so
609 we exit with an exit status of 1 (any exit status other than
610 0 or 1 will cause an additional message to report that exit
611 status, over and above the error message we sent to the parent). */
612 _exit(1);
613 }
614
615 g_strfreev(argv);
616
617 if (fetch_dumpcap_pid && *fork_child > 0)
618 fetch_dumpcap_pid(*fork_child);
619
620 if (data_read_fd != NULL((void*)0)) {
621 *data_read_fd = data_pipe[PIPE_READ];
622 }
623 message_read_fd = sync_pipe[PIPE_READ];
624
625#endif
626
627 /* Parent process - read messages from the child process over the
628 sync pipe. */
629
630 /* Close the write sides of the pipes, so that only the child has them
631 open, and thus they completely close, and thus return to us
632 an EOF indication, if the child closes them (either deliberately
633 or by exiting abnormally). */
634#ifdef _WIN32
635 if (data_read_fd != NULL((void*)0)) {
636 CloseHandle(data_pipe[PIPE_WRITE]);
637 }
638 CloseHandle(sync_pipe[PIPE_WRITE]);
639#else
640 if (data_read_fd != NULL((void*)0)) {
641 ws_closeclose(data_pipe[PIPE_WRITE]);
642 }
643 ws_closeclose(sync_pipe[PIPE_WRITE]);
644#endif
645
646 if (*fork_child == WS_INVALID_PID-1) {
647 /* We couldn't even create the child process. */
648 *msg = ws_strdup_printf("Couldn't create child process: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create child process: %s"
, g_strerror((*__errno_location ())))
;
649 if (data_read_fd != NULL((void*)0)) {
650 ws_closeclose(*data_read_fd);
651 }
652#ifdef _WIN32
653 if (signal_write_fd != NULL((void*)0)) {
654 ws_closeclose(signal_pipe_write_fd);
655 }
656#endif
657 ws_closeclose(message_read_fd);
658 return -1;
659 }
660
661#ifdef _WIN32
662 *message_read_io = g_io_channel_win32_new_fd(message_read_fd);
663#else
664 *message_read_io = g_io_channel_unix_new(message_read_fd);
665#endif
666 g_io_channel_set_encoding(*message_read_io, NULL((void*)0), NULL((void*)0));
667 g_io_channel_set_buffered(*message_read_io, false0);
668 g_io_channel_set_close_on_unref(*message_read_io, true1);
669
670 /* we might wait for a moment till child is ready, so update screen now */
671 if (update_cb) update_cb();
672 return 0;
673}
674
675/* a new capture run: start a new dumpcap task and hand over parameters through command line */
676bool_Bool
677sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
678 capture_session *cap_session, info_data_t* cap_data,
679 void (*update_cb)(void))
680{
681#ifdef _WIN32
682 char control_id[ARGV_NUMBER_LEN24];
683#endif
684 GIOChannel *sync_pipe_read_io;
685 int argc;
686 char **argv;
687 int i;
688 unsigned j;
689 interface_options *interface_opts;
690
691 if (capture_opts->ifaces->len > 1)
692 capture_opts->use_pcapng = true1;
693 ws_debug("sync_pipe_start")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 693, __func__, "sync_pipe_start"); } } while (0)
;
694 capture_opts_log(LOG_DOMAIN_CAPTURE"Capture", LOG_LEVEL_DEBUG, capture_opts);
695
696 cap_session->fork_child = WS_INVALID_PID-1;
697 cap_session->capture_opts = capture_opts;
698
699 if (!extcap_init_interfaces(cap_session)) {
700 report_failure("Unable to init extcaps. (tmp fifo already exists?)");
701 return false0;
702 }
703
704 argv = init_pipe_args(capture_opts->app_name, &argc);
705 if (!argv) {
706 /* We don't know where to find dumpcap. */
707 report_failure("We don't know where to find dumpcap.");
708 return false0;
709 }
710
711 if (capture_opts->ifaces->len > 1)
712 argv = sync_pipe_add_arg(argv, &argc, "-t");
713
714 argv = sync_pipe_add_arg(argv, &argc, "-F");
715 if (capture_opts->use_pcapng)
716 argv = sync_pipe_add_arg(argv, &argc, "pcapng");
717 else
718 argv = sync_pipe_add_arg(argv, &argc, "pcap");
719
720 if (capture_comments != NULL((void*)0)) {
721 for (j = 0; j < capture_comments->len; j++) {
722 argv = sync_pipe_add_arg(argv, &argc, "--capture-comment");
723 argv = sync_pipe_add_arg(argv, &argc, (char*)g_ptr_array_index(capture_comments, j)((capture_comments)->pdata)[j]);
724 }
725 }
726
727 if (capture_opts->temp_dir) {
728 argv = sync_pipe_add_arg(argv, &argc, "--temp-dir");
729 argv = sync_pipe_add_arg(argv, &argc, capture_opts->temp_dir);
730 }
731
732 if (capture_opts->multi_files_on) {
733 if (capture_opts->has_autostop_filesize) {
734 char sfilesize[ARGV_NUMBER_LEN24];
735 argv = sync_pipe_add_arg(argv, &argc, "-b");
736 snprintf(sfilesize, ARGV_NUMBER_LEN24, "filesize:%u",capture_opts->autostop_filesize);
737 argv = sync_pipe_add_arg(argv, &argc, sfilesize);
738 }
739
740 if (capture_opts->has_file_duration) {
741 char sfile_duration[ARGV_NUMBER_LEN24];
742 argv = sync_pipe_add_arg(argv, &argc, "-b");
743 snprintf(sfile_duration, ARGV_NUMBER_LEN24, "duration:%f",capture_opts->file_duration);
744 argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
745 }
746
747 if (capture_opts->has_file_interval) {
748 char sfile_interval[ARGV_NUMBER_LEN24];
749 argv = sync_pipe_add_arg(argv, &argc, "-b");
750 snprintf(sfile_interval, ARGV_NUMBER_LEN24, "interval:%d",capture_opts->file_interval);
751 argv = sync_pipe_add_arg(argv, &argc, sfile_interval);
752 }
753
754 if (capture_opts->has_file_packets) {
755 char sfile_packets[ARGV_NUMBER_LEN24];
756 argv = sync_pipe_add_arg(argv, &argc, "-b");
757 snprintf(sfile_packets, ARGV_NUMBER_LEN24, "packets:%d",capture_opts->file_packets);
758 argv = sync_pipe_add_arg(argv, &argc, sfile_packets);
759 }
760
761 if (capture_opts->has_ring_num_files) {
762 char sring_num_files[ARGV_NUMBER_LEN24];
763 argv = sync_pipe_add_arg(argv, &argc, "-b");
764 snprintf(sring_num_files, ARGV_NUMBER_LEN24, "files:%d",capture_opts->ring_num_files);
765 argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
766 }
767
768 if (capture_opts->print_file_names) {
769 char *print_name = g_strdup_printf("printname:%s", capture_opts->print_name_to);
770 argv = sync_pipe_add_arg(argv, &argc, "-b");
771 argv = sync_pipe_add_arg(argv, &argc, print_name);
772 g_free(print_name);
773 }
774
775 if (capture_opts->has_nametimenum) {
776 char nametimenum[ARGV_NUMBER_LEN24];
777 argv = sync_pipe_add_arg(argv, &argc, "-b");
778 snprintf(nametimenum, ARGV_NUMBER_LEN24, "nametimenum:2");
779 argv = sync_pipe_add_arg(argv, &argc, nametimenum);
780 }
781
782 if (capture_opts->has_autostop_files) {
783 char sautostop_files[ARGV_NUMBER_LEN24];
784 argv = sync_pipe_add_arg(argv, &argc, "-a");
785 snprintf(sautostop_files, ARGV_NUMBER_LEN24, "files:%d",capture_opts->autostop_files);
786 argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
787 }
788 } else {
789 if (capture_opts->has_autostop_filesize) {
790 char sautostop_filesize[ARGV_NUMBER_LEN24];
791 argv = sync_pipe_add_arg(argv, &argc, "-a");
792 snprintf(sautostop_filesize, ARGV_NUMBER_LEN24, "filesize:%u",capture_opts->autostop_filesize);
793 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
794 }
795 }
796
797 if (capture_opts->has_autostop_packets) {
798 char scount[ARGV_NUMBER_LEN24];
799 argv = sync_pipe_add_arg(argv, &argc, "-c");
800 snprintf(scount, ARGV_NUMBER_LEN24, "%d",capture_opts->autostop_packets);
801 argv = sync_pipe_add_arg(argv, &argc, scount);
802 }
803
804 if (capture_opts->has_autostop_duration) {
805 char sautostop_duration[ARGV_NUMBER_LEN24];
806 argv = sync_pipe_add_arg(argv, &argc, "-a");
807 snprintf(sautostop_duration, ARGV_NUMBER_LEN24, "duration:%f",capture_opts->autostop_duration);
808 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
809 }
810
811 if (capture_opts->has_autostop_written_packets) {
812 char scount[ARGV_NUMBER_LEN24];
813 argv = sync_pipe_add_arg(argv, &argc, "-a");
814 snprintf(scount, ARGV_NUMBER_LEN24, "packets:%d",capture_opts->autostop_written_packets);
815 argv = sync_pipe_add_arg(argv, &argc, scount);
816 }
817
818 if (capture_opts->group_read_access) {
819 argv = sync_pipe_add_arg(argv, &argc, "-g");
820 }
821
822 if (capture_opts->update_interval != DEFAULT_UPDATE_INTERVAL100) {
823 char scount[ARGV_NUMBER_LEN24];
824 argv = sync_pipe_add_arg(argv, &argc, "--update-interval");
825 snprintf(scount, ARGV_NUMBER_LEN24, "%d", capture_opts->update_interval);
826 argv = sync_pipe_add_arg(argv, &argc, scount);
827 }
828
829 for (j = 0; j < capture_opts->ifaces->len; j++) {
830 interface_opts = &g_array_index(capture_opts->ifaces, interface_options, j)(((interface_options*) (void *) (capture_opts->ifaces)->
data) [(j)])
;
831
832 argv = sync_pipe_add_arg(argv, &argc, "-i");
833 if (interface_opts->extcap_fifo != NULL((void*)0))
834 {
835#ifdef _WIN32
836 char *pipe = ws_strdup_printf("%s%" PRIuMAX, EXTCAP_PIPE_PREFIX, (uintmax_t)interface_opts->extcap_pipe_h)wmem_strdup_printf(((void*)0), "%s%" "l" "u", "wireshark_extcap"
, (uintmax_t)interface_opts->extcap_pipe_h)
;
837 argv = sync_pipe_add_arg(argv, &argc, pipe);
838 g_free(pipe);
839#else
840 argv = sync_pipe_add_arg(argv, &argc, interface_opts->extcap_fifo);
841#endif
842 /* Add a name for the interface, to put into an IDB. */
843 argv = sync_pipe_add_arg(argv, &argc, "--ifname");
844 argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
845 }
846 else
847 argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
848
849 if (interface_opts->descr != NULL((void*)0))
850 {
851 /* Add a description for the interface to put into an IDB and
852 * use for the temporary filename. */
853 argv = sync_pipe_add_arg(argv, &argc, "--ifdescr");
854 argv = sync_pipe_add_arg(argv, &argc, interface_opts->descr);
855 }
856
857 if (interface_opts->cfilter != NULL((void*)0) && strlen(interface_opts->cfilter) != 0) {
858 argv = sync_pipe_add_arg(argv, &argc, "-f");
859 argv = sync_pipe_add_arg(argv, &argc, interface_opts->cfilter);
860 }
861 if (!interface_opts->optimize) {
862 argv = sync_pipe_add_arg(argv, &argc, "--no-optimize");
863 }
864 if (interface_opts->has_snaplen) {
865 char ssnap[ARGV_NUMBER_LEN24];
866 argv = sync_pipe_add_arg(argv, &argc, "-s");
867 snprintf(ssnap, ARGV_NUMBER_LEN24, "%d", interface_opts->snaplen);
868 argv = sync_pipe_add_arg(argv, &argc, ssnap);
869 }
870
871 if (interface_opts->linktype != -1) {
872 const char *linktype = linktype_val_to_name(interface_opts->linktype);
873 if ( linktype != NULL((void*)0) )
874 {
875 argv = sync_pipe_add_arg(argv, &argc, "-y");
876 argv = sync_pipe_add_arg(argv, &argc, linktype);
877 }
878 }
879
880 if (!interface_opts->promisc_mode) {
881 argv = sync_pipe_add_arg(argv, &argc, "-p");
882 }
883
884 if (interface_opts->buffer_size != DEFAULT_CAPTURE_BUFFER_SIZE2) {
885 char buffer_size[ARGV_NUMBER_LEN24];
886 argv = sync_pipe_add_arg(argv, &argc, "-B");
887 if(interface_opts->buffer_size == 0x00)
888 interface_opts->buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE2;
889 snprintf(buffer_size, ARGV_NUMBER_LEN24, "%d", interface_opts->buffer_size);
890 argv = sync_pipe_add_arg(argv, &argc, buffer_size);
891 }
892
893 if (interface_opts->monitor_mode) {
894 argv = sync_pipe_add_arg(argv, &argc, "-I");
895 }
896
897#ifdef HAVE_PCAP_REMOTE
898 if (interface_opts->datatx_udp)
899 argv = sync_pipe_add_arg(argv, &argc, "-u");
900
901 if (!interface_opts->nocap_rpcap)
902 argv = sync_pipe_add_arg(argv, &argc, "-r");
903
904 if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
905 char sauth[256];
906 argv = sync_pipe_add_arg(argv, &argc, "-A");
907 snprintf(sauth, sizeof(sauth), "%s:%s",
908 interface_opts->auth_username,
909 interface_opts->auth_password);
910 argv = sync_pipe_add_arg(argv, &argc, sauth);
911 }
912#endif
913
914#ifdef HAVE_PCAP_SETSAMPLING
915 if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) {
916 char ssampling[ARGV_NUMBER_LEN24];
917 argv = sync_pipe_add_arg(argv, &argc, "-m");
918 snprintf(ssampling, ARGV_NUMBER_LEN24, "%s:%d",
919 interface_opts->sampling_method == CAPTURE_SAMP_BY_COUNT ? "count" :
920 interface_opts->sampling_method == CAPTURE_SAMP_BY_TIMER ? "timer" :
921 "undef",
922 interface_opts->sampling_param);
923 argv = sync_pipe_add_arg(argv, &argc, ssampling);
924 }
925#endif
926 if (interface_opts->timestamp_type) {
927 argv = sync_pipe_add_arg(argv, &argc, "--time-stamp-type");
928 argv = sync_pipe_add_arg(argv, &argc, interface_opts->timestamp_type);
929 }
930 }
931
932#ifndef DEBUG_CHILD
933#ifdef _WIN32
934 /* pass process id to dumpcap for named signal pipe */
935 argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
936 snprintf(control_id, ARGV_NUMBER_LEN24, "%ld", GetCurrentProcessId());
937 argv = sync_pipe_add_arg(argv, &argc, control_id);
938#endif
939#endif
940
941 if (capture_opts->save_file) {
942 argv = sync_pipe_add_arg(argv, &argc, "-w");
943 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
944 }
945 for (i = 0; i < argc; i++) {
946 ws_debug("argv[%d]: %s", i, argv[i])do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 946, __func__, "argv[%d]: %s", i, argv[i]); } } while (0)
;
947 }
948 if (capture_opts->compress_type) {
949 argv = sync_pipe_add_arg(argv, &argc, "--compress-type");
950 argv = sync_pipe_add_arg(argv, &argc, capture_opts->compress_type);
951 }
952
953 int ret;
954 char* msg;
955#ifdef _WIN32
956 ret = sync_pipe_open_command(argv, NULL((void*)0), &sync_pipe_read_io, &cap_session->signal_pipe_write_fd,
957 &cap_session->fork_child, capture_opts->ifaces, &msg, update_cb);
958#else
959 ret = sync_pipe_open_command(argv, NULL((void*)0), &sync_pipe_read_io, NULL((void*)0),
960 &cap_session->fork_child, NULL((void*)0), &msg, update_cb);
961#endif
962
963 if (ret == -1) {
964 report_failure("%s", msg);
965 g_free(msg);
966 return false0;
967 }
968
969 /* Parent process - read messages from the child process over the
970 sync pipe. */
971
972 cap_session->fork_child_status = 0;
973 cap_session->cap_data_info = cap_data;
974
975 /* We were able to set up to read the capture file;
976 arrange that our callback be called whenever it's possible
977 to read from the sync pipe, so that it's called when
978 the child process wants to tell us something. */
979
980 /* we have a running capture, now wait for the real capture filename */
981 if (cap_session->pipe_input_id) {
982 g_source_remove(cap_session->pipe_input_id);
983 cap_session->pipe_input_id = 0;
984 }
985 cap_session->pipe_input_id = g_io_add_watch(sync_pipe_read_io, G_IO_IN | G_IO_HUP, pipe_io_cb, cap_session);
986 /* Pipe will be closed when watch is removed */
987 g_io_channel_unref(sync_pipe_read_io);
988
989 return true1;
990}
991
992/*
993 * Close the pipes we're using to read from dumpcap, and wait for it
994 * to exit. On success, *msgp is unchanged, and the exit status of
995 * dumpcap is returned. On failure (which includes "dumpcap exited
996 * due to being killed by a signal or an exception"), *msgp points
997 * to an error message for the failure, and -1 is returned. In the
998 * latter case, *msgp must be freed with g_free().
999 */
1000static int
1001sync_pipe_close_command(int *data_read_fd, GIOChannel *message_read_io,
1002 ws_process_id *fork_child, char **msgp)
1003{
1004 ws_closeclose(*data_read_fd);
1005 if (message_read_io != NULL((void*)0))
1006 g_io_channel_unref(message_read_io);
1007
1008#ifdef _WIN32
1009 /* XXX - Should we signal the child somehow? */
1010 sync_pipe_kill(*fork_child);
1011#endif
1012
1013 return sync_pipe_wait_for_child(*fork_child, msgp);
1014}
1015
1016/*
1017 * Run dumpcap with the supplied arguments.
1018 *
1019 * On success, *data points to a buffer containing the dumpcap output,
1020 * *primary_msg and *secondary_message are NULL, and 0 is returned; *data
1021 * must be freed with g_free().
1022 *
1023 * On failure, *data is NULL, *primary_msg points to an error message,
1024 * *secondary_msg either points to an additional error message or is
1025 * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1026 * must be freed with g_free().
1027 */
1028static int
1029sync_pipe_run_command_actual(char **argv, char **data, char **primary_msg,
1030 char **secondary_msg, void(*update_cb)(void))
1031{
1032 char *msg;
1033 int data_pipe_read_fd, ret;
1034 GIOChannel *sync_pipe_read_io;
1035 ws_process_id fork_child;
1036 char *wait_msg;
1037 char *buffer = g_malloc(PIPE_BUF_SIZE((512 * 1000)+4) + 1);
1038 ssize_t nread;
1039 char indicator;
1040 int32_t exec_errno = 0;
1041 unsigned primary_msg_len;
1042 const char *primary_msg_text;
1043 unsigned secondary_msg_len;
1044 const char *secondary_msg_text;
1045 char *combined_msg;
1046 GString *data_buf = NULL((void*)0);
1047 ssize_t count;
1048
1049 if (buffer == NULL((void*)0)) {
1050 /* g_malloc is supposed to terminate the program if this fails, but,
1051 * at least on a RELEASE build, some versions of gcc don't think that
1052 * happens.
1053 */
1054 *primary_msg = ws_strdup_printf("Couldn't allocate memory for dumpcap output buffer: %s",wmem_strdup_printf(((void*)0), "Couldn't allocate memory for dumpcap output buffer: %s"
, g_strerror((*__errno_location ())))
1055 g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't allocate memory for dumpcap output buffer: %s"
, g_strerror((*__errno_location ())))
;
1056 *secondary_msg = NULL((void*)0);
1057 *data = NULL((void*)0);
1058 return -1;
1059 }
1060
1061 ret = sync_pipe_open_command(argv, &data_pipe_read_fd, &sync_pipe_read_io, NULL((void*)0),
1062 &fork_child, NULL((void*)0), &msg, update_cb);
1063 if (ret == -1) {
1064 *primary_msg = msg;
1065 *secondary_msg = NULL((void*)0);
1066 *data = NULL((void*)0);
1067 g_free(buffer);
1068 return -1;
1069 }
1070
1071 /*
1072 * We were able to set up to read dumpcap's output. Do so.
1073 *
1074 * First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
1075 */
1076 do {
1077 nread = pipe_read_block(sync_pipe_read_io, &indicator, SP_MAX_MSG_LEN(512 * 1000),
1078 buffer, primary_msg);
1079 if(nread <= 0) {
1080 /* We got a read error from the sync pipe, or we got no data at
1081 all from the sync pipe, so we're not going to be getting any
1082 data or error message from the child process. Pick up its
1083 exit status, and complain.
1084
1085 We don't have to worry about killing the child, if the sync pipe
1086 returned an error. Usually this error is caused as the child killed
1087 itself while going down. Even in the rare cases that this isn't the
1088 case, the child will get an error when writing to the broken pipe
1089 the next time, cleaning itself up then. */
1090 g_io_channel_unref(sync_pipe_read_io);
1091 ret = sync_pipe_wait_for_child(fork_child, &wait_msg);
1092 if(nread == 0) {
1093 /* We got an EOF from the sync pipe. That means that it exited
1094 before giving us any data to read. If ret is -1, we report
1095 that as a bad exit (e.g., exiting due to a signal); otherwise,
1096 we report it as a premature exit. */
1097 if (ret == -1)
1098 *primary_msg = wait_msg;
1099 else
1100 *primary_msg = g_strdup("Child dumpcap closed sync pipe prematurely")g_strdup_inline ("Child dumpcap closed sync pipe prematurely"
)
;
1101 } else {
1102 /* We got an error from the sync pipe. If ret is -1, report
1103 both the sync pipe I/O error and the wait error. */
1104 if (ret == -1) {
1105 combined_msg = ws_strdup_printf("%s\n\n%s", *primary_msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", *primary_msg, wait_msg
)
;
1106 g_free(*primary_msg);
1107 g_free(wait_msg);
1108 *primary_msg = combined_msg;
1109 }
1110 }
1111 *secondary_msg = NULL((void*)0);
1112 *data = NULL((void*)0);
1113 g_free(buffer);
1114
1115 return -1;
1116 }
1117
1118 /* we got a valid message block from the child, process it */
1119 switch(indicator) {
1120
1121 case SP_EXEC_FAILED'X':
1122 /*
1123 * Exec of dumpcap failed. Get the errno for the failure.
1124 */
1125 if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
1126 ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 1126, __func__, "Invalid errno: %s", buffer); } } while (0)
;
1127 }
1128
1129 /*
1130 * Pick up the child status.
1131 */
1132 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1133 &fork_child, &msg);
1134 if (ret == -1) {
1135 /*
1136 * Child process failed unexpectedly, or wait failed; msg is the
1137 * error message.
1138 */
1139 *primary_msg = msg;
1140 *secondary_msg = NULL((void*)0);
1141 } else {
1142 /*
1143 * Child process failed, but returned the expected exit status.
1144 * Return the messages it gave us, and indicate failure.
1145 */
1146 *primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
1147 g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
;
1148 *secondary_msg = NULL((void*)0);
1149 ret = -1;
1150 }
1151 *data = NULL((void*)0);
1152 break;
1153
1154 case SP_ERROR_MSG'E':
1155 /*
1156 * Error from dumpcap; there will be a primary message and a
1157 * secondary message.
1158 */
1159
1160 /* convert primary message */
1161 pipe_convert_header((unsigned char*)buffer, &indicator, &primary_msg_len);
1162 primary_msg_text = buffer+4;
1163 /* convert secondary message */
1164 pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, &indicator,
1165 &secondary_msg_len);
1166 secondary_msg_text = primary_msg_text + primary_msg_len + 4;
1167 /* the capture child will close the sync_pipe, nothing to do */
1168
1169 /*
1170 * Pick up the child status.
1171 */
1172 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1173 &fork_child, &msg);
1174 if (ret == -1) {
1175 /*
1176 * Child process failed unexpectedly, or wait failed; msg is the
1177 * error message.
1178 */
1179 *primary_msg = msg;
1180 *secondary_msg = NULL((void*)0);
1181 } else {
1182 /*
1183 * Child process failed, but returned the expected exit status.
1184 * Return the messages it gave us, and indicate failure.
1185 */
1186 *primary_msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1187 *secondary_msg = g_strdup(secondary_msg_text)g_strdup_inline (secondary_msg_text);
1188 ret = -1;
1189 }
1190 *data = NULL((void*)0);
1191 break;
1192
1193 case SP_BAD_FILTER'B': {
1194 uint32_t indx = 0;
1195 const char* end;
1196
1197 if (ws_strtou32(buffer, &end, &indx) && end[0] == ':') {
1198 primary_msg_text = end + 1;
1199 } else {
1200 primary_msg_text = "dumpcap process returned a SP_BAD_FILTER without an error message";
1201 }
1202 /*
1203 * Pick up the child status.
1204 */
1205 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1206 &fork_child, &msg);
1207 if (ret == -1) {
1208 /*
1209 * Child process failed unexpectedly, or wait failed; msg is the
1210 * error message.
1211 */
1212 *primary_msg = msg;
1213 *secondary_msg = NULL((void*)0);
1214 } else {
1215 /*
1216 * Child process failed, but returned the expected exit status.
1217 * Return the messages it gave us, and indicate failure.
1218 */
1219 *primary_msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1220 *secondary_msg = NULL((void*)0);
1221 ret = -1;
1222 }
1223 *data = NULL((void*)0);
1224 break;
1225 }
1226 case SP_LOG_MSG'L':
1227 /*
1228 * Log from dumpcap; pass to our log
1229 */
1230 sync_pipe_handle_log_msg(buffer);
1231 break;
1232
1233 case SP_SUCCESS'S':
1234 /* read the output from the command */
1235 data_buf = g_string_new("");
1236 while ((count = ws_readread(data_pipe_read_fd, buffer, PIPE_BUF_SIZE((512 * 1000)+4))) > 0) {
1237 buffer[count] = '\0';
1238 g_string_append(data_buf, buffer)(__builtin_constant_p (buffer) ? __extension__ ({ const char *
const __val = (buffer); g_string_append_len_inline (data_buf
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (data_buf
, buffer, (gssize) -1))
;
1239 }
1240
1241 /*
1242 * Pick up the child status.
1243 */
1244 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1245 &fork_child, &msg);
1246 if (ret == -1) {
1247 /*
1248 * Child process failed unexpectedly, or wait failed; msg is the
1249 * error message.
1250 */
1251 *primary_msg = msg;
1252 *secondary_msg = NULL((void*)0);
1253 g_string_free(data_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(data_buf), ((!(0)))) : g_string_free_and_steal (data_buf)) :
(g_string_free) ((data_buf), ((!(0)))))
;
1254 *data = NULL((void*)0);
1255 } else {
1256 /*
1257 * Child process succeeded.
1258 */
1259 *primary_msg = NULL((void*)0);
1260 *secondary_msg = NULL((void*)0);
1261 *data = g_string_free(data_buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((data_buf
), ((0))) : g_string_free_and_steal (data_buf)) : (g_string_free
) ((data_buf), ((0))))
;
1262 }
1263 break;
1264
1265 default:
1266 /*
1267 * Pick up the child status.
1268 */
1269 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1270 &fork_child, &msg);
1271 if (ret == -1) {
1272 /*
1273 * Child process failed unexpectedly, or wait failed; msg is the
1274 * error message.
1275 */
1276 *primary_msg = msg;
1277 *secondary_msg = NULL((void*)0);
1278 } else {
1279 /*
1280 * Child process returned an unknown status.
1281 */
1282 *primary_msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x"
, indicator)
1283 indicator)wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x"
, indicator)
;
1284 *secondary_msg = NULL((void*)0);
1285 ret = -1;
1286 }
1287 *data = NULL((void*)0);
1288 break;
1289 }
1290 } while (indicator != SP_SUCCESS'S' && ret != -1);
1291
1292 g_free(buffer);
1293 return ret;
1294}
1295
1296/* centralised logging and timing for sync_pipe_run_command_actual(),
1297* redirects to sync_pipe_run_command_actual()
1298*/
1299static int
1300sync_pipe_run_command(char **argv, char **data, char **primary_msg,
1301 char **secondary_msg, void (*update_cb)(void))
1302{
1303 int ret, i;
1304 int64_t start_time;
1305 double elapsed;
1306 int logging_enabled;
1307
1308 /* check if logging is actually enabled, otherwise don't expend the CPU generating logging */
1309 logging_enabled = ws_log_msg_is_active(WS_LOG_DOMAIN"Capture", LOG_LEVEL_INFO);
1310 if (logging_enabled) {
1311 start_time = g_get_monotonic_time();
1312 ws_debug("sync_pipe_run_command() starts")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1312, __func__, "sync_pipe_run_command() starts"); } } while
(0)
;
1313 for (i=0; argv[i] != 0; i++) {
1314 ws_noisy(" argv[%d]: %s", i, argv[i])do { if (1) { ws_log_full("Capture", LOG_LEVEL_NOISY, "capture/capture_sync.c"
, 1314, __func__, " argv[%d]: %s", i, argv[i]); } } while (0
)
;
1315 }
1316 }
1317 /* do the actual sync pipe run command */
1318 ret = sync_pipe_run_command_actual(argv, data, primary_msg, secondary_msg, update_cb);
1319
1320 if (logging_enabled) {
1321 elapsed = (g_get_monotonic_time() - start_time) / 1e6;
1322
1323 ws_debug("sync_pipe_run_command() ends, taking %.3fs, result=%d", elapsed, ret)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1323, __func__, "sync_pipe_run_command() ends, taking %.3fs, result=%d"
, elapsed, ret); } } while (0)
;
1324
1325 }
1326 return ret;
1327}
1328
1329
1330int
1331sync_interface_set_80211_chan(const char* app_name, const char *iface, const char *freq, const char *type,
1332 const char *center_freq1, const char *center_freq2,
1333 char **data, char **primary_msg,
1334 char **secondary_msg, void (*update_cb)(void))
1335{
1336 int argc, ret;
1337 char **argv;
1338 char *opt;
1339
1340 argv = init_pipe_args(app_name, &argc);
1341
1342 if (!argv) {
1343 *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1344 *secondary_msg = NULL((void*)0);
1345 *data = NULL((void*)0);
1346 return -1;
1347 }
1348
1349 argv = sync_pipe_add_arg(argv, &argc, "-i");
1350 argv = sync_pipe_add_arg(argv, &argc, iface);
1351
1352 if (center_freq2)
1353 opt = ws_strdup_printf("%s,%s,%s,%s", freq, type, center_freq1, center_freq2)wmem_strdup_printf(((void*)0), "%s,%s,%s,%s", freq, type, center_freq1
, center_freq2)
;
1354 else if (center_freq1)
1355 opt = ws_strdup_printf("%s,%s,%s", freq, type, center_freq1)wmem_strdup_printf(((void*)0), "%s,%s,%s", freq, type, center_freq1
)
;
1356 else if (type)
1357 opt = ws_strdup_printf("%s,%s", freq, type)wmem_strdup_printf(((void*)0), "%s,%s", freq, type);
1358 else
1359 opt = g_strdup(freq)g_strdup_inline (freq);
1360
1361 argv = sync_pipe_add_arg(argv, &argc, "-k");
1362 argv = sync_pipe_add_arg(argv, &argc, opt);
1363
1364 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1365 g_free(opt);
1366 return ret;
1367}
1368
1369/*
1370 * Get the results of compiling a capture filter for an interface using dumpcap.
1371 *
1372 * On success, *data points to a buffer containing the dumpcap output,
1373 * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1374 * must be freed with g_free().
1375 *
1376 * On failure, *data is NULL, *primary_msg points to an error message,
1377 * *secondary_msg either points to an additional error message or is
1378 * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1379 * must be freed with g_free().
1380 */
1381int
1382sync_if_bpf_filter_open(const char* app_name, const char *ifname, const char* filter, int linktype,
1383 bool_Bool optimize, char **data, char **primary_msg,
1384 char **secondary_msg, void (*update_cb)(void))
1385{
1386 int argc;
1387 char **argv;
1388 int ret;
1389
1390 ws_debug("sync_if_bpf_filter_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1390, __func__, "sync_if_bpf_filter_open"); } } while (0)
;
1391
1392 const char* linktype_name = linktype_val_to_name(linktype);
1393 if (linktype != -1) { // Allow -1 for device default
1394 if (!linktype_name) {
1395 *primary_msg = g_strdup_printf("Unknown link-layer type %d.", linktype);
1396 *secondary_msg = NULL((void*)0);
1397 *data = NULL((void*)0);
1398 return -1;
1399 }
1400 }
1401
1402 argv = init_pipe_args(app_name, &argc);
1403
1404 if (!argv) {
1405 *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1406 *secondary_msg = NULL((void*)0);
1407 *data = NULL((void*)0);
1408 return -1;
1409 }
1410
1411 /* Ask for the human-readable BPF code for the capture filter */
1412 argv = sync_pipe_add_arg(argv, &argc, "-d");
1413 argv = sync_pipe_add_arg(argv, &argc, "-i");
1414 argv = sync_pipe_add_arg(argv, &argc, ifname);
1415 if (linktype_name) {
1416 argv = sync_pipe_add_arg(argv, &argc, "-y");
1417 argv = sync_pipe_add_arg(argv, &argc, linktype_name);
1418 }
1419 if (!optimize) {
1420 argv = sync_pipe_add_arg(argv, &argc, "--no-optimize");
1421 }
1422 if (filter && strcmp(filter, "") != 0) {
1423 argv = sync_pipe_add_arg(argv, &argc, "-f");
1424 argv = sync_pipe_add_arg(argv, &argc, filter);
1425 }
1426
1427 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1428 return ret;
1429}
1430
1431/*
1432 * Get the list of interfaces using dumpcap.
1433 *
1434 * On success, *data points to a buffer containing the dumpcap output,
1435 * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1436 * must be freed with g_free().
1437 *
1438 * On failure, *data is NULL, *primary_msg points to an error message,
1439 * *secondary_msg either points to an additional error message or is
1440 * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1441 * must be freed with g_free().
1442 */
1443int
1444sync_interface_list_open(const char* app_name, char **data, char **primary_msg,
1445 char **secondary_msg, void (*update_cb)(void))
1446{
1447 int argc;
1448 char **argv;
1449 int ret;
1450
1451 ws_debug("sync_interface_list_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1451, __func__, "sync_interface_list_open"); } } while (0)
;
1452
1453 argv = init_pipe_args(app_name, &argc);
1454
1455 if (!argv) {
1456 *primary_msg = g_strdup("We don't know where to find dumpcap..")g_strdup_inline ("We don't know where to find dumpcap..");
1457 *secondary_msg = NULL((void*)0);
1458 *data = NULL((void*)0);
1459 return -1;
1460 }
1461
1462 /* Ask for the interface list */
1463 argv = sync_pipe_add_arg(argv, &argc, "-D");
1464
1465 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1466 return ret;
1467}
1468
1469/*
1470 * Get the capabilities of an interface using dumpcap.
1471 *
1472 * On success, *data points to a buffer containing the dumpcap output,
1473 * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1474 * must be freed with g_free().
1475 *
1476 * On failure, *data is NULL, *primary_msg points to an error message,
1477 * *secondary_msg either points to an additional error message or is
1478 * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1479 * must be freed with g_free().
1480 */
1481int
1482sync_if_capabilities_open(const char* app_name, const char *ifname, bool_Bool monitor_mode, const char* auth,
1483 char **data, char **primary_msg,
1484 char **secondary_msg, void (*update_cb)(void))
1485{
1486 int argc;
1487 char **argv;
1488 int ret;
1489
1490 ws_debug("sync_if_capabilities_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1490, __func__, "sync_if_capabilities_open"); } } while (0)
;
1491
1492 argv = init_pipe_args(app_name, &argc);
1493
1494 if (!argv) {
1495 *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1496 *secondary_msg = NULL((void*)0);
1497 *data = NULL((void*)0);
1498 return -1;
1499 }
1500
1501 /* Ask for the interface capabilities */
1502 argv = sync_pipe_add_arg(argv, &argc, "-i");
1503 argv = sync_pipe_add_arg(argv, &argc, ifname);
1504 argv = sync_pipe_add_arg(argv, &argc, "-L");
1505 argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
1506 if (monitor_mode)
1507 argv = sync_pipe_add_arg(argv, &argc, "-I");
1508 if (auth) {
1509 argv = sync_pipe_add_arg(argv, &argc, "-A");
1510 argv = sync_pipe_add_arg(argv, &argc, auth);
1511 }
1512
1513 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1514 return ret;
1515}
1516
1517int
1518sync_if_list_capabilities_open(const char* app_name, GList *if_queries,
1519 char **data, char **primary_msg,
1520 char **secondary_msg, void (*update_cb)(void))
1521{
1522 int argc;
1523 char **argv;
1524 int ret;
1525 if_cap_query_t *if_cap_query;
1526
1527 ws_debug("sync_if_list_capabilities_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1527, __func__, "sync_if_list_capabilities_open"); } } while
(0)
;
1528
1529 argv = init_pipe_args(app_name, &argc);
1530
1531 if (!argv) {
1532 *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1533 *secondary_msg = NULL((void*)0);
1534 *data = NULL((void*)0);
1535 return -1;
1536 }
1537
1538 for (GList *li = if_queries; li != NULL((void*)0); li = g_list_next(li)((li) ? (((GList *)(li))->next) : ((void*)0))) {
1539 if_cap_query = (if_cap_query_t*)li->data;
1540 /* Ask for the interface capabilities */
1541 argv = sync_pipe_add_arg(argv, &argc, "-i");
1542 argv = sync_pipe_add_arg(argv, &argc, if_cap_query->name);
1543 if (if_cap_query->monitor_mode)
1544 argv = sync_pipe_add_arg(argv, &argc, "-I");
1545 if (if_cap_query->auth_username && if_cap_query->auth_password) {
1546 char sauth[256];
1547 argv = sync_pipe_add_arg(argv, &argc, "-A");
1548 snprintf(sauth, sizeof(sauth), "%s:%s",
1549 if_cap_query->auth_username,
1550 if_cap_query->auth_password);
1551 argv = sync_pipe_add_arg(argv, &argc, sauth);
1552 }
1553 }
1554 argv = sync_pipe_add_arg(argv, &argc, "-L");
1555 argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
1556
1557 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1558 return ret;
1559}
1560
1561/*
1562 * Start getting interface statistics using dumpcap. On success, read_fd
1563 * contains the file descriptor for the pipe's stdout, *msg is unchanged,
1564 * and zero is returned. On failure, *msg will point to an error message
1565 * that must be g_free()d, and -1 will be returned.
1566 * If data is not NULL, then it will also be set to point to a JSON
1567 * serialization of the list of local interfaces and their capabilities.
1568 */
1569int
1570sync_interface_stats_open(const char* app_name, int *data_read_fd, ws_process_id *fork_child, char **data, char **msg, void (*update_cb)(void))
1571{
1572 int argc;
1573 char **argv;
1574 int ret;
1575 GIOChannel *message_read_io;
1576 char *wait_msg;
1577 char *buffer = g_malloc(PIPE_BUF_SIZE((512 * 1000)+4) + 1);
1578 ssize_t nread;
1579 char indicator;
1580 int32_t exec_errno = 0;
1581 unsigned primary_msg_len;
1582 char *primary_msg_text;
1583 unsigned secondary_msg_len;
1584 /*char *secondary_msg_text;*/
1585 char *combined_msg;
1586
1587 ws_debug("sync_interface_stats_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1587, __func__, "sync_interface_stats_open"); } } while (0)
;
1
Taking true branch
2
Loop condition is false. Exiting loop
1588
1589 argv = init_pipe_args(app_name, &argc);
1590
1591 if (!argv) {
3
Assuming 'argv' is non-null
4
Taking false branch
1592 *msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1593 g_free(buffer);
1594 return -1;
1595 }
1596
1597 /* Ask for the interface statistics */
1598 argv = sync_pipe_add_arg(argv, &argc, "-S");
1599
1600 /* If requested, ask for the interface list and capabilities. */
1601 if (data) {
5
Assuming 'data' is non-null
6
Taking true branch
1602 argv = sync_pipe_add_arg(argv, &argc, "-D");
1603 argv = sync_pipe_add_arg(argv, &argc, "-L");
7
Calling 'sync_pipe_add_arg'
9
Returned allocated memory
1604 }
1605
1606#ifndef DEBUG_CHILD
1607#ifdef _WIN32
1608 argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
1609 ret = create_dummy_signal_pipe(msg);
1610 if (ret == -1) {
1611 g_free(buffer);
1612 return -1;
1613 }
1614 argv = sync_pipe_add_arg(argv, &argc, dummy_control_id);
1615#endif
1616#endif
1617 ret = sync_pipe_open_command(argv, data_read_fd, &message_read_io, NULL((void*)0),
10
Potential leak of memory pointed to by 'argv'
1618 fork_child, NULL((void*)0), msg, update_cb);
1619 if (ret == -1) {
1620 g_free(buffer);
1621 return -1;
1622 }
1623
1624 /*
1625 * We were able to set up to read dumpcap's output. Do so.
1626 *
1627 * First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
1628 */
1629 do {
1630 nread = pipe_read_block(message_read_io, &indicator, SP_MAX_MSG_LEN(512 * 1000),
1631 buffer, msg);
1632 if(nread <= 0) {
1633 /* We got a read error from the sync pipe, or we got no data at
1634 all from the sync pipe, so we're not going to be getting any
1635 data or error message from the child process. Pick up its
1636 exit status, and complain.
1637
1638 We don't have to worry about killing the child, if the sync pipe
1639 returned an error. Usually this error is caused as the child killed
1640 itself while going down. Even in the rare cases that this isn't the
1641 case, the child will get an error when writing to the broken pipe
1642 the next time, cleaning itself up then. */
1643 g_io_channel_unref(message_read_io);
1644 ws_closeclose(*data_read_fd);
1645 ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
1646 if(nread == 0) {
1647 /* We got an EOF from the sync pipe. That means that it exited
1648 before giving us any data to read. If ret is -1, we report
1649 that as a bad exit (e.g., exiting due to a signal); otherwise,
1650 we report it as a premature exit. */
1651 if (ret == -1)
1652 *msg = wait_msg;
1653 else
1654 *msg = g_strdup("Child dumpcap closed sync pipe prematurely")g_strdup_inline ("Child dumpcap closed sync pipe prematurely"
)
;
1655 } else {
1656 /* We got an error from the sync pipe. If ret is -1, report
1657 both the sync pipe I/O error and the wait error. */
1658 if (ret == -1) {
1659 combined_msg = ws_strdup_printf("%s\n\n%s", *msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", *msg, wait_msg);
1660 g_free(*msg);
1661 g_free(wait_msg);
1662 *msg = combined_msg;
1663 }
1664 }
1665 g_free(buffer);
1666 return -1;
1667 }
1668
1669 /* we got a valid message block from the child, process it */
1670 switch(indicator) {
1671
1672 case SP_EXEC_FAILED'X':
1673 /*
1674 * Exec of dumpcap failed. Get the errno for the failure.
1675 */
1676 if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
1677 ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 1677, __func__, "Invalid errno: %s", buffer); } } while (0)
;
1678 }
1679 *msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
1680 g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
;
1681
1682 /*
1683 * Pick up the child status.
1684 */
1685 char *close_msg = NULL((void*)0);
1686 sync_pipe_close_command(data_read_fd, message_read_io,
1687 fork_child, &close_msg);
1688 /*
1689 * Ignore the error from sync_pipe_close_command, presumably the one
1690 * returned by the child is more pertinent to what went wrong.
1691 */
1692 g_free(close_msg);
1693 ret = -1;
1694 break;
1695
1696 case SP_ERROR_MSG'E':
1697 /*
1698 * Error from dumpcap; there will be a primary message and a
1699 * secondary message.
1700 */
1701
1702 /* convert primary message */
1703 pipe_convert_header((unsigned char*)buffer, &indicator, &primary_msg_len);
1704 primary_msg_text = buffer+4;
1705 /* convert secondary message */
1706 pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, &indicator,
1707 &secondary_msg_len);
1708 /*secondary_msg_text = primary_msg_text + primary_msg_len + 4;*/
1709 /* the capture child will close the sync_pipe, nothing to do */
1710
1711 /*
1712 * Pick up the child status.
1713 */
1714 ret = sync_pipe_close_command(data_read_fd, message_read_io,
1715 fork_child, msg);
1716 if (ret == -1) {
1717 /*
1718 * Child process failed unexpectedly, or wait failed; msg is the
1719 * error message.
1720 */
1721 } else if (ret == WS_EXIT_NO_INTERFACES12) {
1722 /*
1723 * No interfaces were found. If that's not the
1724 * result of an error when fetching the local
1725 * interfaces, let the user know.
1726 */
1727 *msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1728 } else {
1729 /*
1730 * Child process failed, but returned the expected exit status.
1731 * Return the messages it gave us, and indicate failure.
1732 */
1733 *msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1734 ret = -1;
1735 }
1736 g_free(buffer);
1737 return ret;
1738
1739 case SP_LOG_MSG'L':
1740 /*
1741 * Log from dumpcap; pass to our log
1742 */
1743 sync_pipe_handle_log_msg(buffer);
1744 break;
1745
1746 case SP_IFACE_LIST'I':
1747 /*
1748 * Dumpcap giving us the interface list
1749 */
1750
1751 /* convert primary message */
1752 if (data) {
1753 *data = g_strdup(buffer)g_strdup_inline (buffer);
1754 }
1755 break;
1756
1757 case SP_SUCCESS'S':
1758 /* Close the message pipe. */
1759 g_io_channel_unref(message_read_io);
1760 break;
1761
1762 default:
1763 /*
1764 * Pick up the child status.
1765 */
1766 ret = sync_pipe_close_command(data_read_fd, message_read_io,
1767 fork_child, msg);
1768 if (ret == -1) {
1769 /*
1770 * Child process failed unexpectedly, or wait failed; msg is the
1771 * error message.
1772 */
1773 } else {
1774 /*
1775 * Child process returned an unknown status.
1776 */
1777 *msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x"
, indicator)
1778 indicator)wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x"
, indicator)
;
1779 ret = -1;
1780 }
1781 break;
1782 }
1783 } while (indicator != SP_SUCCESS'S' && ret != -1);
1784
1785 g_free(buffer);
1786 return ret;
1787}
1788
1789/* Close down the stats process */
1790int
1791sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, char **msg)
1792{
1793#ifdef _WIN32
1794 CloseHandle(dummy_signal_pipe);
1795 dummy_signal_pipe = NULL((void*)0);
1796#else
1797 /*
1798 * Don't bother waiting for the child. sync_pipe_close_command
1799 * does this for us on Windows.
1800 */
1801 sync_pipe_kill(*fork_child);
1802#endif
1803 return sync_pipe_close_command(read_fd, NULL((void*)0), fork_child, msg);
1804}
1805
1806/* read a number of bytes from a pipe */
1807/* (blocks until enough bytes read or an error occurs) */
1808static ssize_t
1809pipe_read_bytes(GIOChannel *pipe_io, char *bytes, size_t required, char **msg)
1810{
1811 GError *err = NULL((void*)0);
1812 size_t newly;
1813 size_t offset = 0;
1814
1815 /* This should never happen, as "required" should be no greater than 2^24. */
1816 if (required > SSIZE_MAX9223372036854775807L) {
1817 ws_debug("read from pipe %p: bytes to read %zu > %zu", pipe_io, required, SSIZE_MAX)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1817, __func__, "read from pipe %p: bytes to read %zu > %zu"
, pipe_io, required, 9223372036854775807L); } } while (0)
;
1818 *msg = ws_strdup_printf("Error reading from sync pipe: bytes to read %zu > %zu", required, SSIZE_MAX)wmem_strdup_printf(((void*)0), "Error reading from sync pipe: bytes to read %zu > %zu"
, required, 9223372036854775807L)
;
1819 return -1;
1820 }
1821 while(required) {
1822 if (g_io_channel_read_chars(pipe_io, &bytes[offset], required, &newly, &err) == G_IO_STATUS_ERROR) {
1823 if (err != NULL((void*)0)) {
1824 ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1824, __func__, "read from pipe %p: error(%u): %s", pipe_io
, err->code, err->message); } } while (0)
;
1825 *msg = ws_strdup_printf("Error reading from sync pipe: %s", err->message)wmem_strdup_printf(((void*)0), "Error reading from sync pipe: %s"
, err->message)
;
1826 g_clear_error(&err);
1827 } else {
1828 ws_debug("read from pipe %p: unknown error", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1828, __func__, "read from pipe %p: unknown error", pipe_io
); } } while (0)
;
1829 *msg = ws_strdup_printf("Error reading from sync pipe: unknown error")wmem_strdup_printf(((void*)0), "Error reading from sync pipe: unknown error"
)
;
1830 }
1831 return -1;
1832 }
1833 if (newly == 0) {
1834 /* EOF */
1835 ws_debug("read from pipe %p: EOF (capture closed?)", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1835, __func__, "read from pipe %p: EOF (capture closed?)",
pipe_io); } } while (0)
;
1836 *msg = NULL((void*)0);
1837 /*
1838 * offset is, at this point, known to be less than the value of
1839 * required passed to us, which is guaranteed to fit in an ssize_t.
1840 */
1841 return (ssize_t)offset;
1842 }
1843
1844 required -= newly;
1845 offset += newly;
1846 }
1847
1848 /*
1849 * offset is, at this point, known to be equal to the value of
1850 * required passed to us, which is guaranteed to fit in an ssize_t.
1851 */
1852 *msg = NULL((void*)0);
1853 return (ssize_t)offset;
1854}
1855
1856/*
1857 * Read a line from a pipe; similar to fgets, but doesn't block.
1858 *
1859 * XXX - just stops reading if there's nothing to be read right now;
1860 * that could conceivably mean that you don't get a complete line.
1861 */
1862int
1863sync_pipe_gets_nonblock(int pipe_fd, char *bytes, int max) {
1864 ssize_t newly;
1865 int offset = -1;
1866
1867 while(offset < max - 1) {
1868 offset++;
1869 if (! ws_pipe_data_available(pipe_fd))
1870 break;
1871 newly = ws_readread(pipe_fd, &bytes[offset], 1);
1872 if (newly == 0) {
1873 /* EOF - not necessarily an error */
1874 break;
1875 } else if (newly == -1) {
1876 /* error */
1877 ws_debug("read from pipe %d: error(%u): %s", pipe_fd, errno, g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1877, __func__, "read from pipe %d: error(%u): %s", pipe_fd
, (*__errno_location ()), g_strerror((*__errno_location ())))
; } } while (0)
;
1878 return -1;
1879 } else if (bytes[offset] == '\n') {
1880 break;
1881 }
1882 }
1883
1884 if (offset >= 0)
1885 bytes[offset] = '\0';
1886
1887 return offset;
1888}
1889
1890
1891/* convert header values (indicator and 3-byte length) */
1892static void
1893pipe_convert_header(const unsigned char *header, char *indicator, unsigned *block_len) {
1894
1895 /* convert header values */
1896 *indicator = pntohu8(&header[0]);
1897 *block_len = pntohu24(&header[1]);
1898}
1899
1900/* read a message from the sending pipe in the standard format
1901 (1-byte message indicator, 3-byte message length (excluding length
1902 and indicator field), and the rest is the message) */
1903static ssize_t
1904pipe_read_block(GIOChannel *pipe_io, char *indicator, unsigned len, char *msg,
1905 char **err_msg)
1906{
1907 unsigned required;
1908 ssize_t newly;
1909 char header[4];
1910
1911 /* read header (indicator and 3-byte length) */
1912 newly = pipe_read_bytes(pipe_io, header, 4, err_msg);
1913 if(newly != 4) {
1914 if(newly == -1) {
1915 /*
1916 * Error; *err_msg has been set.
1917 */
1918 ws_debug("read %p got an error reading header: %s", pipe_io, *err_msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1918, __func__, "read %p got an error reading header: %s", pipe_io
, *err_msg); } } while (0)
;
1919 return -1;
1920 }
1921 if(newly == 0) {
1922 /*
1923 * Immediate EOF; if the capture child exits normally, this
1924 * is an "I'm done" indication, so don't report it as an
1925 * error.
1926 */
1927 ws_debug("read %p got an EOF reading header", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1927, __func__, "read %p got an EOF reading header", pipe_io
); } } while (0)
;
1928 return 0;
1929 }
1930 /*
1931 * Short read, but not an immediate EOF.
1932 */
1933 ws_debug("read %p got premature EOF reading header: %zd", pipe_io, newly)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1933, __func__, "read %p got premature EOF reading header: %zd"
, pipe_io, newly); } } while (0)
;
1934 *err_msg = ws_strdup_printf("Premature EOF reading from sync pipe: got only %zd bytes",wmem_strdup_printf(((void*)0), "Premature EOF reading from sync pipe: got only %zd bytes"
, newly)
1935 newly)wmem_strdup_printf(((void*)0), "Premature EOF reading from sync pipe: got only %zd bytes"
, newly)
;
1936 return -1;
1937 }
1938
1939 /* convert header values */
1940 pipe_convert_header((unsigned char*)header, indicator, &required);
1941
1942 /* only indicator with no value? */
1943 if(required == 0) {
1944 ws_debug("read %p indicator: %c empty value", pipe_io, *indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1944, __func__, "read %p indicator: %c empty value", pipe_io
, *indicator); } } while (0)
;
1945 return 4;
1946 }
1947
1948 /* does the data fit into the given buffer? */
1949 if(required > len) {
1950 size_t bytes_read;
1951 GError *err = NULL((void*)0);
1952 ws_debug("read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x",do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1954, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x"
, pipe_io, required, len, header[0], header[1], header[2], header
[3]); } } while (0)
1953 pipe_io, required, len,do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1954, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x"
, pipe_io, required, len, header[0], header[1], header[2], header
[3]); } } while (0)
1954 header[0], header[1], header[2], header[3])do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1954, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x"
, pipe_io, required, len, header[0], header[1], header[2], header
[3]); } } while (0)
;
1955
1956 /* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */
1957 if (g_io_channel_read_chars(pipe_io, msg, len, &bytes_read, &err) == G_IO_STATUS_ERROR) {
1958 if (err != NULL((void*)0)) { /* error */
1959 ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1959, __func__, "read from pipe %p: error(%u): %s", pipe_io
, err->code, err->message); } } while (0)
;
1960 g_clear_error(&err);
1961 } else {
1962 ws_debug("read from pipe %p: unknown error", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1962, __func__, "read from pipe %p: unknown error", pipe_io
); } } while (0)
;
1963 }
1964 }
1965 *err_msg = ws_strdup_printf("Message %c from dumpcap with length %d > buffer size %d! Partial message: %s",wmem_strdup_printf(((void*)0), "Message %c from dumpcap with length %d > buffer size %d! Partial message: %s"
, *indicator, required, len, msg)
1966 *indicator, required, len, msg)wmem_strdup_printf(((void*)0), "Message %c from dumpcap with length %d > buffer size %d! Partial message: %s"
, *indicator, required, len, msg)
;
1967 return -1;
1968 }
1969 len = required;
1970
1971 /* read the actual block data */
1972 newly = pipe_read_bytes(pipe_io, msg, required, err_msg);
1973 if(newly == -1) {
1974 /*
1975 * Error; *err_msg has been set.
1976 */
1977 ws_debug("read %p got an error reading block data: %s", pipe_io, *err_msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1977, __func__, "read %p got an error reading block data: %s"
, pipe_io, *err_msg); } } while (0)
;
1978 return -1;
1979 }
1980
1981 /*
1982 * newly is guaranteed to be >= 0 at this point, as pipe_read_bytes()
1983 * either returns -1 on an error, a positive value <= required on
1984 * a short read, or required on a non-short read.
1985 */
1986 if((size_t)newly != required) {
1987 *err_msg = ws_strdup_printf("Unknown message from dumpcap reading data, try to show it as a string: %s",wmem_strdup_printf(((void*)0), "Unknown message from dumpcap reading data, try to show it as a string: %s"
, msg)
1988 msg)wmem_strdup_printf(((void*)0), "Unknown message from dumpcap reading data, try to show it as a string: %s"
, msg)
;
1989 return -1;
1990 }
1991
1992 /* XXX If message is "2part", the msg probably won't be sent to debug log correctly */
1993 ws_debug("read %p ok indicator: %c len: %u msg: %s", pipe_io, *indicator, len, msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1993, __func__, "read %p ok indicator: %c len: %u msg: %s",
pipe_io, *indicator, len, msg); } } while (0)
;
1994 *err_msg = NULL((void*)0);
1995 return newly + 4;
1996}
1997
1998
1999/* There's stuff to read from the sync pipe, meaning the child has sent
2000 us a message, or the sync pipe has closed, meaning the child has
2001 closed it (perhaps because it exited). */
2002static gboolean
2003sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
2004{
2005 int ret;
2006 char *buffer = g_malloc(SP_MAX_MSG_LEN(512 * 1000) + 1);
2007 ssize_t nread;
2008 char indicator;
2009 int32_t exec_errno = 0;
2010 unsigned primary_len;
2011 char *primary_msg;
2012 unsigned secondary_len;
2013 char *secondary_msg;
2014 char *wait_msg, *combined_msg;
2015 uint32_t npackets = 0;
2016
2017 nread = pipe_read_block(pipe_io, &indicator, SP_MAX_MSG_LEN(512 * 1000), buffer,
2018 &primary_msg);
2019 if(nread <= 0) {
2020 /* We got a read error, or a bad message, or an EOF, from the sync pipe.
2021
2022 If we got a read error or a bad message, nread is -1 and
2023 primary_msg is set to point to an error message. We don't
2024 have to worry about killing the child; usually this error
2025 is caused as the child killed itself while going down.
2026 Even in the rare cases that this isn't the case, the child
2027 will get an error when writing to the broken pipe the next time,
2028 cleaning itself up then.
2029
2030 If we got an EOF, nread is 0 and primary_msg isn't set. This
2031 is an indication that the capture is finished. */
2032 ret = sync_pipe_wait_for_child(cap_session->fork_child, &wait_msg);
2033 if(nread == 0) {
2034 /* We got an EOF from the sync pipe. That means that the capture
2035 child exited, and not in the middle of a message; we treat
2036 that as an indication that it's done, and only report an
2037 error if ret is -1, in which case wait_msg is the error
2038 message. */
2039 if (ret == -1)
2040 primary_msg = wait_msg;
2041 } else {
2042 /* We got an error from the sync pipe. If ret is -1, report
2043 both the sync pipe I/O error and the wait error. */
2044 if (ret == -1) {
2045 combined_msg = ws_strdup_printf("%s\n\n%s", primary_msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", primary_msg, wait_msg
)
;
2046 g_free(primary_msg);
2047 g_free(wait_msg);
2048 primary_msg = combined_msg;
2049 }
2050 }
2051
2052 /* No more child process. */
2053 cap_session->fork_child = WS_INVALID_PID-1;
2054 cap_session->fork_child_status = ret;
2055
2056#ifdef _WIN32
2057 ws_closeclose(cap_session->signal_pipe_write_fd);
2058#endif
2059 cap_session->capture_opts->closed_msg = primary_msg;
2060 if (extcap_session_stop(cap_session)) {
2061 capture_process_finished(cap_session);
2062 } else {
2063 extcap_request_stop(cap_session);
2064 }
2065 g_free(buffer);
2066 return false0;
2067 }
2068
2069 /* we got a valid message block from the child, process it */
2070 switch(indicator) {
2071 case SP_FILE'F':
2072 if(!cap_session->new_file(cap_session, buffer)) {
2073 ws_debug("file failed, closing capture")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2073, __func__, "file failed, closing capture"); } } while (
0)
;
2074
2075 /* We weren't able to open the new capture file; user has been
2076 alerted. The sync pipe will close after we return false. */
2077
2078 /* The child has sent us a filename which we couldn't open.
2079
2080 This could mean that the child is creating and deleting files
2081 (ring buffer mode) faster than we can handle it.
2082
2083 That should only be the case for very fast file switches;
2084 We can't do much more than telling the child to stop.
2085 (This is the "emergency brake" if the user e.g. wants to
2086 switch files every second).
2087
2088 This can also happen if the user specified "-", meaning
2089 "standard output", as the capture file. */
2090 sync_pipe_stop(cap_session);
2091 cap_session->closed(cap_session, NULL((void*)0));
2092 g_free(buffer);
2093 return false0;
2094 }
2095 break;
2096 case SP_PACKET_COUNT'P':
2097 if (!ws_strtou32(buffer, NULL((void*)0), &npackets)) {
2098 ws_warning("Invalid packets number: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2098, __func__, "Invalid packets number: %s", buffer); } } while
(0)
;
2099 }
2100 ws_debug("new packets %u", npackets)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2100, __func__, "new packets %u", npackets); } } while (0)
;
2101 cap_session->count += npackets;
2102 cap_session->new_packets(cap_session, npackets);
2103 break;
2104 case SP_EXEC_FAILED'X':
2105 /*
2106 * Exec of dumpcap failed. Get the errno for the failure.
2107 */
2108 if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
2109 ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2109, __func__, "Invalid errno: %s", buffer); } } while (0)
;
2110 }
2111 primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
2112 g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
;
2113 cap_session->error(cap_session, primary_msg, NULL((void*)0));
2114 /* the capture child will close the sync_pipe, nothing to do for now */
2115 /* (an error message doesn't mean we have to stop capturing) */
2116 break;
2117 case SP_ERROR_MSG'E':
2118 /* convert primary message */
2119 pipe_convert_header((unsigned char*)buffer, &indicator, &primary_len);
2120 primary_msg = buffer+4;
2121 /* convert secondary message */
2122 pipe_convert_header((unsigned char*)primary_msg + primary_len, &indicator, &secondary_len);
2123 secondary_msg = primary_msg + primary_len + 4;
2124 /* message output */
2125 cap_session->error(cap_session, primary_msg, secondary_msg);
2126 /* the capture child will close the sync_pipe, nothing to do for now */
2127 /* (an error message doesn't mean we have to stop capturing) */
2128 break;
2129 case SP_LOG_MSG'L':
2130 /*
2131 * Log from dumpcap; pass to our log
2132 */
2133 sync_pipe_handle_log_msg(buffer);
2134 break;
2135 case SP_BAD_FILTER'B': {
2136 const char *message=NULL((void*)0);
2137 uint32_t indx = 0;
2138 const char* end;
2139
2140 if (ws_strtou32(buffer, &end, &indx) && end[0] == ':') {
2141 message = end + 1;
2142 }
2143
2144 cap_session->cfilter_error(cap_session, indx, message);
2145 /* the capture child will close the sync_pipe, nothing to do for now */
2146 break;
2147 }
2148 case SP_DROPS'D': {
2149 const char *name = NULL((void*)0);
2150 const char* end;
2151 uint32_t num = 0;
2152
2153 if (ws_strtou32(buffer, &end, &num) && end[0] == ':') {
2154 name = end + 1;
2155 }
2156
2157 cap_session->drops(cap_session, num, name);
2158 break;
2159 }
2160 default:
2161 if (g_ascii_isprint(indicator)((g_ascii_table[(guchar) (indicator)] & G_ASCII_PRINT) !=
0)
)
2162 ws_warning("Unknown indicator '%c'", indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2162, __func__, "Unknown indicator '%c'", indicator); } } while
(0)
;
2163 else
2164 ws_warning("Unknown indicator '\\x%02x", indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2164, __func__, "Unknown indicator '\\x%02x", indicator); }
} while (0)
;
2165 break;
2166 }
2167
2168 g_free(buffer);
2169 return true1;
2170}
2171
2172
2173
2174/*
2175 * dumpcap is exiting; wait for it to exit. On success, *msgp is
2176 * unchanged, and the exit status of dumpcap is returned. On
2177 * failure (which includes "dumpcap exited due to being killed by
2178 * a signal or an exception"), *msgp points to an error message
2179 * for the failure, and -1 is returned. In the latter case, *msgp
2180 * must be freed with g_free().
2181 */
2182static int
2183sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp)
2184{
2185 int fork_child_status;
2186#ifndef _WIN32
2187 int retry_waitpid = 3;
2188#endif
2189 int ret = -1;
2190 int64_t start_time;
2191 double elapsed;
2192
2193 start_time = g_get_monotonic_time();
2194
2195 ws_debug("wait till child closed")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2195, __func__, "wait till child closed"); } } while (0)
;
2196 ws_assert(fork_child != WS_INVALID_PID)do { if ((1) && !(fork_child != -1)) ws_log_fatal_full
("Capture", LOG_LEVEL_ERROR, "capture/capture_sync.c", 2196, __func__
, "assertion failed: %s", "fork_child != -1"); } while (0)
;
2197
2198 *msgp = NULL((void*)0); /* assume no error */
2199#ifdef _WIN32
2200 if (_cwait(&fork_child_status, (intptr_t) fork_child, _WAIT_CHILD) == -1) {
2201 *msgp = ws_strdup_printf("Error from cwait(): %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Error from cwait(): %s", g_strerror
((*__errno_location ())))
;
2202 ret = -1;
2203 } else {
2204 /*
2205 * The child exited; return its exit status. Do not treat this as
2206 * an error.
2207 */
2208 ret = fork_child_status;
2209 if ((fork_child_status & 0xC0000000) == ERROR_SEVERITY_ERROR) {
2210 /* Probably an exception code */
2211 *msgp = ws_strdup_printf("Child dumpcap process died: %s",wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s"
, win32strexception(fork_child_status))
2212 win32strexception(fork_child_status))wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s"
, win32strexception(fork_child_status))
;
2213 ret = -1;
2214 }
2215 }
2216#else
2217 while (--retry_waitpid >= 0) {
2218 if (waitpid(fork_child, &fork_child_status, 0) != -1) {
2219 /* waitpid() succeeded */
2220 if (WIFEXITED(fork_child_status)(((fork_child_status) & 0x7f) == 0)) {
2221 /*
2222 * The child exited; return its exit status. Do not treat this as
2223 * an error.
2224 */
2225 ret = WEXITSTATUS(fork_child_status)(((fork_child_status) & 0xff00) >> 8);
2226 } else if (WIFSTOPPED(fork_child_status)(((fork_child_status) & 0xff) == 0x7f)) {
2227 /* It stopped, rather than exiting. "Should not happen." */
2228 *msgp = ws_strdup_printf("Child dumpcap process stopped: %s",wmem_strdup_printf(((void*)0), "Child dumpcap process stopped: %s"
, sync_pipe_signame((((fork_child_status) & 0xff00) >>
8)))
2229 sync_pipe_signame(WSTOPSIG(fork_child_status)))wmem_strdup_printf(((void*)0), "Child dumpcap process stopped: %s"
, sync_pipe_signame((((fork_child_status) & 0xff00) >>
8)))
;
2230 ret = -1;
2231 } else if (WIFSIGNALED(fork_child_status)(((signed char) (((fork_child_status) & 0x7f) + 1) >>
1) > 0)
) {
2232 /* It died with a signal. */
2233 *msgp = ws_strdup_printf("Child dumpcap process died: %s%s",wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s"
, sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status
) & 0x80) ? " - core dumped" : "")
2234 sync_pipe_signame(WTERMSIG(fork_child_status)),wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s"
, sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status
) & 0x80) ? " - core dumped" : "")
2235 WCOREDUMP(fork_child_status) ? " - core dumped" : "")wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s"
, sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status
) & 0x80) ? " - core dumped" : "")
;
2236 ret = -1;
2237 } else {
2238 /* What? It had to either have exited, or stopped, or died with
2239 a signal; what happened here? */
2240 *msgp = ws_strdup_printf("Bad status from waitpid(): %#o",wmem_strdup_printf(((void*)0), "Bad status from waitpid(): %#o"
, fork_child_status)
2241 fork_child_status)wmem_strdup_printf(((void*)0), "Bad status from waitpid(): %#o"
, fork_child_status)
;
2242 ret = -1;
2243 }
2244 } else {
2245 /* waitpid() failed */
2246 if (errno(*__errno_location ()) == EINTR4) {
2247 /*
2248 * Signal interrupted waitpid().
2249 *
2250 * If it's SIGALRM, we just want to keep waiting, in case
2251 * there's some timer using it (e.g., in a GUI toolkit).
2252 *
2253 * If you ^C TShark (or Wireshark), that should deliver
2254 * SIGINT to dumpcap as well. dumpcap catches SIGINT,
2255 * and should clean up and exit, so we should eventually
2256 * see that and clean up and terminate.
2257 *
2258 * If we're sent a SIGTERM, we should (and do) catch it,
2259 * and TShark, at least, calls sync_pipe_stop(). which
2260 * kills dumpcap, so we should eventually see that and
2261 * clean up and terminate.
2262 */
2263 ws_warning("waitpid returned EINTR. retrying.")do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2263, __func__, "waitpid returned EINTR. retrying."); } } while
(0)
;
2264 continue;
2265 } else if (errno(*__errno_location ()) == ECHILD10) {
2266 /*
2267 * The process identified by fork_child either doesn't
2268 * exist any more or isn't our child process (anymore?).
2269 *
2270 * echld might have already reaped the child.
2271 */
2272 ret = fetch_dumpcap_pid ? 0 : -1;
2273 } else {
2274 /* Unknown error. */
2275 *msgp = ws_strdup_printf("Error from waitpid(): %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Error from waitpid(): %s", g_strerror
((*__errno_location ())))
;
2276 ret = -1;
2277 }
2278 }
2279 break;
2280 }
2281#endif
2282
2283 elapsed = (g_get_monotonic_time() - start_time) / 1e6;
2284 ws_debug("capture child closed after %.3fs", elapsed)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2284, __func__, "capture child closed after %.3fs", elapsed
); } } while (0)
;
2285 return ret;
2286}
2287
2288
2289#ifndef _WIN32
2290/* convert signal to corresponding name */
2291static const char *
2292sync_pipe_signame(int sig)
2293{
2294 const char *sigmsg;
2295 static char sigmsg_buf[6+1+3+1];
2296
2297 switch (sig) {
2298
2299 case SIGHUP1:
2300 sigmsg = "Hangup";
2301 break;
2302
2303 case SIGINT2:
2304 sigmsg = "Interrupted";
2305 break;
2306
2307 case SIGQUIT3:
2308 sigmsg = "Quit";
2309 break;
2310
2311 case SIGILL4:
2312 sigmsg = "Illegal instruction";
2313 break;
2314
2315 case SIGTRAP5:
2316 sigmsg = "Trace trap";
2317 break;
2318
2319 case SIGABRT6:
2320 sigmsg = "Abort";
2321 break;
2322
2323 case SIGFPE8:
2324 sigmsg = "Arithmetic exception";
2325 break;
2326
2327 case SIGKILL9:
2328 sigmsg = "Killed";
2329 break;
2330
2331 case SIGBUS7:
2332 sigmsg = "Bus error";
2333 break;
2334
2335 case SIGSEGV11:
2336 sigmsg = "Segmentation violation";
2337 break;
2338
2339 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
2340 Linux is POSIX compliant. These are not POSIX-defined signals ---
2341 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
2342
2343 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
2344 were omitted from POSIX.1 because their behavior is
2345 implementation dependent and could not be adequately catego-
2346 rized. Conforming implementations may deliver these sig-
2347 nals, but must document the circumstances under which they
2348 are delivered and note any restrictions concerning their
2349 delivery.''
2350
2351 So we only check for SIGSYS on those systems that happen to
2352 implement them (a system can be POSIX-compliant and implement
2353 them, it's just that POSIX doesn't *require* a POSIX-compliant
2354 system to implement them).
2355 */
2356
2357#ifdef SIGSYS31
2358 case SIGSYS31:
2359 sigmsg = "Bad system call";
2360 break;
2361#endif
2362
2363 case SIGPIPE13:
2364 sigmsg = "Broken pipe";
2365 break;
2366
2367 case SIGALRM14:
2368 sigmsg = "Alarm clock";
2369 break;
2370
2371 case SIGTERM15:
2372 sigmsg = "Terminated";
2373 break;
2374
2375 default:
2376 /* Returning a static buffer is ok in the context we use it here */
2377 snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
2378 sigmsg = sigmsg_buf;
2379 break;
2380 }
2381 return sigmsg;
2382}
2383#endif
2384
2385
2386#ifdef _WIN32
2387
2388static int create_dummy_signal_pipe(char **msg) {
2389 char *dummy_signal_pipe_name;
2390
2391 if (dummy_signal_pipe != NULL((void*)0)) return 0;
2392
2393 if (!dummy_control_id) {
2394 dummy_control_id = ws_strdup_printf("%ld.dummy", GetCurrentProcessId())wmem_strdup_printf(((void*)0), "%ld.dummy", GetCurrentProcessId
())
;
2395 }
2396
2397 /* Create the signal pipe */
2398 dummy_signal_pipe_name = ws_strdup_printf(SIGNAL_PIPE_FORMAT, dummy_control_id)wmem_strdup_printf(((void*)0), SIGNAL_PIPE_FORMAT, dummy_control_id
)
;
2399 dummy_signal_pipe = CreateNamedPipe(utf_8to16(dummy_signal_pipe_name),
2400 PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL((void*)0));
2401 g_free(dummy_signal_pipe_name);
2402 if (dummy_signal_pipe == INVALID_HANDLE_VALUE) {
2403 *msg = ws_strdup_printf("Couldn't create signal pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s"
, win32strerror(GetLastError()))
2404 win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s"
, win32strerror(GetLastError()))
;
2405 return -1;
2406 }
2407 return 0;
2408}
2409
2410/* tell the child through the signal pipe that we want to quit the capture */
2411static void
2412signal_pipe_capquit_to_child(capture_session *cap_session)
2413{
2414 const char quit_msg[] = "QUIT";
2415 int ret;
2416
2417 ws_debug("signal_pipe_capquit_to_child")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2417, __func__, "signal_pipe_capquit_to_child"); } } while (
0)
;
2418
2419 /* it doesn't matter *what* we send here, the first byte will stop the capture */
2420 /* simply sending a "QUIT" string */
2421 /*sync_pipe_write_string_msg(cap_session->signal_pipe_write_fd, SP_QUIT, quit_msg);*/
2422 ret = ws_writewrite(cap_session->signal_pipe_write_fd, quit_msg, sizeof quit_msg);
2423 if(ret == -1) {
2424 ws_warning("%d header: error %s", cap_session->signal_pipe_write_fd, win32strerror(GetLastError()))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2424, __func__, "%d header: error %s", cap_session->signal_pipe_write_fd
, win32strerror(GetLastError())); } } while (0)
;
2425 }
2426}
2427#endif
2428
2429
2430/* user wants to stop the capture run */
2431void
2432sync_pipe_stop(capture_session *cap_session)
2433{
2434 if (cap_session->fork_child != WS_INVALID_PID-1) {
2435#ifndef _WIN32
2436 /* send the SIGINT signal to close the capture child gracefully. */
2437 int sts = kill(cap_session->fork_child, SIGINT2);
2438 if (sts != 0) {
2439 ws_warning("Sending SIGINT to child failed: %s\n", g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2439, __func__, "Sending SIGINT to child failed: %s\n", g_strerror
((*__errno_location ()))); } } while (0)
;
2440 }
2441#else
2442#define STOP_SLEEP_TIME 500 /* ms */
2443 DWORD status;
2444
2445 /* First, use the special signal pipe to try to close the capture child
2446 * gracefully.
2447 */
2448 signal_pipe_capquit_to_child(cap_session);
2449
2450 /* Next, wait for the process to exit on its own */
2451 status = WaitForSingleObject((HANDLE) cap_session->fork_child, STOP_SLEEP_TIME);
2452
2453 /* Force the issue. */
2454 if (status != WAIT_OBJECT_0) {
2455 ws_warning("sync_pipe_stop: forcing child to exit")do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2455, __func__, "sync_pipe_stop: forcing child to exit"); }
} while (0)
;
2456 sync_pipe_kill(cap_session->fork_child);
2457 }
2458#endif
2459 }
2460}
2461
2462
2463/* Wireshark has to exit, force the capture child to close */
2464void
2465sync_pipe_kill(ws_process_id fork_child)
2466{
2467 if (fork_child != WS_INVALID_PID-1) {
2468#ifndef _WIN32
2469 int sts = kill(fork_child, SIGTERM15); /* SIGTERM so it can clean up if necessary */
2470 if (sts != 0) {
2471 ws_warning("Sending SIGTERM to child failed: %s\n", g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2471, __func__, "Sending SIGTERM to child failed: %s\n", g_strerror
((*__errno_location ()))); } } while (0)
;
2472 }
2473#else
2474 /* Remark: This is not the preferred method of closing a process!
2475 * the clean way would be getting the process id of the child process,
2476 * then getting window handle hWnd of that process (using EnumChildWindows),
2477 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
2478 *
2479 * Unfortunately, I don't know how to get the process id from the
2480 * handle. OpenProcess will get an handle (not a window handle)
2481 * from the process ID; it will not get a window handle from the
2482 * process ID. (How could it? A process can have more than one
2483 * window. For that matter, a process might have *no* windows,
2484 * as a process running dumpcap, the normal child process program,
2485 * probably does.)
2486 *
2487 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
2488 * running in the same console; that's not necessarily the case for
2489 * us, as we might not be running in a console.
2490 * And this also will require to have the process id.
2491 */
2492 TerminateProcess((HANDLE) (fork_child), 0);
2493
2494#endif
2495 }
2496}
2497
2498void capture_sync_set_fetch_dumpcap_pid_cb(void(*cb)(ws_process_id pid)) {
2499 fetch_dumpcap_pid = cb;
2500}
2501
2502#endif /* HAVE_LIBPCAP */