SMB2: dissect new signing capability negotiate context
[wireshark-sm.git] / extcap.c
blob59436f09e5f087f2e35687e66b31f6fc9e0ffebf
1 /* extcap.c
3 * Routines for extcap external capture
4 * Copyright 2013, Mike Ryan <mikeryan@lacklustre.net>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <config.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
19 #ifdef _WIN32
20 #include <windows.h>
21 #include <process.h>
22 #include <time.h>
23 #else
24 /* Include for unlink */
25 #include <unistd.h>
26 #endif
28 #include <sys/types.h>
29 #ifdef HAVE_SYS_WAIT_H
30 #include <sys/wait.h>
31 #endif
33 #include <glib.h>
34 #include <log.h>
36 #include <epan/prefs.h>
38 #include "ui/iface_toolbar.h"
40 #include <wsutil/file_util.h>
41 #include <wsutil/filesystem.h>
42 #include <wsutil/ws_pipe.h>
43 #include <wsutil/ws_printf.h>
44 #include <wsutil/tempfile.h>
46 #include "capture_opts.h"
48 #include "extcap.h"
49 #include "extcap_parser.h"
51 #include "version_info.h"
53 static void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data);
55 /* internal container, for all the extcap executables that have been found.
56 * Will be reset if extcap_clear_interfaces() is being explicitly called
57 * and is being used for printing information about all extcap interfaces found,
58 * as well as storing all sub-interfaces
60 static GHashTable * _loaded_interfaces = NULL;
62 /* Internal container, which maps each ifname to the tool providing it, for faster
63 * lookup. The key and string value are owned by this table.
65 static GHashTable * _tool_for_ifname = NULL;
67 /* internal container, for all the extcap executables that have been found
68 * and that provides a toolbar with controls to be added to a Interface Toolbar
70 static GHashTable *_toolbars = NULL;
72 /* internal container, to map preference names to pointers that hold preference
73 * values. These ensure that preferences can survive extcap if garbage
74 * collection, and does not lead to dangling pointers in the prefs subsystem.
76 static GHashTable *_extcap_prefs_dynamic_vals = NULL;
78 typedef struct _extcap_callback_info_t
80 const gchar * extcap;
81 const gchar * ifname;
82 gchar * output;
83 void * data;
84 gchar ** err_str;
85 } extcap_callback_info_t;
87 /* Callback definition for extcap_foreach */
88 typedef gboolean(*extcap_cb_t)(extcap_callback_info_t info_structure);
90 /** GThreadPool does not support pushing new work from a thread while waiting
91 * for the thread pool to finish. This data structure tracks ongoing work.
92 * See https://gitlab.gnome.org/GNOME/glib/issues/1598 */
93 typedef struct thread_pool {
94 GThreadPool *pool;
95 gint count; /**< Number of tasks that have not finished. */
96 GCond cond;
97 GMutex data_mutex;
98 } thread_pool_t;
101 * Callback definition for extcap_run_all, invoked with a thread pool (to
102 * schedule new tasks), an opaque data parameter, and the output from last task
103 * (or NULL if it failed). The output must be freed by the callback function.
104 * The implementation MUST be thread-safe.
106 typedef void (*extcap_run_cb_t)(thread_pool_t *pool, void *data, char *output);
108 typedef struct extcap_run_task {
109 const char *extcap_path;
110 char **argv; /**< NULL-terminated arguments list, freed when the task is completed. */
111 extcap_run_cb_t output_cb;
112 void *data; /** Parameter to be passed to output_cb. */
113 } extcap_run_task_t;
115 typedef struct extcap_iface_info {
116 char *ifname; /**< Interface name. */
117 char *output; /**< Output of --extcap-config. */
118 } extcap_iface_info_t;
120 typedef struct extcap_run_extcaps_info {
121 char *extcap_path; /**< Extcap program path, MUST be the first member. */
122 char *output; /**< Output of --extcap-interfaces. */
123 guint num_interfaces; /**< Number of discovered interfaces. */
124 extcap_iface_info_t *iface_infos; /**< Per-interface information. */
125 } extcap_run_extcaps_info_t;
128 static void extcap_load_interface_list(void);
130 /* Used for lazily loading our interfaces. */
131 static void extcap_ensure_all_interfaces_loaded(void) {
132 if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
133 extcap_load_interface_list();
136 static gboolean
137 thread_pool_push(thread_pool_t *pool, gpointer data, GError **error)
139 g_mutex_lock(&pool->data_mutex);
140 ++pool->count;
141 g_mutex_unlock(&pool->data_mutex);
142 return g_thread_pool_push(pool->pool, data, error);
145 static void
146 thread_pool_wait(thread_pool_t *pool)
148 g_mutex_lock(&pool->data_mutex);
149 while (pool->count != 0) {
150 g_cond_wait(&pool->cond, &pool->data_mutex);
152 g_mutex_unlock(&pool->data_mutex);
155 static GHashTable *
156 extcap_loaded_interfaces(void)
158 if (prefs.capture_no_extcap)
159 return NULL;
161 extcap_ensure_all_interfaces_loaded();
163 return _loaded_interfaces;
166 void
167 extcap_clear_interfaces(void)
169 if ( _loaded_interfaces )
170 g_hash_table_destroy(_loaded_interfaces);
171 _loaded_interfaces = NULL;
173 if ( _tool_for_ifname )
174 g_hash_table_destroy(_tool_for_ifname);
175 _tool_for_ifname = NULL;
178 static gint
179 compare_tools(gconstpointer a, gconstpointer b)
181 return g_strcmp0((*(extcap_info *const *)a)->basename, (*(extcap_info *const *)b)->basename);
184 void
185 extcap_get_descriptions(plugin_description_callback callback, void *callback_data)
187 extcap_ensure_all_interfaces_loaded();
189 GHashTable * tools = extcap_loaded_interfaces();
190 GPtrArray *tools_array = g_ptr_array_new();
192 if (tools && g_hash_table_size(tools) > 0) {
193 GList * keys = g_hash_table_get_keys(tools);
194 GList * walker = g_list_first(keys);
195 while (walker && walker->data) {
196 extcap_info * tool = (extcap_info *)g_hash_table_lookup(tools, walker->data);
197 if (tool) {
198 g_ptr_array_add(tools_array, tool);
200 walker = g_list_next(walker);
202 g_list_free(keys);
205 g_ptr_array_sort(tools_array, compare_tools);
207 for (guint i = 0; i < tools_array->len; i++) {
208 extcap_info *tool = (extcap_info *)tools_array->pdata[i];
209 callback(tool->basename, tool->version, "extcap", tool->full_path, callback_data);
212 g_ptr_array_free(tools_array, TRUE);
215 static void
216 print_extcap_description(const char *basename, const char *version,
217 const char *description, const char *filename,
218 void *user_data _U_)
220 ws_debug_printf("%-16s\t%s\t%s\t%s\n", basename, version, description, filename);
223 void
224 extcap_dump_all(void)
226 extcap_get_descriptions(print_extcap_description, NULL);
229 static GSList *
230 extcap_get_extcap_paths_from_dir(GSList * list, const char * dirname)
232 GDir * dir;
233 const char * file;
235 GSList * paths = list;
237 if ((dir = g_dir_open(dirname, 0, NULL)) != NULL) {
238 while ((file = g_dir_read_name(dir)) != NULL) {
239 /* full path to extcap binary */
240 gchar *extcap_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname, file);
241 /* treat anything executable as an extcap binary */
242 if (g_file_test(extcap_path, G_FILE_TEST_IS_REGULAR) &&
243 g_file_test(extcap_path, G_FILE_TEST_IS_EXECUTABLE)) {
244 paths = g_slist_append(paths, extcap_path);
245 } else {
246 g_free(extcap_path);
250 g_dir_close(dir);
253 return paths;
257 * Obtains a list of extcap program paths. Use g_slist_free_full(paths, g_free)
258 * to destroy the list.
260 static GSList *
261 extcap_get_extcap_paths(void)
263 GSList *paths = NULL;
265 char *persconffile_path = get_persconffile_path("extcap", FALSE);
266 paths = extcap_get_extcap_paths_from_dir(paths, persconffile_path);
267 g_free(persconffile_path);
269 paths = extcap_get_extcap_paths_from_dir(paths, get_extcap_dir());
271 return paths;
274 static extcap_interface *
275 extcap_find_interface_for_ifname(const gchar *ifname)
277 extcap_interface * result = NULL;
279 if ( !ifname || ! _tool_for_ifname || ! _loaded_interfaces )
280 return result;
282 gchar * extcap_util = (gchar *)g_hash_table_lookup(_tool_for_ifname, ifname);
283 if ( ! extcap_util )
284 return result;
286 extcap_info * element = (extcap_info *)g_hash_table_lookup(_loaded_interfaces, extcap_util);
287 if ( ! element )
288 return result;
290 GList * walker = element->interfaces;
291 while ( walker && walker->data && ! result )
293 extcap_interface * interface = (extcap_interface *)walker->data;
294 if ( g_strcmp0(interface->call, ifname) == 0 )
296 result = interface;
297 break;
300 walker = g_list_next ( walker );
303 return result;
306 static void
307 extcap_free_toolbar(gpointer data)
309 if (!data)
311 return;
314 iface_toolbar *toolbar = (iface_toolbar *)data;
316 g_free(toolbar->menu_title);
317 g_free(toolbar->help);
318 g_list_free_full(toolbar->ifnames, g_free);
319 g_list_free_full(toolbar->controls, (GDestroyNotify)extcap_free_toolbar_control);
320 g_free(toolbar);
323 static gchar *
324 extcap_if_executable(const gchar *ifname)
326 extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
327 return interface != NULL ? interface->extcap_path : NULL;
330 static gboolean
331 extcap_iface_toolbar_add(const gchar *extcap, iface_toolbar *toolbar_entry)
333 char *toolname;
334 gboolean ret = FALSE;
336 if (!extcap || !toolbar_entry)
338 return ret;
341 toolname = g_path_get_basename(extcap);
343 if (!g_hash_table_lookup(_toolbars, toolname))
345 g_hash_table_insert(_toolbars, g_strdup(toolname), toolbar_entry);
346 ret = TRUE;
349 g_free(toolname);
350 return ret;
353 static gchar **
354 extcap_convert_arguments_to_array(GList * arguments)
356 gchar ** result = NULL;
357 if ( arguments )
359 GList * walker = g_list_first(arguments);
360 int cnt = 0;
362 result = (gchar **) g_malloc0(sizeof(gchar *) * (g_list_length(arguments)));
364 while(walker)
366 result[cnt] = g_strdup((const gchar *)walker->data);
367 walker = g_list_next(walker);
368 cnt++;
371 return result;
374 static void extcap_free_array(gchar ** args, int argc)
376 int cnt = 0;
378 for ( cnt = 0; cnt < argc; cnt++ )
379 g_free(args[cnt]);
380 g_free(args);
383 static void
384 extcap_free_extcaps_info_array(extcap_run_extcaps_info_t *infos, guint count)
386 for (guint i = 0; i < count; i++) {
387 g_free(infos[i].extcap_path);
388 g_free(infos[i].output);
389 for (guint j = 0; j < infos[i].num_interfaces; j++) {
390 extcap_iface_info_t *iface_info = &infos[i].iface_infos[j];
391 g_free(iface_info->ifname);
392 g_free(iface_info->output);
394 g_free(infos[i].iface_infos);
396 g_free(infos);
399 static void
400 extcap_run_one(const extcap_interface *interface, GList *arguments, extcap_cb_t cb, void *user_data, char **err_str)
402 const char *dirname = get_extcap_dir();
403 gchar **args = extcap_convert_arguments_to_array(arguments);
404 int cnt = g_list_length(arguments);
405 gchar *command_output;
406 if (ws_pipe_spawn_sync(dirname, interface->extcap_path, cnt, args, &command_output)) {
407 extcap_callback_info_t cb_info = {
408 .ifname = interface->call,
409 .extcap = interface->extcap_path,
410 .output = command_output,
411 .data = user_data,
412 .err_str = err_str,
414 cb(cb_info);
415 g_free(command_output);
417 extcap_free_array(args, cnt);
420 /** Thread callback to run an extcap program and pass its output. */
421 static void
422 extcap_thread_callback(gpointer data, gpointer user_data)
424 extcap_run_task_t *task = (extcap_run_task_t *)data;
425 thread_pool_t *pool = (thread_pool_t *)user_data;
426 const char *dirname = get_extcap_dir();
428 char *command_output;
429 if (ws_pipe_spawn_sync(dirname, task->extcap_path, g_strv_length(task->argv), task->argv, &command_output)) {
430 task->output_cb(pool, task->data, command_output);
431 } else {
432 task->output_cb(pool, task->data, NULL);
434 g_strfreev(task->argv);
435 g_free(task);
437 // Notify when all tasks are completed and no new subtasks were created.
438 g_mutex_lock(&pool->data_mutex);
439 if (--pool->count == 0) {
440 g_cond_signal(&pool->cond);
442 g_mutex_unlock(&pool->data_mutex);
446 * Run all extcap programs with the given arguments list, invoke the callback to
447 * do some processing and return the results.
449 * @param [IN] argv NULL-terminated arguments list.
450 * @param [IN] output_cb Thread callback function that receives the output.
451 * @param [IN] data_size Size of the per-program information that will be returned.
452 * @param [OUT] count Size of the returned array.
453 * @return Array of information or NULL if there are none. The first member of
454 * each element (char *extcap_path) must be freed.
456 static gpointer
457 extcap_run_all(const char *argv[], extcap_run_cb_t output_cb, gsize data_size, guint *count)
459 /* Need enough space for at least 'extcap_path'. */
460 g_assert(data_size >= sizeof(char *));
462 GSList *paths = extcap_get_extcap_paths();
463 int i = 0;
464 #if GLIB_CHECK_VERSION(2,36,0)
465 int max_threads = (int)g_get_num_processors();
466 #else
467 // If the number of processors is unavailable, just use some sane maximum.
468 // extcap should not be CPU bound, so -1 could also be used for unlimited.
469 int max_threads = 8;
470 #endif
472 if (!paths) {
473 *count = 0;
474 return NULL;
477 guint64 start_time = g_get_monotonic_time();
478 guint paths_count = g_slist_length(paths);
479 /* GSList is not thread-safe, so pre-allocate an array instead. */
480 gpointer infos = g_malloc0_n(paths_count, data_size);
482 thread_pool_t pool;
483 pool.pool = g_thread_pool_new(extcap_thread_callback, &pool, max_threads, FALSE, NULL);
484 pool.count = 0;
485 g_cond_init(&pool.cond);
486 g_mutex_init(&pool.data_mutex);
488 for (GSList *path = paths; path; path = g_slist_next(path), i++) {
489 extcap_run_task_t *task = g_new0(extcap_run_task_t, 1);
491 task->extcap_path = (char *)path->data;
492 task->argv = g_strdupv((char **)argv);
493 task->output_cb = output_cb;
494 task->data = ((char *)infos) + (i * data_size);
495 *((char **)task->data) = (char *)path->data;
497 thread_pool_push(&pool, task, NULL);
499 g_slist_free(paths); /* Note: the contents are transferred to 'infos'. */
501 /* Wait for all (sub)tasks to complete. */
502 thread_pool_wait(&pool);
504 g_mutex_clear(&pool.data_mutex);
505 g_cond_clear(&pool.cond);
506 g_thread_pool_free(pool.pool, FALSE, TRUE);
508 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap: completed discovery of %d tools in %.3fms",
509 paths_count, (g_get_monotonic_time() - start_time) / 1000.0);
510 *count = paths_count;
511 return infos;
514 static void extcap_free_dlt(gpointer d, gpointer user_data _U_)
516 if (d == NULL)
518 return;
521 g_free(((extcap_dlt *)d)->name);
522 g_free(((extcap_dlt *)d)->display);
523 g_free(d);
526 static void extcap_free_dlts(GList *dlts)
528 g_list_foreach(dlts, extcap_free_dlt, NULL);
529 g_list_free(dlts);
532 static gboolean cb_dlt(extcap_callback_info_t cb_info)
534 GList *dlts = NULL, *temp = NULL;
536 if_capabilities_t *caps;
537 GList *linktype_list = NULL;
538 data_link_info_t *data_link_info;
539 extcap_dlt *dlt_item;
541 dlts = extcap_parse_dlts(cb_info.output);
542 temp = dlts;
544 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", cb_info.extcap);
547 * Allocate the interface capabilities structure.
549 caps = (if_capabilities_t *) g_malloc(sizeof * caps);
550 caps->can_set_rfmon = FALSE;
551 caps->timestamp_types = NULL;
553 while (dlts)
555 dlt_item = (extcap_dlt *)dlts->data;
556 if (dlt_item)
558 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
559 " DLT %d name=\"%s\" display=\"%s\" ", dlt_item->number,
560 dlt_item->name, dlt_item->display);
562 data_link_info = g_new(data_link_info_t, 1);
563 data_link_info->dlt = dlt_item->number;
564 data_link_info->name = g_strdup(dlt_item->name);
565 data_link_info->description = g_strdup(dlt_item->display);
566 linktype_list = g_list_append(linktype_list, data_link_info);
569 dlts = g_list_next(dlts);
572 /* Check to see if we built a list */
573 if (linktype_list != NULL && cb_info.data != NULL)
575 caps->data_link_types = linktype_list;
576 *(if_capabilities_t **) cb_info.data = caps;
578 else
580 if (cb_info.err_str)
582 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, " returned no DLTs");
583 *(cb_info.err_str) = g_strdup("Extcap returned no DLTs");
585 g_free(caps);
588 extcap_free_dlts(temp);
590 return FALSE;
593 if_capabilities_t *
594 extcap_get_if_dlts(const gchar *ifname, char **err_str)
596 GList * arguments = NULL;
597 if_capabilities_t *caps = NULL;
599 if (err_str != NULL)
601 *err_str = NULL;
604 /* Update the extcap interfaces and get a list of their if_infos */
605 extcap_ensure_all_interfaces_loaded();
607 extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
608 if (interface)
610 arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_LIST_DLTS));
611 arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_INTERFACE));
612 arguments = g_list_append(arguments, g_strdup(ifname));
614 extcap_run_one(interface, arguments, cb_dlt, &caps, err_str);
616 g_list_free_full(arguments, g_free);
619 return caps;
622 static void extcap_free_interface(gpointer i)
625 extcap_interface *interface = (extcap_interface *)i;
627 if (i == NULL)
629 return;
632 g_free(interface->call);
633 g_free(interface->display);
634 g_free(interface->version);
635 g_free(interface->help);
636 g_free(interface->extcap_path);
637 g_free(interface);
640 static void extcap_free_interfaces(GList *interfaces)
642 if (interfaces == NULL)
644 return;
647 g_list_free_full(interfaces, extcap_free_interface);
650 static gint
651 if_info_compare(gconstpointer a, gconstpointer b)
653 gint comp = 0;
654 const if_info_t *if_a = (const if_info_t *)a;
655 const if_info_t *if_b = (const if_info_t *)b;
657 if ((comp = g_strcmp0(if_a->name, if_b->name)) == 0)
659 return g_strcmp0(if_a->friendly_name, if_b->friendly_name);
662 return comp;
665 gchar *
666 extcap_get_help_for_ifname(const char *ifname)
668 extcap_ensure_all_interfaces_loaded();
670 extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
671 return interface != NULL ? interface->help : NULL;
674 GList *
675 append_extcap_interface_list(GList *list, char **err_str _U_)
677 GList *interface_list = NULL;
678 extcap_interface *data = NULL;
679 GList *ifutilkeys_head = NULL, *ifutilkeys = NULL;
681 if (prefs.capture_no_extcap)
682 return list;
684 /* Update the extcap interfaces and get a list of their if_infos */
685 extcap_ensure_all_interfaces_loaded();
687 ifutilkeys_head = g_hash_table_get_keys(_loaded_interfaces);
688 ifutilkeys = ifutilkeys_head;
689 while ( ifutilkeys && ifutilkeys->data )
691 extcap_info * extinfo =
692 (extcap_info *) g_hash_table_lookup(_loaded_interfaces, (gchar *)ifutilkeys->data);
693 GList * walker = extinfo->interfaces;
694 while ( walker && walker->data )
696 interface_list = g_list_append(interface_list, walker->data);
697 walker = g_list_next(walker);
700 ifutilkeys = g_list_next(ifutilkeys);
702 g_list_free(ifutilkeys_head);
704 /* Sort that list */
705 interface_list = g_list_sort(interface_list, if_info_compare);
707 /* Append the interfaces in that list to the list we're handed. */
708 while (interface_list != NULL)
710 GList *entry = g_list_first(interface_list);
711 data = (extcap_interface *)entry->data;
712 interface_list = g_list_delete_link(interface_list, entry);
714 if_info_t * if_info = g_new0(if_info_t, 1);
715 if_info->name = g_strdup(data->call);
716 if_info->friendly_name = g_strdup(data->display);
718 if_info->type = IF_EXTCAP;
720 if_info->extcap = g_strdup(data->extcap_path);
722 list = g_list_append(list, if_info);
725 return list;
728 void extcap_register_preferences(void)
730 if (prefs.capture_no_extcap)
731 return;
733 module_t *dev_module = prefs_find_module("extcap");
735 if (!dev_module)
737 return;
740 // Will load information about extcaps and their supported config.
741 extcap_ensure_all_interfaces_loaded();
745 * Releases the dynamic preference value pointers. Must not be called before
746 * prefs_cleanup since these pointers could still be in use.
748 void extcap_cleanup(void)
750 if (_extcap_prefs_dynamic_vals)
751 g_hash_table_destroy(_extcap_prefs_dynamic_vals);
753 if (_loaded_interfaces)
754 g_hash_table_destroy(_loaded_interfaces);
756 if (_tool_for_ifname)
757 g_hash_table_destroy(_tool_for_ifname);
761 * Obtains a pointer which can store a value for the given preference name.
762 * The preference name that can be passed to the prefs API is stored into
763 * 'prefs_name'.
765 * Extcap interfaces (and their preferences) are dynamic, they can be created
766 * and destroyed at will. Thus their data structures are insufficient to pass to
767 * the preferences APIs which require pointers which are valid until the
768 * preferences are removed (at exit).
770 static gchar **extcap_prefs_dynamic_valptr(const char *name, char **pref_name)
772 gchar **valp;
773 if (!_extcap_prefs_dynamic_vals)
775 /* Initialize table only as needed, most preferences are not dynamic */
776 _extcap_prefs_dynamic_vals = g_hash_table_new_full(g_str_hash, g_str_equal,
777 g_free, g_free);
779 if (!g_hash_table_lookup_extended(_extcap_prefs_dynamic_vals, name,
780 (gpointer *)pref_name, (gpointer *)&valp))
782 /* New dynamic pref, allocate, initialize and store. */
783 valp = g_new0(gchar *, 1);
784 *pref_name = g_strdup(name);
785 g_hash_table_insert(_extcap_prefs_dynamic_vals, *pref_name, valp);
787 return valp;
790 void extcap_free_if_configuration(GList *list, gboolean free_args)
792 GList *elem, *sl;
794 for (elem = g_list_first(list); elem; elem = elem->next)
796 if (elem->data != NULL)
798 sl = g_list_first((GList *)elem->data);
799 if (free_args)
801 extcap_free_arg_list(sl);
803 else
805 g_list_free(sl);
809 g_list_free(list);
812 struct preference *
813 extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg *arg)
815 struct preference *pref = NULL;
817 extcap_ensure_all_interfaces_loaded();
819 GRegex *regex_name = g_regex_new("[-]+", G_REGEX_RAW, (GRegexMatchFlags) 0, NULL);
820 GRegex *regex_ifname = g_regex_new("(?![a-zA-Z0-9_]).", G_REGEX_RAW, (GRegexMatchFlags) 0, NULL);
821 if (regex_name && regex_ifname)
823 if (prefs_find_module("extcap"))
825 gchar *pref_name = g_regex_replace(regex_name, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL);
826 gchar *ifname_underscore = g_regex_replace(regex_ifname, ifname, strlen(ifname), 0, "_", (GRegexMatchFlags) 0, NULL);
827 gchar *ifname_lowercase = g_ascii_strdown(ifname_underscore, -1);
828 gchar *pref_ifname = g_strconcat(ifname_lowercase, ".", pref_name, NULL);
830 pref = prefs_find_preference(prefs_find_module("extcap"), pref_ifname);
832 g_free(pref_name);
833 g_free(ifname_underscore);
834 g_free(ifname_lowercase);
835 g_free(pref_ifname);
838 if (regex_name)
840 g_regex_unref(regex_name);
842 if (regex_ifname)
844 g_regex_unref(regex_ifname);
847 return pref;
850 static gboolean cb_preference(extcap_callback_info_t cb_info)
852 GList *arguments = NULL;
853 GList **il = (GList **) cb_info.data;
854 module_t *dev_module = NULL;
856 arguments = extcap_parse_args(cb_info.output);
858 dev_module = prefs_find_module("extcap");
860 if (dev_module)
862 GList *walker = arguments;
864 GRegex *regex_name = g_regex_new("[-]+", G_REGEX_RAW, (GRegexMatchFlags) 0, NULL);
865 GRegex *regex_ifname = g_regex_new("(?![a-zA-Z0-9_]).", G_REGEX_RAW, (GRegexMatchFlags) 0, NULL);
866 if (regex_name && regex_ifname)
868 while (walker != NULL)
870 extcap_arg *arg = (extcap_arg *)walker->data;
871 arg->device_name = g_strdup(cb_info.ifname);
873 if (arg->save)
875 struct preference *pref = NULL;
877 gchar *pref_name = g_regex_replace(regex_name, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL);
878 gchar *ifname_underscore = g_regex_replace(regex_ifname, cb_info.ifname, strlen(cb_info.ifname), 0, "_", (GRegexMatchFlags) 0, NULL);
879 gchar *ifname_lowercase = g_ascii_strdown(ifname_underscore, -1);
880 gchar *pref_ifname = g_strconcat(ifname_lowercase, ".", pref_name, NULL);
882 if ((pref = prefs_find_preference(dev_module, pref_ifname)) == NULL)
884 char *pref_name_for_prefs;
885 char *pref_title = wmem_strdup(wmem_epan_scope(), arg->display);
887 arg->pref_valptr = extcap_prefs_dynamic_valptr(pref_ifname, &pref_name_for_prefs);
888 /* Set an initial value if any (the string will be copied at registration) */
889 if (arg->default_complex)
891 *arg->pref_valptr = arg->default_complex->_val;
894 prefs_register_string_preference(dev_module, pref_name_for_prefs,
895 pref_title, pref_title, (const char **)arg->pref_valptr);
897 else
899 /* Been here before, restore stored value */
900 if (arg->pref_valptr == NULL)
902 arg->pref_valptr = (gchar**)g_hash_table_lookup(_extcap_prefs_dynamic_vals, pref_ifname);
906 g_free(pref_name);
907 g_free(ifname_underscore);
908 g_free(ifname_lowercase);
909 g_free(pref_ifname);
912 walker = g_list_next(walker);
915 if (regex_name)
917 g_regex_unref(regex_name);
919 if (regex_ifname)
921 g_regex_unref(regex_ifname);
925 *il = g_list_append(*il, arguments);
927 /* By returning false, extcap_foreach will break on first found */
928 return TRUE;
931 GList *
932 extcap_get_if_configuration(const char *ifname)
934 GList * arguments = NULL;
935 GList *ret = NULL;
937 extcap_ensure_all_interfaces_loaded();
939 extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
940 if (interface)
942 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap path %s",
943 get_extcap_dir());
945 arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_CONFIG));
946 arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_INTERFACE));
947 arguments = g_list_append(arguments, g_strdup(ifname));
949 extcap_run_one(interface, arguments, cb_preference, &ret, NULL);
951 g_list_free_full(arguments, g_free);
954 return ret;
957 static gboolean cb_reload_preference(extcap_callback_info_t cb_info)
959 GList *arguments = NULL, * walker = NULL;
960 GList **il = (GList **) cb_info.data;
962 arguments = extcap_parse_values(cb_info.output);
964 walker = g_list_first(arguments);
965 while (walker != NULL)
967 extcap_value * val = (extcap_value *)walker->data;
968 *il = g_list_append(*il, val);
969 walker = g_list_next(walker);
971 g_list_free(arguments);
973 /* By returning false, extcap_foreach will break on first found */
974 return FALSE;
977 GList *
978 extcap_get_if_configuration_values(const char * ifname, const char * argname, GHashTable *arguments)
980 GList * args = NULL;
981 GList *ret = NULL;
983 extcap_ensure_all_interfaces_loaded();
985 extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
986 if (interface)
988 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap path %s",
989 get_extcap_dir());
991 args = g_list_append(args, g_strdup(EXTCAP_ARGUMENT_CONFIG));
992 args = g_list_append(args, g_strdup(EXTCAP_ARGUMENT_INTERFACE));
993 args = g_list_append(args, g_strdup(ifname));
994 args = g_list_append(args, g_strdup(EXTCAP_ARGUMENT_RELOAD_OPTION));
995 args = g_list_append(args, g_strdup(argname));
997 if ( arguments )
999 GList * keys = g_hash_table_get_keys(arguments);
1000 GList * walker = g_list_first(keys);
1001 while ( walker )
1003 const gchar * key_data = (const gchar *)walker->data;
1004 args = g_list_append(args, g_strdup(key_data));
1005 args = g_list_append(args, g_strdup((const gchar *)g_hash_table_lookup(arguments, key_data)));
1006 walker = g_list_next(walker);
1008 g_list_free(keys);
1011 extcap_run_one(interface, args, cb_reload_preference, &ret, NULL);
1013 g_list_free_full(args, g_free);
1016 return ret;
1019 gboolean
1020 extcap_has_configuration(const char *ifname, gboolean is_required)
1022 GList *arguments = 0;
1023 GList *walker = 0, * item = 0;
1024 gboolean found = FALSE;
1026 extcap_ensure_all_interfaces_loaded();
1028 arguments = extcap_get_if_configuration(ifname);
1029 walker = g_list_first(arguments);
1031 while (walker != NULL && !found)
1033 item = g_list_first((GList *)(walker->data));
1034 while (item != NULL && !found)
1036 if ((extcap_arg *)(item->data) != NULL)
1038 extcap_arg *arg = (extcap_arg *)(item->data);
1039 /* Should required options be present, or any kind of options */
1040 if (!is_required)
1042 found = TRUE;
1044 else if (arg->is_required)
1046 const gchar *stored = NULL;
1047 const gchar *defval = NULL;
1049 if (arg->pref_valptr != NULL)
1051 stored = *arg->pref_valptr;
1054 if (arg->default_complex != NULL && arg->default_complex->_val != NULL)
1056 defval = arg->default_complex->_val;
1059 if (arg->is_required)
1061 /* If stored and defval is identical and the argument is required,
1062 * configuration is needed */
1063 if (defval && stored && g_strcmp0(stored, defval) == 0)
1065 found = TRUE;
1067 else if (!defval && (!stored || !*stored))
1069 found = TRUE;
1073 if (arg->arg_type == EXTCAP_ARG_FILESELECT)
1075 if (arg->fileexists && !(file_exists(defval) || file_exists(stored)))
1077 found = TRUE;
1083 item = item->next;
1085 walker = walker->next;
1087 extcap_free_if_configuration(arguments, TRUE);
1089 return found;
1092 static gboolean cb_verify_filter(extcap_callback_info_t cb_info)
1094 extcap_filter_status *status = (extcap_filter_status *)cb_info.data;
1095 size_t output_size, i;
1097 output_size = strlen(cb_info.output);
1098 if (output_size == 0) {
1099 *status = EXTCAP_FILTER_VALID;
1100 } else {
1101 *status = EXTCAP_FILTER_INVALID;
1102 for (i = 0; i < output_size; i++) {
1103 if (cb_info.output[i] == '\n' || cb_info.output[i] == '\r') {
1104 cb_info.output[i] = '\0';
1105 break;
1108 *cb_info.err_str = g_strdup(cb_info.output);
1111 return TRUE;
1114 extcap_filter_status
1115 extcap_verify_capture_filter(const char *ifname, const char *filter, gchar **err_str)
1117 GList * arguments = NULL;
1118 extcap_filter_status status = EXTCAP_FILTER_UNKNOWN;
1120 extcap_ensure_all_interfaces_loaded();
1122 extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
1123 if (interface)
1125 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap path %s",
1126 get_extcap_dir());
1128 arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_CAPTURE_FILTER));
1129 arguments = g_list_append(arguments, g_strdup(filter));
1130 arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_INTERFACE));
1131 arguments = g_list_append(arguments, g_strdup(ifname));
1133 extcap_run_one(interface, arguments, cb_verify_filter, &status, err_str);
1134 g_list_free_full(arguments, g_free);
1137 return status;
1140 gboolean
1141 extcap_has_toolbar(const char *ifname)
1143 if (!iface_toolbar_use())
1145 return FALSE;
1148 extcap_ensure_all_interfaces_loaded();
1150 GList *toolbar_list = g_hash_table_get_values (_toolbars);
1151 for (GList *walker = toolbar_list; walker; walker = walker->next)
1153 iface_toolbar *toolbar = (iface_toolbar *) walker->data;
1154 if (g_list_find_custom(toolbar->ifnames, ifname, (GCompareFunc) g_strcmp0))
1156 g_list_free(toolbar_list);
1157 return TRUE;
1161 g_list_free(toolbar_list);
1162 return FALSE;
1165 void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
1167 interface_options *interface_opts;
1168 ws_pipe_t *pipedata;
1169 guint icnt = 0;
1170 gboolean overwrite_exitcode;
1171 gchar *buffer;
1172 #define STDERR_BUFFER_SIZE 1024
1174 for (icnt = 0; icnt < capture_opts->ifaces->len; icnt++)
1176 interface_opts = &g_array_index(capture_opts->ifaces, interface_options,
1177 icnt);
1179 /* skip native interfaces */
1180 if (interface_opts->if_type != IF_EXTCAP)
1182 continue;
1185 overwrite_exitcode = FALSE;
1187 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1188 "Extcap [%s] - Cleaning up fifo: %s; PID: %d", interface_opts->name,
1189 interface_opts->extcap_fifo, interface_opts->extcap_pid);
1190 #ifdef _WIN32
1191 if (interface_opts->extcap_pipe_h != INVALID_HANDLE_VALUE)
1193 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1194 "Extcap [%s] - Closing pipe", interface_opts->name);
1195 FlushFileBuffers(interface_opts->extcap_pipe_h);
1196 DisconnectNamedPipe(interface_opts->extcap_pipe_h);
1197 CloseHandle(interface_opts->extcap_pipe_h);
1198 interface_opts->extcap_pipe_h = INVALID_HANDLE_VALUE;
1200 if (interface_opts->extcap_control_in_h != INVALID_HANDLE_VALUE)
1202 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1203 "Extcap [%s] - Closing control_in pipe", interface_opts->name);
1204 FlushFileBuffers(interface_opts->extcap_control_in_h);
1205 DisconnectNamedPipe(interface_opts->extcap_control_in_h);
1206 CloseHandle(interface_opts->extcap_control_in_h);
1207 interface_opts->extcap_control_in_h = INVALID_HANDLE_VALUE;
1209 if (interface_opts->extcap_control_out_h != INVALID_HANDLE_VALUE)
1211 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1212 "Extcap [%s] - Closing control_out pipe", interface_opts->name);
1213 FlushFileBuffers(interface_opts->extcap_control_out_h);
1214 DisconnectNamedPipe(interface_opts->extcap_control_out_h);
1215 CloseHandle(interface_opts->extcap_control_out_h);
1216 interface_opts->extcap_control_out_h = INVALID_HANDLE_VALUE;
1218 #else
1219 if (interface_opts->extcap_fifo != NULL && file_exists(interface_opts->extcap_fifo))
1221 /* the fifo will not be freed here, but with the other capture_opts in capture_sync */
1222 ws_unlink(interface_opts->extcap_fifo);
1223 interface_opts->extcap_fifo = NULL;
1225 if (interface_opts->extcap_control_in && file_exists(interface_opts->extcap_control_in))
1227 ws_unlink(interface_opts->extcap_control_in);
1228 interface_opts->extcap_control_in = NULL;
1230 if (interface_opts->extcap_control_out && file_exists(interface_opts->extcap_control_out))
1232 ws_unlink(interface_opts->extcap_control_out);
1233 interface_opts->extcap_control_out = NULL;
1235 /* Send termination signal to child. On Linux and OSX the child will not notice that the
1236 * pipe has been closed before writing to the pipe.
1238 if (interface_opts->extcap_pid != WS_INVALID_PID)
1240 kill(interface_opts->extcap_pid, SIGTERM);
1242 #endif
1243 /* Maybe the client closed and removed fifo, but ws should check if
1244 * pid should be closed */
1245 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1246 "Extcap [%s] - Closing spawned PID: %d", interface_opts->name,
1247 interface_opts->extcap_pid);
1249 pipedata = (ws_pipe_t *) interface_opts->extcap_pipedata;
1250 if (pipedata)
1252 if (pipedata->stderr_fd > 0)
1254 buffer = (gchar *)g_malloc0(STDERR_BUFFER_SIZE + 1);
1255 ws_read_string_from_pipe(ws_get_pipe_handle(pipedata->stderr_fd), buffer, STDERR_BUFFER_SIZE + 1);
1256 if (strlen(buffer) > 0)
1258 pipedata->stderr_msg = g_strdup(buffer);
1259 pipedata->exitcode = 1;
1261 g_free(buffer);
1264 #ifndef _WIN32
1265 /* Final child watch may not have been called */
1266 if (interface_opts->extcap_child_watch > 0)
1268 extcap_child_watch_cb(pipedata->pid, 0, capture_opts);
1269 /* it will have changed in extcap_child_watch_cb */
1270 interface_opts = &g_array_index(capture_opts->ifaces, interface_options,
1271 icnt);
1273 #endif
1275 if (pipedata->stderr_msg != NULL)
1277 overwrite_exitcode = TRUE;
1280 if (overwrite_exitcode || pipedata->exitcode != 0)
1282 if (pipedata->stderr_msg != NULL)
1284 if (*errormsg == NULL)
1286 *errormsg = g_strdup_printf("Error by extcap pipe: %s", pipedata->stderr_msg);
1288 else
1290 gchar *temp = g_strconcat(*errormsg, "\nError by extcap pipe: " , pipedata->stderr_msg, NULL);
1291 g_free(*errormsg);
1292 *errormsg = temp;
1294 g_free(pipedata->stderr_msg);
1297 pipedata->stderr_msg = NULL;
1298 pipedata->exitcode = 0;
1302 if (interface_opts->extcap_child_watch > 0)
1304 g_source_remove(interface_opts->extcap_child_watch);
1305 interface_opts->extcap_child_watch = 0;
1308 if (pipedata) {
1309 if (pipedata->stdout_fd > 0)
1311 ws_close(pipedata->stdout_fd);
1314 if (pipedata->stderr_fd > 0)
1316 ws_close(pipedata->stderr_fd);
1319 if (interface_opts->extcap_pid != WS_INVALID_PID)
1321 ws_pipe_close(pipedata);
1322 interface_opts->extcap_pid = WS_INVALID_PID;
1324 g_free(pipedata);
1325 interface_opts->extcap_pipedata = NULL;
1331 static gboolean
1332 extcap_add_arg_and_remove_cb(gpointer key, gpointer value, gpointer data)
1334 GPtrArray *args = (GPtrArray *)data;
1336 if (key != NULL)
1338 g_ptr_array_add(args, g_strdup((const gchar *)key));
1340 if (value != NULL)
1342 g_ptr_array_add(args, g_strdup((const gchar *)value));
1345 return TRUE;
1348 return FALSE;
1351 void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data)
1353 guint i;
1354 interface_options *interface_opts;
1355 ws_pipe_t *pipedata = NULL;
1356 capture_options *capture_opts = (capture_options *)(user_data);
1358 if (capture_opts == NULL || capture_opts->ifaces == NULL || capture_opts->ifaces->len == 0)
1360 return;
1363 /* Close handle to child process. */
1364 g_spawn_close_pid(pid);
1366 /* Update extcap_pid in interface options structure. */
1367 for (i = 0; i < capture_opts->ifaces->len; i++)
1369 interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
1370 if (interface_opts->extcap_pid == pid)
1372 pipedata = (ws_pipe_t *)interface_opts->extcap_pipedata;
1373 if (pipedata != NULL)
1375 interface_opts->extcap_pid = WS_INVALID_PID;
1376 pipedata->exitcode = 0;
1377 #ifndef _WIN32
1378 if (WIFEXITED(status))
1380 if (WEXITSTATUS(status) != 0)
1382 pipedata->exitcode = WEXITSTATUS(status);
1385 else
1387 pipedata->exitcode = G_SPAWN_ERROR_FAILED;
1389 #else
1390 if (status != 0)
1392 pipedata->exitcode = status;
1394 #endif
1395 if (status == 0 && pipedata->stderr_msg != NULL)
1397 pipedata->exitcode = 1;
1400 g_source_remove(interface_opts->extcap_child_watch);
1401 interface_opts->extcap_child_watch = 0;
1402 break;
1407 static
1408 GPtrArray *extcap_prepare_arguments(interface_options *interface_opts)
1410 GPtrArray *result = NULL;
1412 if (interface_opts->if_type == IF_EXTCAP)
1414 result = g_ptr_array_new();
1416 #define add_arg(X) g_ptr_array_add(result, g_strdup(X))
1418 add_arg(interface_opts->extcap);
1419 add_arg(EXTCAP_ARGUMENT_RUN_CAPTURE);
1420 add_arg(EXTCAP_ARGUMENT_INTERFACE);
1421 add_arg(interface_opts->name);
1422 if (interface_opts->cfilter && strlen(interface_opts->cfilter) > 0)
1424 add_arg(EXTCAP_ARGUMENT_CAPTURE_FILTER);
1425 add_arg(interface_opts->cfilter);
1427 add_arg(EXTCAP_ARGUMENT_RUN_PIPE);
1428 add_arg(interface_opts->extcap_fifo);
1429 if (interface_opts->extcap_control_in)
1431 add_arg(EXTCAP_ARGUMENT_CONTROL_OUT);
1432 add_arg(interface_opts->extcap_control_in);
1434 if (interface_opts->extcap_control_out)
1436 add_arg(EXTCAP_ARGUMENT_CONTROL_IN);
1437 add_arg(interface_opts->extcap_control_out);
1439 if (interface_opts->extcap_args == NULL || g_hash_table_size(interface_opts->extcap_args) == 0)
1441 /* User did not perform interface configuration.
1443 * Check if there are any boolean flags that are set by default
1444 * and hence their argument should be added.
1446 GList *arglist;
1447 GList *elem;
1449 arglist = extcap_get_if_configuration(interface_opts->name);
1450 for (elem = g_list_first(arglist); elem; elem = elem->next)
1452 GList *arg_list;
1453 extcap_arg *arg_iter;
1455 if (elem->data == NULL)
1457 continue;
1460 arg_list = g_list_first((GList *)elem->data);
1461 while (arg_list != NULL)
1463 const gchar *stored = NULL;
1464 /* In case of boolflags only first element in arg_list is relevant. */
1465 arg_iter = (extcap_arg *)(arg_list->data);
1466 if (arg_iter->pref_valptr != NULL)
1468 stored = *arg_iter->pref_valptr;
1471 if (arg_iter->arg_type == EXTCAP_ARG_BOOLFLAG)
1473 if (!stored && extcap_complex_get_bool(arg_iter->default_complex))
1475 add_arg(arg_iter->call);
1477 else if (g_strcmp0(stored, "true") == 0)
1479 add_arg(arg_iter->call);
1482 else
1484 if (stored && strlen(stored) > 0) {
1485 add_arg(arg_iter->call);
1486 add_arg(stored);
1490 arg_list = arg_list->next;
1494 extcap_free_if_configuration(arglist, TRUE);
1496 else
1498 g_hash_table_foreach_remove(interface_opts->extcap_args, extcap_add_arg_and_remove_cb, result);
1500 add_arg(NULL);
1501 #undef add_arg
1505 return result;
1508 static void ptr_array_free(gpointer data, gpointer user_data _U_)
1510 g_free(data);
1513 #ifdef _WIN32
1514 static gboolean extcap_create_pipe(const gchar *ifname, gchar **fifo, HANDLE *handle_out, const gchar *pipe_prefix)
1516 gchar timestr[ 14 + 1 ];
1517 time_t current_time;
1518 gchar *pipename = NULL;
1519 SECURITY_ATTRIBUTES security;
1521 /* create pipename */
1522 current_time = time(NULL);
1524 * XXX - we trust Windows not to return a time before the Epoch here,
1525 * so we won't get a null pointer back from localtime().
1527 strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", localtime(&current_time));
1528 pipename = g_strconcat("\\\\.\\pipe\\", pipe_prefix, "_", ifname, "_", timestr, NULL);
1530 /* Security struct to enable Inheritable HANDLE */
1531 memset(&security, 0, sizeof(SECURITY_ATTRIBUTES));
1532 security.nLength = sizeof(SECURITY_ATTRIBUTES);
1533 security.bInheritHandle = TRUE;
1534 security.lpSecurityDescriptor = NULL;
1536 /* create a namedPipe */
1537 *handle_out = CreateNamedPipe(
1538 utf_8to16(pipename),
1539 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
1540 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1541 1, 65536, 65536,
1542 300,
1543 &security);
1545 if (*handle_out == INVALID_HANDLE_VALUE)
1547 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nError creating pipe => (%d)", GetLastError());
1548 g_free (pipename);
1549 return FALSE;
1551 else
1553 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nWireshark Created pipe =>(%s) handle (%" G_GUINTPTR_FORMAT ")", pipename, *handle_out);
1554 *fifo = g_strdup(pipename);
1557 return TRUE;
1559 #else
1560 static gboolean extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe_prefix)
1562 gchar *temp_name = NULL;
1563 int fd = 0;
1565 gchar *pfx = g_strconcat(pipe_prefix, "_", ifname, NULL);
1566 if ((fd = create_tempfile(&temp_name, pfx, NULL, NULL)) < 0)
1568 g_free(pfx);
1569 return FALSE;
1571 g_free(pfx);
1573 ws_close(fd);
1575 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1576 "Extcap - Creating fifo: %s", temp_name);
1578 if (file_exists(temp_name))
1580 ws_unlink(temp_name);
1583 if (mkfifo(temp_name, 0600) == 0)
1585 *fifo = temp_name;
1587 else
1589 g_free(temp_name);
1591 return TRUE;
1593 #endif
1595 /* call mkfifo for each extcap,
1596 * returns FALSE if there's an error creating a FIFO */
1597 gboolean
1598 extcap_init_interfaces(capture_options *capture_opts)
1600 guint i;
1601 interface_options *interface_opts;
1602 ws_pipe_t *pipedata;
1604 extcap_ensure_all_interfaces_loaded();
1606 for (i = 0; i < capture_opts->ifaces->len; i++)
1608 GPtrArray *args = NULL;
1609 GPid pid = WS_INVALID_PID;
1611 interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
1613 /* skip native interfaces */
1614 if (interface_opts->if_type != IF_EXTCAP)
1616 continue;
1619 /* create control pipes if having toolbar */
1620 if (extcap_has_toolbar(interface_opts->name))
1622 extcap_create_pipe(interface_opts->name, &interface_opts->extcap_control_in,
1623 #ifdef _WIN32
1624 &interface_opts->extcap_control_in_h,
1625 #endif
1626 EXTCAP_CONTROL_IN_PREFIX);
1627 extcap_create_pipe(interface_opts->name, &interface_opts->extcap_control_out,
1628 #ifdef _WIN32
1629 &interface_opts->extcap_control_out_h,
1630 #endif
1631 EXTCAP_CONTROL_OUT_PREFIX);
1634 /* create pipe for fifo */
1635 if (!extcap_create_pipe(interface_opts->name, &interface_opts->extcap_fifo,
1636 #ifdef _WIN32
1637 &interface_opts->extcap_pipe_h,
1638 #endif
1639 EXTCAP_PIPE_PREFIX))
1641 return FALSE;
1645 /* Create extcap call */
1646 args = extcap_prepare_arguments(interface_opts);
1648 pipedata = g_new0(ws_pipe_t, 1);
1650 pid = ws_pipe_spawn_async(pipedata, args);
1652 g_ptr_array_foreach(args, ptr_array_free, NULL);
1653 g_ptr_array_free(args, TRUE);
1655 if (pid == WS_INVALID_PID)
1657 g_free(pipedata);
1658 continue;
1661 ws_close(pipedata->stdin_fd);
1662 interface_opts->extcap_pid = pid;
1664 interface_opts->extcap_child_watch =
1665 g_child_watch_add(pid, extcap_child_watch_cb, (gpointer)capture_opts);
1667 #ifdef _WIN32
1668 /* On Windows, wait for extcap to connect to named pipe.
1669 * Some extcaps will present UAC screen to user.
1670 * 30 second timeout should be reasonable timeout for extcap to
1671 * connect to named pipe (including user interaction).
1672 * Wait on multiple object in case of extcap termination
1673 * without opening pipe.
1675 if (pid != WS_INVALID_PID)
1677 HANDLE pipe_handles[3];
1678 int num_pipe_handles = 1;
1679 pipe_handles[0] = interface_opts->extcap_pipe_h;
1681 if (extcap_has_toolbar(interface_opts->name))
1683 pipe_handles[1] = interface_opts->extcap_control_in_h;
1684 pipe_handles[2] = interface_opts->extcap_control_out_h;
1685 num_pipe_handles += 2;
1688 ws_pipe_wait_for_pipe(pipe_handles, num_pipe_handles, pid);
1690 #endif
1692 interface_opts->extcap_pipedata = (gpointer) pipedata;
1695 return TRUE;
1698 /************* EXTCAP LOAD INTERFACE LIST ***************
1700 * The following code handles loading and reloading the interface list. It is explicitly
1701 * kept separate from the rest
1705 static void
1706 extcap_free_interface_info(gpointer data)
1708 extcap_info *info = (extcap_info *)data;
1710 g_free(info->basename);
1711 g_free(info->full_path);
1712 g_free(info->version);
1713 g_free(info->help);
1715 extcap_free_interfaces(info->interfaces);
1717 g_free(info);
1720 static extcap_info *
1721 extcap_ensure_interface(const gchar * toolname, gboolean create_if_nonexist)
1723 extcap_info * element = 0;
1725 if ( prefs.capture_no_extcap )
1726 return NULL;
1728 if ( ! toolname )
1729 return element;
1731 if ( ! _loaded_interfaces )
1732 _loaded_interfaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_interface);
1734 element = (extcap_info *) g_hash_table_lookup(_loaded_interfaces, toolname );
1735 if ( element )
1736 return NULL;
1738 if ( ! element && create_if_nonexist )
1740 g_hash_table_insert(_loaded_interfaces, g_strdup(toolname), g_new0(extcap_info, 1));
1741 element = (extcap_info *) g_hash_table_lookup(_loaded_interfaces, toolname );
1744 return element;
1747 extcap_info *
1748 extcap_get_tool_by_ifname(const gchar *ifname)
1750 extcap_ensure_all_interfaces_loaded();
1752 if ( ifname && _tool_for_ifname )
1754 gchar * toolname = (gchar *)g_hash_table_lookup(_tool_for_ifname, ifname);
1755 if ( toolname )
1756 return extcap_ensure_interface(toolname, FALSE);
1759 return NULL;
1762 extcap_info *
1763 extcap_get_tool_info(const gchar * toolname)
1765 extcap_ensure_all_interfaces_loaded();
1767 return extcap_ensure_interface(toolname, FALSE);
1770 static void remove_extcap_entry(gpointer entry, gpointer data _U_)
1772 extcap_interface *int_iter = (extcap_interface*)entry;
1774 if (int_iter->if_type == EXTCAP_SENTENCE_EXTCAP)
1775 extcap_free_interface(entry);
1778 static void
1779 process_new_extcap(const char *extcap, char *output)
1781 GList * interfaces = NULL, * control_items = NULL, * walker = NULL;
1782 extcap_interface * int_iter = NULL;
1783 extcap_info * element = NULL;
1784 iface_toolbar * toolbar_entry = NULL;
1785 gchar * toolname = g_path_get_basename(extcap);
1787 GList * interface_keys = g_hash_table_get_keys(_loaded_interfaces);
1789 /* Load interfaces from utility */
1790 interfaces = extcap_parse_interfaces(output, &control_items);
1792 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Loading interface list for %s ", extcap);
1794 /* Seems, that there where no interfaces to be loaded */
1795 if ( ! interfaces || g_list_length(interfaces) == 0 )
1797 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Cannot load interfaces for %s", extcap );
1798 g_list_free(interface_keys);
1799 g_free(toolname);
1800 return;
1803 /* Load or create the storage element for the tool */
1804 element = extcap_ensure_interface(toolname, TRUE);
1805 if ( element == NULL )
1807 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING,
1808 "Cannot store interface %s, already loaded as personal plugin", extcap );
1809 g_list_foreach(interfaces, remove_extcap_entry, NULL);
1810 g_list_free(interfaces);
1811 g_list_free(interface_keys);
1812 g_free(toolname);
1813 return;
1816 if (control_items)
1818 toolbar_entry = g_new0(iface_toolbar, 1);
1819 toolbar_entry->controls = control_items;
1822 walker = interfaces;
1823 gchar* help = NULL;
1824 while (walker != NULL)
1826 int_iter = (extcap_interface *)walker->data;
1828 if (int_iter->call != NULL)
1829 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Interface found %s\n", int_iter->call);
1831 /* Help is not necessarily stored with the interface, but rather with the version string.
1832 * As the version string allways comes in front of the interfaces, this ensures, that it get's
1833 * properly stored with the interface */
1834 if (int_iter->if_type == EXTCAP_SENTENCE_EXTCAP)
1836 if (int_iter->call != NULL)
1837 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, " Extcap [%s] ", int_iter->call);
1839 /* Only initialize values if none are set. Need to check only one element here */
1840 if ( ! element->version )
1842 element->version = g_strdup(int_iter->version);
1843 element->basename = g_strdup(toolname);
1844 element->full_path = g_strdup(extcap);
1845 element->help = g_strdup(int_iter->help);
1848 help = int_iter->help;
1849 if (toolbar_entry)
1851 toolbar_entry->menu_title = g_strdup(int_iter->display);
1852 toolbar_entry->help = g_strdup(int_iter->help);
1855 walker = g_list_next(walker);
1856 continue;
1859 /* Only interface definitions will be parsed here. help is already set by the extcap element,
1860 * which makes it necessary to have version in the list before the interfaces. This is normally
1861 * the case by design, but could be changed by separating the information in extcap-base. */
1862 if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE )
1864 if ( g_list_find(interface_keys, int_iter->call) )
1866 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "Extcap interface \"%s\" is already provided by \"%s\" ",
1867 int_iter->call, extcap_if_executable(int_iter->call));
1868 walker = g_list_next(walker);
1869 continue;
1872 if ((int_iter->call != NULL) && (int_iter->display))
1873 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, " Interface [%s] \"%s\" ", int_iter->call, int_iter->display);
1875 int_iter->extcap_path = g_strdup(extcap);
1877 /* Only set the help, if it exists and no parsed help information is present */
1878 if ( ! int_iter->help && help )
1879 int_iter->help = g_strdup(help);
1881 element->interfaces = g_list_append(element->interfaces, int_iter);
1882 g_hash_table_insert(_tool_for_ifname, g_strdup(int_iter->call), g_strdup(toolname));
1884 if (toolbar_entry)
1886 if (!toolbar_entry->menu_title)
1888 toolbar_entry->menu_title = g_strdup(int_iter->display);
1890 toolbar_entry->ifnames = g_list_append(toolbar_entry->ifnames, g_strdup(int_iter->call));
1894 walker = g_list_next(walker);
1897 if (toolbar_entry && toolbar_entry->menu_title)
1899 iface_toolbar_add(toolbar_entry);
1900 if (extcap_iface_toolbar_add(extcap, toolbar_entry))
1902 toolbar_entry = NULL;
1906 extcap_free_toolbar(toolbar_entry);
1907 g_list_foreach(interfaces, remove_extcap_entry, NULL);
1908 g_list_free(interfaces);
1909 g_list_free(interface_keys);
1910 g_free(toolname);
1914 /** Thread callback to save the output of a --extcap-config call. */
1915 static void
1916 extcap_process_config_cb(thread_pool_t *pool _U_, void *data, char *output)
1918 extcap_iface_info_t *iface_info = (extcap_iface_info_t *)data;
1919 iface_info->output = output;
1923 * Thread callback to process discovered interfaces, scheduling more tasks to
1924 * retrieve the configuration for each interface. Called once for every extcap
1925 * program.
1927 static void
1928 extcap_process_interfaces_cb(thread_pool_t *pool, void *data, char *output)
1930 extcap_run_extcaps_info_t *info = (extcap_run_extcaps_info_t *)data;
1931 guint i = 0;
1932 guint num_interfaces = 0;
1934 if (!output) {
1935 // No interfaces available, nothing to do.
1936 return;
1939 // Save output for process_new_extcap.
1940 info->output = output;
1942 // Are there any interfaces to query information from?
1943 GList *interfaces = extcap_parse_interfaces(output, NULL);
1944 for (GList *iface = interfaces; iface; iface = g_list_next(iface)) {
1945 extcap_interface *intf = (extcap_interface *)iface->data;
1946 if (intf->if_type == EXTCAP_SENTENCE_INTERFACE) {
1947 ++num_interfaces;
1950 if (num_interfaces == 0) {
1951 // nothing to do.
1952 g_list_free_full(interfaces, extcap_free_interface);
1953 return;
1956 /* GSList is not thread-safe, so pre-allocate an array instead. */
1957 info->iface_infos = g_new0(extcap_iface_info_t, num_interfaces);
1958 info->num_interfaces = num_interfaces;
1960 // Schedule new commands to retrieve the configuration.
1961 for (GList *iface = interfaces; iface; iface = g_list_next(iface)) {
1962 extcap_interface *intf = (extcap_interface *)iface->data;
1963 if (intf->if_type != EXTCAP_SENTENCE_INTERFACE) {
1964 continue;
1967 const char *argv[] = {
1968 EXTCAP_ARGUMENT_CONFIG,
1969 EXTCAP_ARGUMENT_INTERFACE,
1970 intf->call,
1971 NULL
1973 extcap_run_task_t *task = g_new0(extcap_run_task_t, 1);
1974 extcap_iface_info_t *iface_info = &info->iface_infos[i++];
1976 task->extcap_path = info->extcap_path;
1977 task->argv = g_strdupv((char **)argv);
1978 task->output_cb = extcap_process_config_cb;
1979 task->data = iface_info;
1980 iface_info->ifname = g_strdup(intf->call);
1982 thread_pool_push(pool, task, NULL);
1984 g_list_free_full(interfaces, extcap_free_interface);
1988 * Thread callback to check whether the new-style --list-interfaces call with an
1989 * explicit function succeeded. If not, schedule a call without the new version
1990 * argument.
1992 static void
1993 extcap_list_interfaces_cb(thread_pool_t *pool, void *data, char *output)
1995 extcap_run_extcaps_info_t *info = (extcap_run_extcaps_info_t *)data;
1997 if (!output) {
1998 /* No output available, schedule a fallback query. */
1999 const char *argv[] = {
2000 EXTCAP_ARGUMENT_LIST_INTERFACES,
2001 NULL
2003 extcap_run_task_t *task = g_new0(extcap_run_task_t, 1);
2005 task->extcap_path = info->extcap_path;
2006 task->argv = g_strdupv((char **)argv);
2007 task->output_cb = extcap_process_interfaces_cb;
2008 task->data = info;
2010 thread_pool_push(pool, task, NULL);
2011 } else {
2012 extcap_process_interfaces_cb(pool, info, output);
2017 /* Handles loading of the interfaces. */
2018 static void
2019 extcap_load_interface_list(void)
2021 if (prefs.capture_no_extcap)
2022 return;
2024 if (_toolbars)
2026 // Remove existing interface toolbars here instead of in extcap_clear_interfaces()
2027 // to avoid flicker in shown toolbars when refreshing interfaces.
2028 GList *toolbar_list = g_hash_table_get_values (_toolbars);
2029 for (GList *walker = toolbar_list; walker; walker = walker->next)
2031 iface_toolbar *toolbar = (iface_toolbar *) walker->data;
2032 iface_toolbar_remove(toolbar->menu_title);
2034 g_list_free(toolbar_list);
2035 g_hash_table_remove_all(_toolbars);
2036 } else {
2037 _toolbars = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_toolbar);
2040 if (_loaded_interfaces == NULL)
2042 int major = 0;
2043 int minor = 0;
2044 guint count = 0;
2045 extcap_run_extcaps_info_t *infos;
2046 GList *unused_arguments = NULL;
2048 _loaded_interfaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_interface_info);
2049 /* Cleanup lookup table */
2050 if ( _tool_for_ifname )
2052 g_hash_table_remove_all(_tool_for_ifname);
2053 _tool_for_ifname = 0;
2054 } else {
2055 _tool_for_ifname = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
2058 get_ws_version_number(&major, &minor, NULL);
2059 char *arg_version = g_strdup_printf("%s=%d.%d", EXTCAP_ARGUMENT_VERSION, major, minor);
2060 const char *argv[] = {
2061 EXTCAP_ARGUMENT_LIST_INTERFACES,
2062 arg_version,
2063 NULL
2065 infos = (extcap_run_extcaps_info_t *)extcap_run_all(argv,
2066 extcap_list_interfaces_cb, sizeof(extcap_run_extcaps_info_t),
2067 &count);
2068 for (guint i = 0; i < count; i++) {
2069 if (!infos[i].output) {
2070 continue;
2073 // Save new extcap and each discovered interface.
2074 process_new_extcap(infos[i].extcap_path, infos[i].output);
2075 for (guint j = 0; j < infos[i].num_interfaces; j++) {
2076 extcap_iface_info_t *iface_info = &infos[i].iface_infos[j];
2078 if (!iface_info->output) {
2079 continue;
2082 extcap_callback_info_t cb_info = {
2083 .ifname = iface_info->ifname,
2084 .output = iface_info->output,
2085 .data = &unused_arguments,
2087 cb_preference(cb_info);
2090 /* XXX rework cb_preference such that this unused list can be removed. */
2091 extcap_free_if_configuration(unused_arguments, TRUE);
2092 extcap_free_extcaps_info_array(infos, count);
2093 g_free(arg_version);
2098 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2100 * Local variables:
2101 * c-basic-offset: 4
2102 * tab-width: 8
2103 * indent-tabs-mode: nil
2104 * End:
2106 * vi: set shiftwidth=4 tabstop=8 expandtab:
2107 * :indentSize=4:tabSize=8:noTabs=true: