Put the interface descrptions into the IDB when capturing to pcapng.

capture_opts_add_iface_opt(), when called in a program acting as a
capture child, will fetch the description for the interface, and will
also generate a "display name" for the interface.

In the process, we clean up capture_opts_add_iface_opt() a bit,
combining duplicate code.

We rename console_display_name to just display_name, as it may also be
used in the title bar of Wireshark when capturing.

Change-Id: Ifd18955bb3cb41df4c0ed4362d4854068c825b96
Reviewed-on: https://code.wireshark.org/review/29117
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot
Reviewed-by: Guy Harris <guy@alum.mit.edu>
This commit is contained in:
Guy Harris 2018-08-12 20:32:01 -07:00
parent d48262753e
commit 149e74b70d
6 changed files with 387 additions and 145 deletions

View File

@ -155,7 +155,7 @@ capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_optio
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
g_log(log_domain, log_level, "Interface name[%02d] : %s", i, interface_opts->name ? interface_opts->name : "(unspecified)");
g_log(log_domain, log_level, "Interface description[%02d] : %s", i, interface_opts->descr ? interface_opts->descr : "(unspecified)");
g_log(log_domain, log_level, "Console display name[%02d]: %s", i, interface_opts->console_display_name ? interface_opts->console_display_name : "(unspecified)");
g_log(log_domain, log_level, "Display name[%02d]: %s", i, interface_opts->display_name ? interface_opts->display_name : "(unspecified)");
g_log(log_domain, log_level, "Capture filter[%02d] : %s", i, interface_opts->cfilter ? interface_opts->cfilter : "(unspecified)");
g_log(log_domain, log_level, "Snap length[%02d] (%u) : %d", i, interface_opts->has_snaplen, interface_opts->snaplen);
g_log(log_domain, log_level, "Link Type[%02d] : %d", i, interface_opts->linktype);
@ -499,6 +499,129 @@ get_auth_arguments(capture_options *capture_opts, const char *arg)
}
#endif
#ifdef _WIN32
static char *
capture_opts_generate_display_name(const char *friendly_name,
const char *name _U_)
{
/*
* Display the friendly name rather than the not-so-friendly
* GUID-based interface name.
*/
return g_strdup(friendly_name);
}
#else
static char *
capture_opts_generate_display_name(const char *friendly_name,
const char *name)
{
/*
* On UN*X, however, users are more used to interface names,
* and may find it helpful to see them.
*/
return g_strdup_printf("%s: %s", friendly_name, name);
}
#endif
static gboolean
capture_opts_search_for_interface(interface_options *interface_opts,
const char *name)
{
gboolean matched;
GList *if_list;
int err;
GList *if_entry;
if_info_t *if_info;
size_t prefix_length;
matched = FALSE;
if_list = capture_interface_list(&err, NULL, NULL);
if (if_list != NULL) {
/* try and do an exact match (case insensitive) */
for (if_entry = g_list_first(if_list); if_entry != NULL;
if_entry = g_list_next(if_entry))
{
if_info = (if_info_t *)if_entry->data;
/*
* Does the specified name match the interface name
* with a case-insensitive match?
*/
if (g_ascii_strcasecmp(if_info->name, name) == 0) {
/*
* Yes.
*/
matched = TRUE;
break;
}
/*
* Does this interface have a friendly name and, if so,
* does the specified name match the friendly name with
* a case-insensitive match?
*/
if (if_info->friendly_name != NULL &&
g_ascii_strcasecmp(if_info->friendly_name, name) == 0) {
/*
* Yes.
*/
matched = TRUE;
break;
}
}
if (!matched) {
/*
* We didn't find it; attempt a case-insensitive prefix match
* of the friendly name.
*/
prefix_length = strlen(name);
for (if_entry = g_list_first(if_list); if_entry != NULL;
if_entry = g_list_next(if_entry))
{
if_info = (if_info_t *)if_entry->data;
if (if_info->friendly_name != NULL &&
g_ascii_strncasecmp(if_info->friendly_name, name, prefix_length) == 0) {
/*
* We found an interface whose friendly name matches
* with a case-insensitive prefix match.
*/
matched = TRUE;
break;
}
}
}
}
if (matched) {
/*
* We found an interface that matches.
*/
interface_opts->name = g_strdup(if_info->name);
if (if_info->friendly_name != NULL) {
/*
* We have a friendly name; remember it as the
* description...
*/
interface_opts->descr = g_strdup(if_info->friendly_name);
/*
* ...and use it in the console display name.
*/
interface_opts->display_name = capture_opts_generate_display_name(if_info->friendly_name, if_info->name);
} else {
/* fallback to the interface name */
interface_opts->descr = NULL;
interface_opts->display_name = g_strdup(if_info->name);
}
interface_opts->if_type = if_info->type;
interface_opts->extcap = g_strdup(if_info->extcap);
}
free_interface_list(if_list);
return matched;
}
static int
capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str_p)
{
@ -549,6 +672,28 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str
return 1;
}
interface_opts.name = g_strdup(if_info->name);
if (if_info->friendly_name != NULL) {
/*
* We have a friendly name for the interface, so remember that
* as the description.
*/
interface_opts.descr = g_strdup(if_info->friendly_name);
interface_opts.display_name = capture_opts_generate_display_name(if_info->friendly_name, if_info->name);
} else {
/* fallback to the interface name */
interface_opts.descr = NULL;
interface_opts.display_name = g_strdup(if_info->name);
}
interface_opts.if_type = if_info->type;
interface_opts.extcap = g_strdup(if_info->extcap);
free_interface_list(if_list);
} else if (capture_opts->capture_child) {
/*
* In Wireshark capture child mode, so the exact interface name
* is supplied, and we don't need to look it up.
*/
if_info = if_info_get(optarg_str_p);
interface_opts.name = g_strdup(if_info->name);
if (if_info->friendly_name != NULL) {
/*
* We have a friendly name for the interface, so display that
@ -557,126 +702,37 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str
* XXX - on UN*X, the interface name is not quite so ugly,
* and might be more familiar to users; display them both?
*/
interface_opts.console_display_name = g_strdup(if_info->friendly_name);
interface_opts.descr = g_strdup(if_info->friendly_name);
interface_opts.display_name = g_strdup(if_info->friendly_name);
} else {
interface_opts.descr = NULL;
/* fallback to the interface name */
interface_opts.console_display_name = g_strdup(if_info->name);
interface_opts.display_name = g_strdup(if_info->name);
}
interface_opts.if_type = if_info->type;
interface_opts.extcap = g_strdup(if_info->extcap);
free_interface_list(if_list);
} else if (capture_opts->capture_child) {
/* In Wireshark capture child mode, thus proper device name is supplied. */
/* No need for trying to match it for friendly names. */
interface_opts.name = g_strdup(optarg_str_p);
interface_opts.console_display_name = g_strdup(optarg_str_p);
interface_opts.if_type = capture_opts->default_options.if_type;
interface_opts.extcap = g_strdup(capture_opts->default_options.extcap);
if_info_free(if_info);
} else {
/*
* Retrieve the interface list so that we can search for the
* specified option amongst both the interface names and the
* friendly names and so that we find the friendly name even
* if an interface name was specified.
*
* If we can't get the list, just use the specified option as
* the interface name, so that the user can try specifying an
* interface explicitly for testing purposes.
* Search for that name in the interface list and, if we found
* it, fill in fields in the interface_opts structure.
*/
if_list = capture_interface_list(&err, NULL, NULL);
if (if_list != NULL) {
/* try and do an exact match (case insensitive) */
GList *if_entry;
gboolean matched;
matched = FALSE;
for (if_entry = g_list_first(if_list); if_entry != NULL;
if_entry = g_list_next(if_entry))
{
if_info = (if_info_t *)if_entry->data;
/* exact name check */
if (g_ascii_strcasecmp(if_info->name, optarg_str_p) == 0) {
/* exact match on the interface name, use that for displaying etc */
interface_opts.name = g_strdup(if_info->name);
if (if_info->friendly_name != NULL) {
/*
* If we have a friendly name, use that for the
* console display name, as it is the basis for
* the auto generated temp filename.
*/
interface_opts.console_display_name = g_strdup(if_info->friendly_name);
} else {
interface_opts.console_display_name = g_strdup(if_info->name);
}
interface_opts.if_type = if_info->type;
interface_opts.extcap = g_strdup(if_info->extcap);
matched = TRUE;
break;
}
/* exact friendly name check */
if (if_info->friendly_name != NULL &&
g_ascii_strcasecmp(if_info->friendly_name, optarg_str_p) == 0) {
/* exact match - use the friendly name for display */
interface_opts.name = g_strdup(if_info->name);
interface_opts.console_display_name = g_strdup(if_info->friendly_name);
interface_opts.if_type = if_info->type;
interface_opts.extcap = g_strdup(if_info->extcap);
matched = TRUE;
break;
}
}
/* didn't find, attempt a case insensitive prefix match of the friendly name*/
if (!matched) {
size_t prefix_length;
prefix_length = strlen(optarg_str_p);
for (if_entry = g_list_first(if_list); if_entry != NULL;
if_entry = g_list_next(if_entry))
{
if_info = (if_info_t *)if_entry->data;
if (if_info->friendly_name != NULL &&
g_ascii_strncasecmp(if_info->friendly_name, optarg_str_p, prefix_length) == 0) {
/* prefix match - use the friendly name for display */
interface_opts.name = g_strdup(if_info->name);
interface_opts.console_display_name = g_strdup(if_info->friendly_name);
interface_opts.if_type = if_info->type;
interface_opts.extcap = g_strdup(if_info->extcap);
matched = TRUE;
break;
}
}
}
if (!matched) {
/*
* We didn't find the interface in the list; just use
* the specified name, so that, for example, if an
* interface doesn't show up in the list for some
* reason, the user can try specifying it explicitly
* for testing purposes.
*/
interface_opts.name = g_strdup(optarg_str_p);
interface_opts.console_display_name = g_strdup(optarg_str_p);
interface_opts.if_type = capture_opts->default_options.if_type;
interface_opts.extcap = g_strdup(capture_opts->default_options.extcap);
}
free_interface_list(if_list);
} else {
if (!capture_opts_search_for_interface(&interface_opts, optarg_str_p)) {
/*
* We didn't find the interface in the list; just use
* the specified name, so that, for example, if an
* interface doesn't show up in the list for some
* reason, the user can try specifying it explicitly
* for testing purposes.
*/
interface_opts.name = g_strdup(optarg_str_p);
interface_opts.console_display_name = g_strdup(optarg_str_p);
interface_opts.descr = NULL;
interface_opts.display_name = g_strdup(optarg_str_p);
interface_opts.if_type = capture_opts->default_options.if_type;
interface_opts.extcap = g_strdup(capture_opts->default_options.extcap);
}
}
/* We don't set iface_descr here because doing so requires
* capture_ui_utils.c which requires epan/prefs.c which is
* probably a bit too much dependency for here...
*/
interface_opts.descr = g_strdup(capture_opts->default_options.descr);
interface_opts.cfilter = g_strdup(capture_opts->default_options.cfilter);
interface_opts.snaplen = capture_opts->default_options.snaplen;
interface_opts.has_snaplen = capture_opts->default_options.has_snaplen;
@ -1119,7 +1175,7 @@ capture_opts_del_iface(capture_options *capture_opts, guint if_index)
g_free(interface_opts->name);
g_free(interface_opts->descr);
g_free(interface_opts->console_display_name);
g_free(interface_opts->display_name);
g_free(interface_opts->cfilter);
g_free(interface_opts->timestamp_type);
g_free(interface_opts->extcap);
@ -1164,8 +1220,8 @@ collect_ifaces(capture_options *capture_opts)
device = &g_array_index(capture_opts->all_ifaces, interface_t, i);
if (!device->hidden && device->selected) {
interface_opts.name = g_strdup(device->name);
interface_opts.descr = g_strdup(device->display_name);
interface_opts.console_display_name = g_strdup(device->name);
interface_opts.descr = g_strdup(device->friendly_name);
interface_opts.display_name = g_strdup(device->display_name);
interface_opts.linktype = device->active_dlt;
interface_opts.cfilter = g_strdup(device->cfilter);
interface_opts.timestamp_type = g_strdup(device->timestamp_type);

View File

@ -197,9 +197,9 @@ typedef struct link_row_tag {
} link_row;
typedef struct interface_options_tag {
gchar *name; /* the name of the interface provided to winpcap/libpcap to specify the interface */
gchar *descr;
gchar *console_display_name; /* the name displayed in the console, also the basis for autonamed pcap filenames */
gchar *name; /* the name of the interface supplied to libpcap/WinPcap/Npcap to specify the interface */
gchar *descr; /* a more user-friendly description of the interface; may be NULL if none */
gchar *display_name; /* the name displayed in the console and title bar */
gchar *cfilter;
gboolean has_snaplen;
int snaplen;

View File

@ -260,6 +260,150 @@ add_unix_interface_ifinfo(if_info_t *if_info, const char *name _U_,
}
#endif
if_info_t *
if_info_get(const char *name)
{
char *description = NULL;
if_info_t *if_info;
#ifdef SIOCGIFDESCR
/*
* Try to fetch the description of this interface.
* XXX - this is only here because libpcap has no API to
* get the description of a *single* interface; it really
* needs both an API to get pcapng-IDB-style attributes
* for a single interface and to get a list of interfaces
* with pcapng-IDB-style attributes for each interface.
*/
int s;
struct ifreq ifrdesc;
#ifndef IFDESCRSIZE
size_t descrlen = 64;
#else
size_t descrlen = IFDESCRSIZE;
#endif /* IFDESCRSIZE */
/*
* Get the description for the interface.
*/
memset(&ifrdesc, 0, sizeof ifrdesc);
g_strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s >= 0) {
#ifdef __FreeBSD__
/*
* On FreeBSD, if the buffer isn't big enough for the
* description, the ioctl succeeds, but the description
* isn't copied, ifr_buffer.length is set to the description
* length, and ifr_buffer.buffer is set to NULL.
*/
for (;;) {
g_free(description);
if ((description = g_malloc(descrlen)) != NULL) {
ifrdesc.ifr_buffer.buffer = description;
ifrdesc.ifr_buffer.length = descrlen;
if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) {
if (ifrdesc.ifr_buffer.buffer ==
description)
break;
else
descrlen = ifrdesc.ifr_buffer.length;
} else {
/*
* Failed to get interface description.
*/
g_free(description);
description = NULL;
break;
}
} else
break;
}
#else /* __FreeBSD__ */
/*
* The only other OS that currently supports
* SIOCGIFDESCR is OpenBSD, and it has no way
* to get the description length - it's clamped
* to a maximum of IFDESCRSIZE.
*/
if ((description = g_malloc(descrlen)) != NULL) {
ifrdesc.ifr_data = (caddr_t)description;
if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) {
/*
* Failed to get interface description.
*/
g_free(description);
description = NULL;
}
}
#endif /* __FreeBSD__ */
close(s);
if (description != NULL && strlen(description) == 0) {
/*
* Description is empty, so discard it.
*/
g_free(description);
description = NULL;
}
}
#ifdef __FreeBSD__
/*
* For FreeBSD, if we didn't get a description, and this is
* a device with a name of the form usbusN, label it as a USB
* bus.
*/
if (description == NULL) {
if (strncmp(name, "usbus", 5) == 0) {
/*
* OK, it begins with "usbus".
*/
long busnum;
char *p;
errno = 0;
busnum = strtol(name + 5, &p, 10);
if (errno == 0 && p != name + 5 && *p == '\0' &&
busnum >= 0 && busnum <= INT_MAX) {
/*
* OK, it's a valid number that's not
* bigger than INT_MAX. Construct
* a description from it.
*/
static const char descr_prefix[] = "USB bus number ";
size_t descr_size;
/*
* Allow enough room for a 32-bit bus number.
* sizeof (descr_prefix) includes the
* terminating NUL.
*/
descr_size = sizeof (descr_prefix) + 10;
description = g_malloc(descr_size);
if (description != NULL) {
pcap_snprintf(description, descr_size,
"%s%ld", descr_prefix, busnum);
}
}
}
}
#endif /* __FreeBSD__ */
#endif /* SIOCGIFDESCR */
if_info = if_info_new(name, description, FALSE);
g_free(description);
return if_info;
}
void
if_info_free(if_info_t *if_info)
{
g_free(if_info->name);
g_free(if_info->friendly_name);
g_free(if_info->vendor_description);
g_free(if_info->extcap);
g_slist_free_full(if_info->addrs, g_free);
g_free(if_info);
}
if_info_t *
if_info_new(const char *name, const char *description, gboolean loopback)
{
@ -528,14 +672,7 @@ get_interface_list_findalldevs(int *err, char **err_str)
static void
free_if_cb(gpointer data, gpointer user_data _U_)
{
if_info_t *if_info = (if_info_t *)data;
g_free(if_info->name);
g_free(if_info->friendly_name);
g_free(if_info->vendor_description);
g_free(if_info->extcap);
g_slist_free_full(if_info->addrs, g_free);
g_free(if_info);
if_info_free((if_info_t *)data);
}
void

View File

@ -75,6 +75,17 @@ extern GList *capture_interface_list(int *err, char **err_str, void (*update_cb)
void free_interface_list(GList *if_list);
/**
* Get an if_info_t for a particular interface.
* (May require privilege, so should only be used by dumpcap.)
*/
extern if_info_t *if_info_get(const char *name);
/**
* Free an if_info_t.
*/
void if_info_free(if_info_t *if_info);
/*
* "get_if_capabilities()" and "capture_if_capabilities()" return a pointer
* to an allocated instance of this structure. "free_if_capabilities()"

View File

@ -3310,23 +3310,57 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
prefix = g_strdup_printf("wireshark_%d_interfaces", global_capture_opts.ifaces->len);
} else {
/*
* One interface; use its name to generate the temporary file
* name prefix.
* One interface; use its description, if it has one, to generate
* the temporary file name, otherwise use its name.
*/
gchar *basename;
basename = g_path_get_basename((&g_array_index(global_capture_opts.ifaces, interface_options, 0))->console_display_name);
const interface_options *interface_opts;
interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, 0);
/*
* Do we have a description?
*/
if (interface_opts->descr) {
/*
* Yes - use it.
*
* Strip off any stuff we shouldn't use in the file name,
* by getting the last component of what would be a file
* name.
*/
basename = g_path_get_basename(interface_opts->descr);
} else {
/*
* No - use the name.
*
* Strip off any stuff we shouldn't use in the file name,
* by getting the last component of what would be a file
* name.
*/
basename = g_path_get_basename(interface_opts->name);
#ifdef _WIN32
/* use the generic portion of the interface guid to form the basis of the filename */
if (strncmp("NPF_{", basename, 5)==0)
{
/* we have a windows guid style device name, extract the guid digits as the basis of the filename */
GString *iface;
iface = isolate_uuid(basename);
g_free(basename);
basename = g_strdup(iface->str);
g_string_free(iface, TRUE);
}
/*
* This is Windows, where we might have an ugly GUID-based
* interface name.
*
* If it's an ugly GUID-based name, use the generic portion
* of the interface GUID to form the basis of the filename.
*/
if (strncmp("NPF_{", basename, 5) == 0) {
/*
* We have a GUID-based name; extract the GUID digits
* as the basis of the filename.
*/
GString *iface;
iface = isolate_uuid(basename);
g_free(basename);
basename = g_strdup(iface->str);
g_string_free(iface, TRUE);
}
#endif
}
/* generate the temp file name prefix */
prefix = g_strconcat("wireshark_", basename, NULL);
g_free(basename);
}
@ -3990,7 +4024,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
report_capture_error(errmsg, please_report);
}
}
report_packet_drops(received, pcap_dropped, pcap_src->dropped, pcap_src->flushed, stats->ps_ifdrop, interface_opts->console_display_name);
report_packet_drops(received, pcap_dropped, pcap_src->dropped, pcap_src->flushed, stats->ps_ifdrop, interface_opts->display_name);
}
/* close the input file (pcap or capture pipe) */
@ -5141,7 +5175,7 @@ main(int argc, char *argv[])
g_string_append_printf(str, "and ");
}
}
g_string_append_printf(str, "'%s'", interface_opts->console_display_name);
g_string_append_printf(str, "'%s'", interface_opts->display_name);
}
} else {
g_string_append_printf(str, "%u interfaces", global_capture_opts.ifaces->len);

View File

@ -468,23 +468,27 @@ get_if_name(const char *if_text)
return if_name;
}
/* Return interface_opts->descr (after setting it if it is not set)
* This is necessary because capture_opts.c can't set descr (at least
* not without adding significant dependencies there).
/* Return a display name for the interface.
*/
static const char *
get_iface_description_for_interface(capture_options *capture_opts, guint i)
get_display_name_for_interface(capture_options *capture_opts, guint i)
{
interface_options *interface_opts;
if (i < capture_opts->ifaces->len) {
interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
if (!interface_opts->descr && interface_opts->name) {
interface_opts->descr = get_interface_descriptive_name(interface_opts->name);
if (interface_opts->display_name) {
return interface_opts->display_name;
}
return (interface_opts->descr);
if (!interface_opts->display_name) {
if (interface_opts->descr && interface_opts->name) {
interface_opts->descr = get_interface_descriptive_name(interface_opts->name);
}
interface_opts->display_name = g_strdup(interface_opts->descr);
}
return interface_opts->display_name;
} else {
return (NULL);
return NULL;
}
}
@ -569,7 +573,7 @@ get_iface_list_string(capture_options *capture_opts, guint32 style)
}
if (style & IFLIST_QUOTE_IF_DESCRIPTION)
g_string_append_printf(iface_list_string, "'");
g_string_append_printf(iface_list_string, "%s", get_iface_description_for_interface(capture_opts, i));
g_string_append_printf(iface_list_string, "%s", get_display_name_for_interface(capture_opts, i));
if (style & IFLIST_QUOTE_IF_DESCRIPTION)
g_string_append_printf(iface_list_string, "'");
if (style & IFLIST_SHOW_FILTER) {