tshark: Cache the interface list

For tshark, cache the interface list the first time it is retrieved,
instead of launching dumpcap once for each interface specified in
the capture options, and when getting each interfaces descriptive
name at the start of the capture. If the interface list changes
when in the middle of processing options before the capture starts
we have problems anyway.

On Windows, this means not getting multiple UAC pop-ups if
npcap is installed limited to Administrator privileges.

We can probably do this for the GUI as well, since the command
line options for capture are only parsed at startup.

Fix #16625
This commit is contained in:
John Thacker 2023-11-24 08:41:57 -05:00
parent c62e98c0f5
commit 3b9de4df3d
3 changed files with 83 additions and 2 deletions

View File

@ -407,6 +407,31 @@ if_info_get(const char *name)
return if_info;
}
if_addr_t *
if_addr_copy(const if_addr_t *addr)
{
if_addr_t *new_addr = g_new(if_addr_t, 1);
new_addr->ifat_type = addr->ifat_type;
switch (addr->ifat_type) {
case IF_AT_IPv4:
new_addr->addr.ip4_addr = addr->addr.ip4_addr;
break;
case IF_AT_IPv6:
memcpy(new_addr->addr.ip6_addr, addr->addr.ip6_addr, sizeof(addr->addr));
break;
default:
/* In case we add non-IP addresses */
break;
}
return new_addr;
}
static void*
if_addr_copy_cb(const void *data, void *user_data _U_)
{
return if_addr_copy((if_addr_t*)data);
}
void
if_info_free(if_info_t *if_info)
{
@ -418,6 +443,29 @@ if_info_free(if_info_t *if_info)
g_free(if_info);
}
if_info_t *
if_info_copy(const if_info_t *if_info)
{
if_info_t *new_if_info;
new_if_info = g_new(if_info_t, 1);
new_if_info->name = g_strdup(if_info->name);
/* g_strdup accepts NULL as input and returns NULL. */
new_if_info->friendly_name = g_strdup(if_info->friendly_name);
new_if_info->vendor_description = g_strdup(if_info->vendor_description);
new_if_info->addrs = g_slist_copy_deep(if_info->addrs, if_addr_copy_cb, NULL);
new_if_info->type = if_info->type;
new_if_info->loopback = if_info->loopback;
new_if_info->extcap = g_strdup(if_info->extcap);
return new_if_info;
}
static void*
if_info_copy_cb(const void* data, void *user_data _U_)
{
return if_info_copy((const if_info_t*)data);
}
if_info_t *
if_info_new(const char *name, const char *description, bool loopback)
{
@ -739,6 +787,12 @@ free_interface_list(GList *if_list)
g_list_free(if_list);
}
GList*
interface_list_copy(GList *if_list)
{
return g_list_copy_deep(if_list, if_info_copy_cb, NULL);
}
static void
free_linktype_cb(void * data, void * user_data _U_)
{

View File

@ -83,6 +83,11 @@ extern GList *capture_interface_list(int *err, char **err_str, void (*update_cb)
void free_interface_list(GList *if_list);
/**
* Deep copy an interface list
*/
GList * interface_list_copy(GList *if_list);
/**
* Get an if_info_t for a particular interface.
* (May require privilege, so should only be used by dumpcap.)
@ -94,6 +99,16 @@ extern if_info_t *if_info_get(const char *name);
*/
void if_info_free(if_info_t *if_info);
/**
* Deep copy an if_info_t.
*/
if_info_t *if_info_copy(const if_info_t *if_info);
/**
* Deep copy an if_addr_t.
*/
if_addr_t *if_addr_copy(const if_addr_t *if_addr);
/*
* "get_if_capabilities()" and "capture_if_capabilities()" return a pointer
* to an allocated instance of this structure. "free_if_capabilities()"

View File

@ -905,13 +905,22 @@ warn_about_capture_filter(const char *rfilter)
#endif
#ifdef HAVE_LIBPCAP
static GList *cached_if_list = NULL;
static GList *
capture_opts_get_interface_list(int *err, char **err_str)
{
if (cached_if_list == NULL) {
/*
* This isn't a GUI tool, so no need for a callback.
*/
cached_if_list = capture_interface_list(err, err_str, NULL);
}
/*
* This isn't a GUI tool, so no need for a callback.
* Routines expect to free the returned interface list, so return
* a deep copy.
*/
return capture_interface_list(err, err_str, NULL);
return interface_list_copy(cached_if_list);
}
#endif
@ -2716,6 +2725,9 @@ clean_exit:
g_free(output_file_name);
#ifdef HAVE_LIBPCAP
capture_opts_cleanup(&global_capture_opts);
if (cached_if_list) {
free_interface_list(cached_if_list);
}
#endif
col_cleanup(&cfile.cinfo);
wtap_cleanup();