From 3b9de4df3db1a7fa46870cc47e7256ab7a7a8110 Mon Sep 17 00:00:00 2001 From: John Thacker Date: Fri, 24 Nov 2023 08:41:57 -0500 Subject: [PATCH] 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 --- capture/capture-pcap-util.c | 54 +++++++++++++++++++++++++++++++++++++ capture/capture_ifinfo.h | 15 +++++++++++ tshark.c | 16 +++++++++-- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/capture/capture-pcap-util.c b/capture/capture-pcap-util.c index ac54bb36e2..0c2aae6049 100644 --- a/capture/capture-pcap-util.c +++ b/capture/capture-pcap-util.c @@ -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_) { diff --git a/capture/capture_ifinfo.h b/capture/capture_ifinfo.h index b3c0163eba..ba9cdf7d4a 100644 --- a/capture/capture_ifinfo.h +++ b/capture/capture_ifinfo.h @@ -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()" diff --git a/tshark.c b/tshark.c index a791e6aaf6..74f1e39ec7 100644 --- a/tshark.c +++ b/tshark.c @@ -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();