wireshark/ui/qt/manage_interfaces_dialog.cpp
Guy Harris 357cfd3b03 A bunch of "{Mac} OS X" -> "macOS" changes.
Avoid anachronisms, however; there was no "macOS 10.0" or even "OS X
10.0", for example.  It was "Mac OS X" until 10.8 (although 10.7 was
sometimes called "OS X" and sometimes called "Mac OS X"), and it was "OS
X" from 10.8 to 10.11.

Change-Id: Ie4a848997dcc6c45c2245c1fb84ec526032375c3
Reviewed-on: https://code.wireshark.org/review/20933
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2017-04-05 19:16:22 +00:00

591 lines
21 KiB
C++

/* manage_interfaces_dialog.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <glib.h>
#include "manage_interfaces_dialog.h"
#include <ui_manage_interfaces_dialog.h>
#include "epan/prefs.h"
#include "epan/to_str.h"
#include "capture_opts.h"
#include "ui/capture_globals.h"
#include "ui/qt/capture_interfaces_dialog.h"
#include "ui/qt/interface_tree_cache_model.h"
#include "ui/qt/interface_sort_filter_model.h"
#ifdef HAVE_PCAP_REMOTE
#include "ui/qt/remote_capture_dialog.h"
#include "ui/qt/remote_settings_dialog.h"
#endif
#include "ui/iface_lists.h"
#include "ui/preference_utils.h"
#include "ui/ui_util.h"
#include <wsutil/utf8_entities.h>
#include "qt_ui_utils.h"
#include "wireshark_application.h"
#include <QDebug>
#ifdef HAVE_LIBPCAP
#include "ui/capture_ui_utils.h"
#include "ui/qt/path_chooser_delegate.h"
#include <QCheckBox>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QStandardItemModel>
#include <QTreeWidgetItemIterator>
// To do:
// - Check the validity of pipes and remote interfaces and provide feedback
// via hintLabel.
// - We might want to move PathChooserDelegate to its own module and use it in
// other parts of the application such as the general preferences and UATs.
// Qt Creator has a much more elaborate version from which we might want
// to draw inspiration.
enum {
col_p_pipe_
};
enum
{
col_r_show_,
col_r_host_dev_
};
enum {
tab_local_,
tab_pipe_,
tab_remote_
};
ManageInterfacesDialog::ManageInterfacesDialog(QWidget *parent) :
GeometryStateDialog(parent),
ui(new Ui::ManageInterfacesDialog)
{
ui->setupUi(this);
loadGeometry();
#ifdef Q_OS_MAC
ui->addPipe->setAttribute(Qt::WA_MacSmallSize, true);
ui->delPipe->setAttribute(Qt::WA_MacSmallSize, true);
ui->addRemote->setAttribute(Qt::WA_MacSmallSize, true);
ui->delRemote->setAttribute(Qt::WA_MacSmallSize, true);
#endif
sourceModel = new InterfaceTreeCacheModel(this);
proxyModel = new InterfaceSortFilterModel(this);
QList<InterfaceTreeColumns> columns;
columns.append(IFTREE_COL_HIDDEN);
columns.append(IFTREE_COL_INTERFACE_NAME);
#ifdef Q_OS_WIN
columns.append(IFTREE_COL_NAME);
#endif
columns.append(IFTREE_COL_INTERFACE_COMMENT);
proxyModel->setColumns(columns);
proxyModel->setSourceModel(sourceModel);
proxyModel->setFilterHidden(false);
proxyModel->setFilterByType(false);
ui->localView->setModel(proxyModel);
ui->localView->resizeColumnToContents(proxyModel->mapSourceToColumn(IFTREE_COL_HIDDEN));
ui->localView->resizeColumnToContents(proxyModel->mapSourceToColumn(IFTREE_COL_INTERFACE_NAME));
pipeProxyModel = new InterfaceSortFilterModel(this);
columns.clear();
columns.append(IFTREE_COL_PIPE_PATH);
pipeProxyModel->setColumns(columns);
pipeProxyModel->setSourceModel(sourceModel);
pipeProxyModel->setFilterHidden(true);
pipeProxyModel->setFilterByType(true, true);
pipeProxyModel->setInterfaceTypeVisible(IF_PIPE, false);
ui->pipeView->setModel(pipeProxyModel);
ui->delPipe->setEnabled(pipeProxyModel->rowCount() > 0);
ui->pipeView->setItemDelegateForColumn(
pipeProxyModel->mapSourceToColumn(IFTREE_COL_PIPE_PATH), new PathChooserDelegate()
);
connect(ui->pipeView->selectionModel(),
SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this,
SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &)));
#if defined(HAVE_PCAP_REMOTE)
// The default indentation (20) means our checkboxes are shifted too far on Windows.
// Assume that our disclosure and checkbox controls are square, or at least fit within an em.
int one_em = fontMetrics().height();
ui->remoteList->setIndentation(one_em);
ui->remoteList->setColumnWidth(col_r_show_, one_em * 4);
ui->remoteSettings->setEnabled(false);
showRemoteInterfaces();
#else
ui->tabWidget->removeTab(tab_remote_);
#endif
connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(updateWidgets()));
connect(this, SIGNAL(ifsChanged()), parent, SIGNAL(ifsChanged()));
#ifdef HAVE_PCAP_REMOTE
connect(this, SIGNAL(remoteAdded(GList*, remote_options*)), this, SLOT(addRemoteInterfaces(GList*, remote_options*)));
connect(this, SIGNAL(remoteSettingsChanged(interface_t *)), this, SLOT(setRemoteSettings(interface_t *)));
connect(ui->remoteList, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(remoteSelectionChanged(QTreeWidgetItem*, int)));
#endif
ui->tabWidget->setCurrentIndex(tab_local_);
updateWidgets();
}
ManageInterfacesDialog::~ManageInterfacesDialog()
{
delete ui;
}
void ManageInterfacesDialog::onSelectionChanged(const QItemSelection &sel, const QItemSelection &)
{
ui->delPipe->setEnabled( sel.count() > 0 );
}
void ManageInterfacesDialog::updateWidgets()
{
QString hint;
#ifdef HAVE_PCAP_REMOTE
bool enable_del_remote = false;
bool enable_remote_settings = false;
QTreeWidgetItem *item = ui->remoteList->currentItem();
if (item) {
if (item->childCount() < 1) { // Leaf
enable_remote_settings = true;
} else {
enable_del_remote = true;
}
}
ui->delRemote->setEnabled(enable_del_remote);
ui->remoteSettings->setEnabled(enable_remote_settings);
#endif
switch (ui->tabWidget->currentIndex()) {
case tab_pipe_:
hint = tr("This version of Wireshark does not save pipe settings.");
break;
case tab_remote_:
#ifdef HAVE_PCAP_REMOTE
hint = tr("This version of Wireshark does not save remote settings.");
#else
hint = tr("This version of Wireshark does not support remote interfaces.");
#endif
break;
default:
break;
}
hint.prepend("<small><i>");
hint.append("</i></small>");
ui->hintLabel->setText(hint);
}
void ManageInterfacesDialog::on_buttonBox_accepted()
{
sourceModel->save();
#ifdef HAVE_PCAP_REMOTE
remoteAccepted();
#endif
prefs_main_write();
wsApp->refreshLocalInterfaces();
emit ifsChanged();
}
void ManageInterfacesDialog::on_addPipe_clicked()
{
interface_t * device = g_new0(interface_t, 1);
device->name = qstring_strdup(tr("New Pipe"));
device->display_name = g_strdup(device->name);
device->hidden = FALSE;
device->selected = TRUE;
device->pmode = global_capture_opts.default_options.promisc_mode;
device->has_snaplen = global_capture_opts.default_options.has_snaplen;
device->snaplen = global_capture_opts.default_options.snaplen;
device->cfilter = g_strdup(global_capture_opts.default_options.cfilter);
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
device->buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
#endif
device->active_dlt = -1;
device->if_info.name = g_strdup(device->name);
device->if_info.type = IF_PIPE;
sourceModel->addDevice(device);
updateWidgets();
}
void ManageInterfacesDialog::on_delPipe_clicked()
{
/* Get correct selection and tell the source model to delete the itm. pipe view only
* displays IF_PIPE devices, therefore this will only delete pipes, and this is set
* to only select single items. */
QModelIndex selIndex = ui->pipeView->selectionModel()->selectedIndexes().at(0);
sourceModel->deleteDevice( pipeProxyModel->mapToSource(selIndex) );
updateWidgets();
}
void ManageInterfacesDialog::on_buttonBox_helpRequested()
{
wsApp->helpTopicAction(HELP_CAPTURE_MANAGE_INTERFACES_DIALOG);
}
#ifdef HAVE_PCAP_REMOTE
void ManageInterfacesDialog::remoteSelectionChanged(QTreeWidgetItem*, int)
{
updateWidgets();
}
void ManageInterfacesDialog::updateRemoteInterfaceList(GList* rlist, remote_options* roptions)
{
GList *if_entry, *lt_entry;
if_info_t *if_info;
char *if_string = NULL;
gchar *descr, *auth_str;
if_capabilities_t *caps;
gint linktype_count;
bool monitor_mode, found = false;
GSList *curr_addr;
int ips = 0;
guint i;
if_addr_t *addr;
data_link_info_t *data_link_info;
GString *ip_str;
link_row *linkr = NULL;
interface_t device;
guint num_interfaces;
num_interfaces = global_capture_opts.all_ifaces->len;
for (if_entry = g_list_first(rlist); if_entry != NULL; if_entry = g_list_next(if_entry)) {
auth_str = NULL;
if_info = (if_info_t *)if_entry->data;
#if 0
add_interface_to_remote_list(if_info);
#endif
for (i = 0; i < num_interfaces; i++) {
device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if (device.hidden)
continue;
if (strcmp(device.name, if_info->name) == 0) {
found = TRUE;
break;
}
}
if (found) {
found = FALSE;
continue;
}
ip_str = g_string_new("");
ips = 0;
memset(&device, 0, sizeof(device));
device.name = g_strdup(if_info->name);
device.if_info.name = g_strdup("Don't crash on bug 13448");
/* Is this interface hidden and, if so, should we include it
anyway? */
descr = capture_dev_user_descr_find(if_info->name);
if (descr != NULL) {
/* Yes, we have a user-supplied description; use it. */
if_string = g_strdup_printf("%s: %s", descr, if_info->name);
g_free(descr);
} else {
/* No, we don't have a user-supplied description; did we get
one from the OS or libpcap? */
if (if_info->vendor_description != NULL) {
/* Yes - use it. */
if_string = g_strdup_printf("%s: %s", if_info->vendor_description, if_info->name);
} else {
/* No. */
if_string = g_strdup(if_info->name);
}
} /* else descr != NULL */
if (if_info->loopback) {
device.display_name = g_strdup_printf("%s (loopback)", if_string);
} else {
device.display_name = g_strdup(if_string);
}
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
if ((device.buffer = capture_dev_user_buffersize_find(if_string)) == -1) {
device.buffer = global_capture_opts.default_options.buffer_size;
}
#endif
if (!capture_dev_user_pmode_find(if_string, &device.pmode)) {
device.pmode = global_capture_opts.default_options.promisc_mode;
}
if (!capture_dev_user_snaplen_find(if_string, &device.has_snaplen,
&device.snaplen)) {
device.has_snaplen = global_capture_opts.default_options.has_snaplen;
device.snaplen = global_capture_opts.default_options.snaplen;
}
device.cfilter = g_strdup(global_capture_opts.default_options.cfilter);
monitor_mode = prefs_capture_device_monitor_mode(if_string);
if (roptions->remote_host_opts.auth_type == CAPTURE_AUTH_PWD) {
auth_str = g_strdup_printf("%s:%s", roptions->remote_host_opts.auth_username,
roptions->remote_host_opts.auth_password);
}
caps = capture_get_if_capabilities(if_string, monitor_mode, auth_str, NULL, main_window_update);
g_free(auth_str);
for (; (curr_addr = g_slist_nth(if_info->addrs, ips)) != NULL; ips++) {
address addr_str;
char* temp_addr_str = NULL;
if (ips != 0) {
g_string_append(ip_str, "\n");
}
addr = (if_addr_t *)curr_addr->data;
switch (addr->ifat_type) {
case IF_AT_IPv4:
set_address(&addr_str, AT_IPv4, 4, &addr->addr.ip4_addr);
temp_addr_str = (char*)address_to_str(NULL, &addr_str);
g_string_append(ip_str, temp_addr_str);
break;
case IF_AT_IPv6:
set_address(&addr_str, AT_IPv6, 16, addr->addr.ip6_addr);
temp_addr_str = (char*)address_to_str(NULL, &addr_str);
g_string_append(ip_str, temp_addr_str);
break;
default:
/* In case we add non-IP addresses */
break;
}
wmem_free(NULL, temp_addr_str);
} /* for curr_addr */
linktype_count = 0;
device.links = NULL;
if (caps != NULL) {
#ifdef HAVE_PCAP_CREATE
device.monitor_mode_enabled = monitor_mode;
device.monitor_mode_supported = caps->can_set_rfmon;
#endif
for (lt_entry = caps->data_link_types; lt_entry != NULL; lt_entry = g_list_next(lt_entry)) {
data_link_info = (data_link_info_t *)lt_entry->data;
linkr = (link_row *)g_malloc(sizeof(link_row));
/*
* For link-layer types libpcap/WinPcap doesn't know about, the
* name will be "DLT n", and the description will be null.
* We mark those as unsupported, and don't allow them to be
* used.
*/
if (data_link_info->description != NULL) {
linkr->name = g_strdup(data_link_info->description);
linkr->dlt = data_link_info->dlt;
} else {
linkr->name = g_strdup_printf("%s (not supported)", data_link_info->name);
linkr->dlt = -1;
}
if (linktype_count == 0) {
device.active_dlt = data_link_info->dlt;
}
device.links = g_list_append(device.links, linkr);
linktype_count++;
} /* for link_types */
} else {
#if defined(HAVE_PCAP_CREATE)
device.monitor_mode_enabled = FALSE;
device.monitor_mode_supported = FALSE;
#endif
device.active_dlt = -1;
}
device.addresses = g_strdup(ip_str->str);
device.no_addresses = ips;
device.remote_opts.src_type= roptions->src_type;
if (device.remote_opts.src_type == CAPTURE_IFREMOTE) {
device.local = FALSE;
}
device.remote_opts.remote_host_opts.remote_host = g_strdup(roptions->remote_host_opts.remote_host);
device.remote_opts.remote_host_opts.remote_port = g_strdup(roptions->remote_host_opts.remote_port);
device.remote_opts.remote_host_opts.auth_type = roptions->remote_host_opts.auth_type;
device.remote_opts.remote_host_opts.auth_username = g_strdup(roptions->remote_host_opts.auth_username);
device.remote_opts.remote_host_opts.auth_password = g_strdup(roptions->remote_host_opts.auth_password);
device.remote_opts.remote_host_opts.datatx_udp = roptions->remote_host_opts.datatx_udp;
device.remote_opts.remote_host_opts.nocap_rpcap = roptions->remote_host_opts.nocap_rpcap;
device.remote_opts.remote_host_opts.nocap_local = roptions->remote_host_opts.nocap_local;
#ifdef HAVE_PCAP_SETSAMPLING
device.remote_opts.sampling_method = roptions->sampling_method;
device.remote_opts.sampling_param = roptions->sampling_param;
#endif
device.selected = TRUE;
global_capture_opts.num_selected++;
g_array_append_val(global_capture_opts.all_ifaces, device);
g_string_free(ip_str, TRUE);
} /*for*/
}
void ManageInterfacesDialog::addRemoteInterfaces(GList* rlist, remote_options *roptions)
{
updateRemoteInterfaceList(rlist, roptions);
showRemoteInterfaces();
}
// We don't actually store these. When we do we should make sure they're stored
// securely using CryptProtectData, the macOS Keychain, GNOME Keyring, KWallet, etc.
void ManageInterfacesDialog::remoteAccepted()
{
QTreeWidgetItemIterator it(ui->remoteList);
while(*it) {
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if ((*it)->text(col_r_host_dev_).compare(device.name))
continue;
device.hidden = ((*it)->checkState(col_r_show_) == Qt::Checked ? false : true);
global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
g_array_insert_val(global_capture_opts.all_ifaces, i, device);
}
++it;
}
}
void ManageInterfacesDialog::on_remoteList_currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)
{
updateWidgets();
}
void ManageInterfacesDialog::on_remoteList_itemClicked(QTreeWidgetItem *item, int column)
{
if (!item || column != col_r_show_) {
return;
}
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if (!device.local) {
if (item->text(col_r_host_dev_).compare(device.name))
continue;
device.hidden = (item->checkState(col_r_show_) == Qt::Checked ? false : true);
}
}
}
void ManageInterfacesDialog::on_delRemote_clicked()
{
QTreeWidgetItem* item = ui->remoteList->currentItem();
if (!item) {
return;
}
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if (item->text(col_r_host_dev_).compare(device.remote_opts.remote_host_opts.remote_host))
continue;
global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
}
delete item;
fflush(stdout); // ???
}
void ManageInterfacesDialog::on_addRemote_clicked()
{
RemoteCaptureDialog *dlg = new RemoteCaptureDialog(this);
dlg->show();
}
void ManageInterfacesDialog::showRemoteInterfaces()
{
guint i;
interface_t device;
QTreeWidgetItem *item = NULL;
// We assume that remote interfaces are grouped by host.
for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
QTreeWidgetItem *child;
device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if (!device.local) {
if (!item || item->text(col_r_host_dev_).compare(device.remote_opts.remote_host_opts.remote_host) != 0) {
item = new QTreeWidgetItem(ui->remoteList);
item->setText(col_r_host_dev_, device.remote_opts.remote_host_opts.remote_host);
item->setExpanded(true);
}
child = new QTreeWidgetItem(item);
child->setCheckState(col_r_show_, device.hidden ? Qt::Unchecked : Qt::Checked);
child->setText(col_r_host_dev_, QString(device.name));
}
}
}
void ManageInterfacesDialog::on_remoteSettings_clicked()
{
guint i = 0;
interface_t device;
QTreeWidgetItem* item = ui->remoteList->currentItem();
if (!item) {
return;
}
for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if (!device.local) {
if (item->text(col_r_host_dev_).compare(device.name)) {
continue;
} else {
RemoteSettingsDialog *dlg = new RemoteSettingsDialog(this, &device);
dlg->show();
break;
}
}
}
}
void ManageInterfacesDialog::setRemoteSettings(interface_t *iface)
{
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
interface_t device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
if (!device.local) {
if (strcmp(iface->name, device.name)) {
continue;
}
device.remote_opts.remote_host_opts.nocap_rpcap = iface->remote_opts.remote_host_opts.nocap_rpcap;
device.remote_opts.remote_host_opts.datatx_udp = iface->remote_opts.remote_host_opts.datatx_udp;
#ifdef HAVE_PCAP_SETSAMPLING
device.remote_opts.sampling_method = iface->remote_opts.sampling_method;
device.remote_opts.sampling_param = iface->remote_opts.sampling_param;
#endif //HAVE_PCAP_SETSAMPLING
global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
g_array_insert_val(global_capture_opts.all_ifaces, i, device);
}
}
}
#endif // HAVE_PCAP_REMOTE
#endif /* HAVE_LIBPCAP */
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/