From 743f8598cd0b156c195b906400cdd0d3fcdeafe3 Mon Sep 17 00:00:00 2001 From: Roland Knall Date: Thu, 29 Aug 2019 17:30:29 +0200 Subject: [PATCH] Qt: Rework Resolved Addresses dialog This is a refactoring/redesign of the "Resolved Addresses" dialog, allowing for sorting/filtering and searching within the addresses and ports. Change-Id: I5071e92ff699323b6c93fc533eeaf92e0db334de Reviewed-on: https://code.wireshark.org/review/34398 Reviewed-by: Roland Knall Petri-Dish: Roland Knall Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- ui/qt/CMakeLists.txt | 2 + ui/qt/models/astringlist_list_model.cpp | 114 +++++- ui/qt/models/astringlist_list_model.h | 19 +- ui/qt/models/resolved_addresses_models.cpp | 253 ++++++++++++ ui/qt/models/resolved_addresses_models.h | 61 +++ ui/qt/resolved_addresses_dialog.cpp | 434 ++++----------------- ui/qt/resolved_addresses_dialog.h | 33 +- ui/qt/resolved_addresses_dialog.ui | 91 ++++- 8 files changed, 613 insertions(+), 394 deletions(-) create mode 100644 ui/qt/models/resolved_addresses_models.cpp create mode 100644 ui/qt/models/resolved_addresses_models.h diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index ea68c240b8..fe29e9bcd0 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -94,6 +94,7 @@ set(WIRESHARK_MODEL_HEADERS models/profile_model.h models/proto_tree_model.h models/related_packet_delegate.h + models/resolved_addresses_models.h models/sparkline_delegate.h models/supported_protocols_model.h models/timeline_delegate.h @@ -320,6 +321,7 @@ set(WIRESHARK_MODEL_SRCS models/profile_model.cpp models/proto_tree_model.cpp models/related_packet_delegate.cpp + models/resolved_addresses_models.cpp models/sparkline_delegate.cpp models/supported_protocols_model.cpp models/timeline_delegate.cpp diff --git a/ui/qt/models/astringlist_list_model.cpp b/ui/qt/models/astringlist_list_model.cpp index 2e6ef7cde9..04ea879b99 100644 --- a/ui/qt/models/astringlist_list_model.cpp +++ b/ui/qt/models/astringlist_list_model.cpp @@ -87,13 +87,21 @@ AStringListListSortFilterProxyModel::AStringListListSortFilterProxyModel(QObject : QSortFilterProxyModel(parent) { filter_ = QString(); - type_ = FilterByContains; + types_[-1] = FilterByContains; } bool AStringListListSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { - QString leftData = sourceModel()->data(left).toStringList().join(","); - QString rightData = sourceModel()->data(right).toStringList().join(","); + QString leftData = left.data().toString(); + QString rightData = right.data().toString(); + + if ( numericColumns_.contains(left.column()) || numericColumns_.contains(right.column() ) ) + { + float left = leftData.toFloat(); + float right = rightData.toFloat(); + + return left < right; + } return leftData.compare(rightData, sortCaseSensitivity()) < 0; } @@ -104,14 +112,23 @@ void AStringListListSortFilterProxyModel::setFilter(const QString & filter) invalidateFilter(); } -static bool AContainsB(const QString &a, const QString &b, Qt::CaseSensitivity cs) +static bool AContainsB(const QVariant &a, const QVariant &b, Qt::CaseSensitivity cs) { - return a.contains(b, cs); + if ( ! a.canConvert(QVariant::String) || ! b.canConvert(QVariant::String) ) + return false; + return a.toString().contains(b.toString(), cs); } -static bool AStartsWithB(const QString &a, const QString &b, Qt::CaseSensitivity cs) +static bool AStartsWithB(const QVariant &a, const QVariant &b, Qt::CaseSensitivity cs) { - return a.startsWith(b, cs); + if ( ! a.canConvert(QVariant::String) || ! b.canConvert(QVariant::String) ) + return false; + return a.toString().startsWith(b.toString(), cs); +} + +static bool AIsEquivalentToB(const QVariant &a, const QVariant &b, Qt::CaseSensitivity) +{ + return a == b; } bool AStringListListSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const @@ -125,12 +142,28 @@ bool AStringListListSortFilterProxyModel::filterAcceptsRow(int sourceRow, const continue; QModelIndex chkIdx = sourceModel()->index(sourceRow, column, sourceParent); - QString dataString = sourceModel()->data(chkIdx).toString(); + QString dataString = chkIdx.data().toString(); /* Default is filter by string a contains string b */ - bool (*compareFunc)(const QString&, const QString&, Qt::CaseSensitivity) = AContainsB; - if ( type_ == FilterByStart ) - compareFunc = AStartsWithB; + bool (*compareFunc)(const QVariant&, const QVariant&, Qt::CaseSensitivity) = AContainsB; + if ( types_.keys().contains(column) ) + { + switch (types_.value(column, FilterByContains)) + { + case FilterByStart: + compareFunc = AStartsWithB; + break; + case FilterByEquivalent: + compareFunc = AIsEquivalentToB; + break; + case FilterNone: + return true; + break; + default: + compareFunc = AContainsB; + break; + } + } if ( compareFunc(dataString, filter_, filterCaseSensitivity()) ) return true; @@ -139,12 +172,20 @@ bool AStringListListSortFilterProxyModel::filterAcceptsRow(int sourceRow, const return false; } -void AStringListListSortFilterProxyModel::setFilterType(AStringListListFilterType type) +void AStringListListSortFilterProxyModel::setFilterType(AStringListListFilterType type, int column) { - if ( type != type_ ) + if ( column >= -1 && column < columnCount() ) { - type_ = type; - invalidateFilter(); + if ( ! types_.keys().contains(column) ) + { + types_.insert(column, type); + invalidateFilter(); + } + else if ( types_.keys().contains(column) && type != types_[column] ) + { + types_[column] = type; + invalidateFilter(); + } } } @@ -163,6 +204,49 @@ void AStringListListSortFilterProxyModel::clearColumnsToFilter() invalidateFilter(); } +void AStringListListSortFilterProxyModel::clearHiddenColumns() +{ + hiddenColumns_.clear(); + invalidateFilter(); +} + +void AStringListListSortFilterProxyModel::setColumnToHide(int col) +{ + if ( ! hiddenColumns_.contains(col) && col > -1 && sourceModel() && sourceModel()->columnCount() > col ) + { + hiddenColumns_ << col; + invalidateFilter(); + } +} + +bool AStringListListSortFilterProxyModel::filterAcceptsColumn(int sourceColumn, const QModelIndex &sourceParent) const +{ + QModelIndex realIndex = sourceModel()->index(0, sourceColumn, sourceParent); + + if ( ! realIndex.isValid() ) + return false; + + if ( hiddenColumns_.contains(sourceColumn) ) + return false; + + return true; +} + +void AStringListListSortFilterProxyModel::clearNumericColumns() +{ + numericColumns_.clear(); + invalidateFilter(); +} + +void AStringListListSortFilterProxyModel::setColumnAsNumeric(int col) +{ + if ( ! numericColumns_.contains(col) && col > -1 && sourceModel() && sourceModel()->columnCount() > col ) + { + numericColumns_ << col; + invalidateFilter(); + } +} + AStringListListUrlProxyModel::AStringListListUrlProxyModel(QObject * parent): QIdentityProxyModel(parent) {} diff --git a/ui/qt/models/astringlist_list_model.h b/ui/qt/models/astringlist_list_model.h index 516540b36b..d21fe31a5a 100644 --- a/ui/qt/models/astringlist_list_model.h +++ b/ui/qt/models/astringlist_list_model.h @@ -50,27 +50,38 @@ public: enum AStringListListFilterType { FilterByContains = 0, - FilterByStart = 1 + FilterByStart, + FilterByEquivalent, + FilterNone }; + Q_ENUM(AStringListListFilterType) explicit AStringListListSortFilterProxyModel(QObject * parent = Q_NULLPTR); virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + virtual bool filterAcceptsColumn(int column, const QModelIndex &sourceParent) const; - void setFilterType(AStringListListFilterType type); + void setFilterType(AStringListListFilterType type, int column = -1); void setColumnToFilter(int); void clearColumnsToFilter(); + void clearHiddenColumns(); + void setColumnToHide(int col); + + void clearNumericColumns(); + void setColumnAsNumeric(int col); + public slots: void setFilter(const QString&); private: - QString filter_; - AStringListListFilterType type_; + QMap types_; QList columnsToFilter_; + QList hiddenColumns_; + QList numericColumns_; }; class AStringListListUrlProxyModel : public QIdentityProxyModel diff --git a/ui/qt/models/resolved_addresses_models.cpp b/ui/qt/models/resolved_addresses_models.cpp new file mode 100644 index 0000000000..a802991118 --- /dev/null +++ b/ui/qt/models/resolved_addresses_models.cpp @@ -0,0 +1,253 @@ +/* resolved_addresses_models.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include + +#include + +#include "file.h" + +#include "epan/addr_resolv.h" +#include + +extern "C" +{ + +static void +serv_port_hash_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) +{ + QStringList *string_list = (QStringList *) sl_ptr; + serv_port_t *serv_port = (serv_port_t *)value; + guint port = GPOINTER_TO_UINT(key); + + QStringList entries; + + if (serv_port->tcp_name) entries << QString("%1 %2 tcp").arg(serv_port->tcp_name).arg(port); + if (serv_port->udp_name) entries << QString("%1 %2 udp").arg(serv_port->udp_name).arg(port); + if (serv_port->sctp_name) entries << QString("%1 %2 sctp").arg(serv_port->sctp_name).arg(port); + if (serv_port->dccp_name) entries << QString("%1 %2 dccp").arg(serv_port->dccp_name).arg(port); + + if (!entries.isEmpty()) *string_list << entries.join("\n"); +} + +static void +ipv4_hash_table_resolved_to_qstringlist(gpointer, gpointer value, gpointer sl_ptr) +{ + QStringList *string_list = (QStringList *) sl_ptr; + hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *) value; + + if((ipv4_hash_table_entry->flags & NAME_RESOLVED)) { + QString entry = QString("%1\t%2") + .arg(ipv4_hash_table_entry->ip) + .arg(ipv4_hash_table_entry->name); + *string_list << entry; + } +} + +static void +ipv6_hash_table_resolved_to_qstringlist(gpointer, gpointer value, gpointer sl_ptr) +{ + QStringList *string_list = (QStringList *) sl_ptr; + hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *) value; + + if((ipv6_hash_table_entry->flags & NAME_RESOLVED)) { + QString entry = QString("%1\t%2") + .arg(ipv6_hash_table_entry->ip6) + .arg(ipv6_hash_table_entry->name); + *string_list << entry; + } +} + +static void +ipv4_hash_table_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) +{ + QStringList *string_list = (QStringList *) sl_ptr; + hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value; + guint addr = GPOINTER_TO_UINT(key); + + QString entry = QString("Key: 0x%1 IPv4: %2, Name: %3") + .arg(QString::number(addr, 16)) + .arg(ipv4_hash_table_entry->ip) + .arg(ipv4_hash_table_entry->name); + + *string_list << entry; +} + +static void +ipv6_hash_table_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) +{ + QStringList *string_list = (QStringList *) sl_ptr; + hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value; + guint addr = GPOINTER_TO_UINT(key); + + QString entry = QString("Key: 0x%1 IPv4: %2, Name: %3") + .arg(QString::number(addr, 16)) + .arg(ipv6_hash_table_entry->ip6) + .arg(ipv6_hash_table_entry->name); + + *string_list << entry; +} + +static void +eth_hash_to_qstringlist(gpointer, gpointer value, gpointer sl_ptr) +{ + QStringList *string_list = (QStringList *) sl_ptr; + hashether_t* tp = (hashether_t*)value; + + QString entry = QString("%1 %2") + .arg(get_hash_ether_hexaddr(tp)) + .arg(get_hash_ether_resolved_name(tp)); + + *string_list << entry; +} + +static void +manuf_hash_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) +{ + QStringList *string_list = (QStringList *) sl_ptr; + hashmanuf_t *manuf = (hashmanuf_t*)value; + guint eth_as_guint = GPOINTER_TO_UINT(key); + + QString entry = QString("%1:%2:%3 %4") + .arg((eth_as_guint >> 16 & 0xff), 2, 16, QChar('0')) + .arg((eth_as_guint >> 8 & 0xff), 2, 16, QChar('0')) + .arg((eth_as_guint & 0xff), 2, 16, QChar('0')) + .arg(get_hash_manuf_resolved_name(manuf)); + + *string_list << entry; +} + +static void +wka_hash_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) +{ + QStringList *string_list = (QStringList *) sl_ptr; + gchar *name = (gchar *)value; + guint8 *eth_addr = (guint8*)key; + + QString entry = QString("%1:%2:%3:%4:%5:%6 %7") + .arg(eth_addr[0], 2, 16, QChar('0')) + .arg(eth_addr[1], 2, 16, QChar('0')) + .arg(eth_addr[2], 2, 16, QChar('0')) + .arg(eth_addr[3], 2, 16, QChar('0')) + .arg(eth_addr[4], 2, 16, QChar('0')) + .arg(eth_addr[5], 2, 16, QChar('0')) + .arg(name); + + *string_list << entry; +} + +} + +EthernetAddressModel::EthernetAddressModel(QObject * parent): + AStringListListModel(parent) +{ + populate(); +} + +QStringList EthernetAddressModel::headerColumns() const +{ + return QStringList() << tr("Type") << tr("Mac Address") << tr("Name"); +} + +QStringList EthernetAddressModel::filterValues() const +{ + return QStringList() + << tr("All entries") + << tr("IPv4 Hosts") << tr("IPv4 Hash Table") + << tr("IPv6 Hosts") << tr("IPv6 Hash Table") + << tr("Ethernet Addresses") << tr("Ethernet Manufacturers") + << tr("Ethernet Well-Known Addresses"); +} + +void EthernetAddressModel::populate() +{ + QStringList values; + wmem_map_t *ipv4_hash_table = get_ipv4_hash_table(); + if (ipv4_hash_table) { + wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_resolved_to_qstringlist, &values); + foreach(QString line, values) + appendRow(QStringList() << tr("IPv4 Hosts") << line.split(" ")); + wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_to_qstringlist, &values); + foreach(QString line, values) + appendRow(QStringList() << tr("IPv4 Hash Table") << line.split(" ")); + } + + wmem_map_t *ipv6_hash_table = get_ipv6_hash_table(); + if (ipv6_hash_table) { + wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_resolved_to_qstringlist, &values); + foreach(QString line, values) + appendRow(QStringList() << tr("IPv6 Hosts") << line.split(" ")); + wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_to_qstringlist, &values); + foreach(QString line, values) + appendRow(QStringList() << tr("IPv6 Hash Table") << line.split(" ")); + } + + wmem_map_t *eth_hashtable = get_eth_hashtable(); + if (eth_hashtable) + wmem_map_foreach(eth_hashtable, eth_hash_to_qstringlist, &values); + foreach(QString line, values) + appendRow(QStringList() << tr("Ethernet Addresses") << line.split(" ")); + + eth_hashtable = get_manuf_hashtable(); + if (eth_hashtable) + wmem_map_foreach(eth_hashtable, manuf_hash_to_qstringlist, &values); + + foreach(QString line, values) + appendRow(QStringList() << tr("Ethernet Manufacturers") << line.split(" ")); + + eth_hashtable = get_wka_hashtable(); + if (eth_hashtable) + wmem_map_foreach(eth_hashtable, wka_hash_to_qstringlist, &values); + + foreach(QString line, values) + appendRow(QStringList() << tr("Ethernet Well-Known Addresses") << line.split(" ")); +} + +PortsModel::PortsModel(QObject * parent): + AStringListListModel(parent) +{ + populate(); +} + +QStringList PortsModel::filterValues() const +{ + return QStringList() + << tr("All entries") << tr("tcp") << tr("udp") << tr("sctp") << tr("dccp"); +} + +QStringList PortsModel::headerColumns() const +{ + return QStringList() << tr("Name") << tr("Port") << tr("Type"); +} + +void PortsModel::populate() +{ + QStringList values; + + wmem_map_t *serv_port_hashtable = get_serv_port_hashtable(); + if(serv_port_hashtable){ + wmem_map_foreach(serv_port_hashtable, serv_port_hash_to_qstringlist, &values); + } + + foreach(QString line, values) + appendRow(QStringList() << line.split(" ")); +} + +/* + * 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: + */ diff --git a/ui/qt/models/resolved_addresses_models.h b/ui/qt/models/resolved_addresses_models.h new file mode 100644 index 0000000000..852d371e48 --- /dev/null +++ b/ui/qt/models/resolved_addresses_models.h @@ -0,0 +1,61 @@ +/* resolved_addresses_models.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef RESOLVED_ADDRESSES_MODELS_H +#define RESOLVED_ADDRESSES_MODELS_H + +#include + +#include +#include + +class EthernetAddressModel : public AStringListListModel +{ + Q_OBJECT + +public: + EthernetAddressModel(QObject * parent = Q_NULLPTR); + + QStringList filterValues() const; + +protected: + QStringList headerColumns() const override; + void populate(); + +}; + +class PortsModel : public AStringListListModel +{ + Q_OBJECT + +public: + PortsModel(QObject * parent = Q_NULLPTR); + + QStringList filterValues() const; + +protected: + QStringList headerColumns() const override; + void populate(); + +}; + +#endif // RESOLVED_ADDRESSES_MODELS_H + +/* + * 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: + */ diff --git a/ui/qt/resolved_addresses_dialog.cpp b/ui/qt/resolved_addresses_dialog.cpp index 6ac7c17965..c6c669cccc 100644 --- a/ui/qt/resolved_addresses_dialog.cpp +++ b/ui/qt/resolved_addresses_dialog.cpp @@ -22,150 +22,23 @@ #include #include #include +#include #include "capture_file.h" #include "wireshark_application.h" -// To do: -// - We do a *lot* of string copying. -// - We end up with a lot of numeric entries here. +#include +#include -extern "C" { - -static void -ipv4_hash_table_resolved_to_qstringlist(gpointer, gpointer value, gpointer sl_ptr) -{ - QStringList *string_list = (QStringList *) sl_ptr; - hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *) value; - - if((ipv4_hash_table_entry->flags & NAME_RESOLVED)) { - QString entry = QString("%1\t%2") - .arg(ipv4_hash_table_entry->ip) - .arg(ipv4_hash_table_entry->name); - *string_list << entry; - } -} - -static void -ipv6_hash_table_resolved_to_qstringlist(gpointer, gpointer value, gpointer sl_ptr) -{ - QStringList *string_list = (QStringList *) sl_ptr; - hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *) value; - - if((ipv6_hash_table_entry->flags & NAME_RESOLVED)) { - QString entry = QString("%1\t%2") - .arg(ipv6_hash_table_entry->ip6) - .arg(ipv6_hash_table_entry->name); - *string_list << entry; - } -} - -static void -ipv4_hash_table_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) -{ - QStringList *string_list = (QStringList *) sl_ptr; - hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value; - guint addr = GPOINTER_TO_UINT(key); - - QString entry = QString("Key: 0x%1 IPv4: %2, Name: %3") - .arg(QString::number(addr, 16)) - .arg(ipv4_hash_table_entry->ip) - .arg(ipv4_hash_table_entry->name); - - *string_list << entry; -} - -static void -ipv6_hash_table_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) -{ - QStringList *string_list = (QStringList *) sl_ptr; - hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value; - guint addr = GPOINTER_TO_UINT(key); - - QString entry = QString("Key: 0x%1 IPv4: %2, Name: %3") - .arg(QString::number(addr, 16)) - .arg(ipv6_hash_table_entry->ip6) - .arg(ipv6_hash_table_entry->name); - - *string_list << entry; -} - -static void -serv_port_hash_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) -{ - QStringList *string_list = (QStringList *) sl_ptr; - serv_port_t *serv_port = (serv_port_t *)value; - guint port = GPOINTER_TO_UINT(key); - - QStringList entries; - - if (serv_port->tcp_name) entries << QString("%1\t%2/tcp").arg(serv_port->tcp_name).arg(port); - if (serv_port->udp_name) entries << QString("%1\t%2/udp").arg(serv_port->udp_name).arg(port); - if (serv_port->sctp_name) entries << QString("%1\t%2/sctp").arg(serv_port->sctp_name).arg(port); - if (serv_port->dccp_name) entries << QString("%1\t%2/dccp").arg(serv_port->dccp_name).arg(port); - - if (!entries.isEmpty()) *string_list << entries.join("\n"); -} - -static void -eth_hash_to_qstringlist(gpointer, gpointer value, gpointer sl_ptr) -{ - QStringList *string_list = (QStringList *) sl_ptr; - hashether_t* tp = (hashether_t*)value; - - QString entry = QString("%1 %2") - .arg(get_hash_ether_hexaddr(tp)) - .arg(get_hash_ether_resolved_name(tp)); - - *string_list << entry; -} - -static void -manuf_hash_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) -{ - QStringList *string_list = (QStringList *) sl_ptr; - hashmanuf_t *manuf = (hashmanuf_t*)value; - guint eth_as_guint = GPOINTER_TO_UINT(key); - - QString entry = QString("%1:%2:%3 %4") - .arg((eth_as_guint >> 16 & 0xff), 2, 16, QChar('0')) - .arg((eth_as_guint >> 8 & 0xff), 2, 16, QChar('0')) - .arg((eth_as_guint & 0xff), 2, 16, QChar('0')) - .arg(get_hash_manuf_resolved_name(manuf)); - - *string_list << entry; -} - -static void -wka_hash_to_qstringlist(gpointer key, gpointer value, gpointer sl_ptr) -{ - QStringList *string_list = (QStringList *) sl_ptr; - gchar *name = (gchar *)value; - guint8 *eth_addr = (guint8*)key; - - QString entry = QString("%1:%2:%3:%4:%5:%6 %7") - .arg(eth_addr[0], 2, 16, QChar('0')) - .arg(eth_addr[1], 2, 16, QChar('0')) - .arg(eth_addr[2], 2, 16, QChar('0')) - .arg(eth_addr[3], 2, 16, QChar('0')) - .arg(eth_addr[4], 2, 16, QChar('0')) - .arg(eth_addr[5], 2, 16, QChar('0')) - .arg(name); - - *string_list << entry; -} - -} const QString no_entries_ = QObject::tr("No entries."); const QString entry_count_ = QObject::tr("%1 entries."); ResolvedAddressesDialog::ResolvedAddressesDialog(QWidget *parent, CaptureFile *capture_file) : - GeometryStateDialog(NULL), + GeometryStateDialog(parent), ui(new Ui::ResolvedAddressesDialog), file_name_(tr("[no file]")) { ui->setupUi(this); - if (parent) loadGeometry(parent->width() * 2 / 3, parent->height()); setAttribute(Qt::WA_DeleteOnClose, true); QStringList title_parts = QStringList() << tr("Resolved Addresses"); @@ -203,40 +76,39 @@ ResolvedAddressesDialog::ResolvedAddressesDialog(QWidget *parent, CaptureFile *c } } - wmem_map_t *ipv4_hash_table = get_ipv4_hash_table(); - if (ipv4_hash_table) { - wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_resolved_to_qstringlist, &host_addresses_); - wmem_map_foreach(ipv4_hash_table, ipv4_hash_table_to_qstringlist, &v4_hash_addrs_); - } - - wmem_map_t *ipv6_hash_table = get_ipv6_hash_table(); - if (ipv6_hash_table) { - wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_resolved_to_qstringlist, &host_addresses_); - wmem_map_foreach(ipv6_hash_table, ipv6_hash_table_to_qstringlist, &v6_hash_addrs_); - } - - wmem_map_t *serv_port_hashtable = get_serv_port_hashtable(); - if(serv_port_hashtable){ - wmem_map_foreach(serv_port_hashtable, serv_port_hash_to_qstringlist, &service_ports_); - } - - wmem_map_t *eth_hashtable = get_eth_hashtable(); - if (eth_hashtable){ - wmem_map_foreach(eth_hashtable, eth_hash_to_qstringlist, ðernet_addresses_); - } - - wmem_map_t *manuf_hashtable = get_manuf_hashtable(); - if (manuf_hashtable){ - wmem_map_foreach(manuf_hashtable, manuf_hash_to_qstringlist, ðernet_manufacturers_); - } - - wmem_map_t *wka_hashtable = get_wka_hashtable(); - if(wka_hashtable){ - wmem_map_foreach(wka_hashtable, wka_hash_to_qstringlist, ðernet_well_known_); - } - - fillShowMenu(); fillBlocks(); + + ethSortModel = new AStringListListSortFilterProxyModel(this); + ethTypeModel = new AStringListListSortFilterProxyModel(this); + EthernetAddressModel * ethModel = new EthernetAddressModel(this); + ethSortModel->setSourceModel(ethModel); + ethSortModel->setColumnToFilter(1); + ethSortModel->setColumnToFilter(2); + ethSortModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + ethTypeModel->setSourceModel(ethSortModel); + ethTypeModel->setColumnToFilter(0); + ethTypeModel->setColumnToHide(0); + ui->tblAddresses->setModel(ethTypeModel); + ui->tblAddresses->resizeColumnsToContents(); + ui->tblAddresses->horizontalHeader()->setStretchLastSection(true); + ui->tblAddresses->sortByColumn(1, Qt::AscendingOrder); + ui->cmbDataType->addItems(ethModel->filterValues()); + + portSortModel = new AStringListListSortFilterProxyModel(this); + portTypeModel = new AStringListListSortFilterProxyModel(this); + PortsModel * portModel = new PortsModel(this); + portSortModel->setSourceModel(portModel); + portSortModel->setColumnAsNumeric(1); + portSortModel->setColumnToFilter(0); + portSortModel->setColumnToFilter(1); + portSortModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + portTypeModel->setSourceModel(portSortModel); + portTypeModel->setColumnToFilter(2); + ui->tblPorts->setModel(portTypeModel); + ui->tblPorts->resizeColumnsToContents(); + ui->tblPorts->horizontalHeader()->setStretchLastSection(true); + ui->tblPorts->sortByColumn(1, Qt::AscendingOrder); + ui->cmbPortFilterType->addItems(portModel->filterValues()); } ResolvedAddressesDialog::~ResolvedAddressesDialog() @@ -244,6 +116,54 @@ ResolvedAddressesDialog::~ResolvedAddressesDialog() delete ui; } +void ResolvedAddressesDialog::on_cmbDataType_currentIndexChanged(QString) +{ + if ( ! ethSortModel ) + return; + + QString filter = ui->cmbDataType->currentText(); + if ( ui->cmbDataType->currentIndex() == 0 ) + { + filter.clear(); + ethTypeModel->setFilterType(AStringListListSortFilterProxyModel::FilterNone, 0); + } + else + ethTypeModel->setFilterType(AStringListListSortFilterProxyModel::FilterByEquivalent, 0); + ethTypeModel->setFilter(filter); +} + +void ResolvedAddressesDialog::on_txtSearchFilter_textChanged(QString) +{ + if ( ! ethSortModel || ui->txtSearchFilter->text().length() < 3 ) + return; + + ethSortModel->setFilter(ui->txtSearchFilter->text()); +} + +void ResolvedAddressesDialog::on_cmbPortFilterType_currentIndexChanged(QString) +{ + if ( ! portSortModel ) + return; + + QString filter = ui->cmbPortFilterType->currentText(); + if ( ui->cmbPortFilterType->currentIndex() == 0 ) + { + filter.clear(); + portTypeModel->setFilterType(AStringListListSortFilterProxyModel::FilterNone, 2); + } + else + portTypeModel->setFilterType(AStringListListSortFilterProxyModel::FilterByEquivalent, 2); + portTypeModel->setFilter(filter); +} + +void ResolvedAddressesDialog::on_txtPortFilter_textChanged(QString val) +{ + if ( ! portSortModel ) + return; + + portSortModel->setFilter(val); +} + void ResolvedAddressesDialog::changeEvent(QEvent *event) { if (0 != event) @@ -252,7 +172,6 @@ void ResolvedAddressesDialog::changeEvent(QEvent *event) { case QEvent::LanguageChange: ui->retranslateUi(this); - fillShowMenu(); fillBlocks(); break; default: @@ -262,32 +181,6 @@ void ResolvedAddressesDialog::changeEvent(QEvent *event) QDialog::changeEvent(event); } -void ResolvedAddressesDialog::fillShowMenu() -{ - QPushButton *show_bt = ui->buttonBox->button(QDialogButtonBox::Apply); - show_bt->setText(tr("Show")); - - if (!show_bt->menu()) { - show_bt->setMenu(new QMenu(show_bt)); - } - - QMenu *show_menu = show_bt->menu(); - show_menu->clear(); - - show_menu->addAction(ui->actionAddressesHosts); - show_menu->addAction(ui->actionComment); - show_menu->addAction(ui->actionIPv4HashTable); - show_menu->addAction(ui->actionIPv6HashTable); - show_menu->addAction(ui->actionPortNames); - show_menu->addAction(ui->actionEthernetAddresses); - show_menu->addAction(ui->actionEthernetManufacturers); - show_menu->addAction(ui->actionEthernetWKA); - - show_menu->addSeparator(); - show_menu->addAction(ui->actionShowAll); - show_menu->addAction(ui->actionHideAll); -} - void ResolvedAddressesDialog::fillBlocks() { setUpdatesEnabled(false); @@ -309,169 +202,10 @@ void ResolvedAddressesDialog::fillBlocks() ui->plainTextEdit->appendPlainText(lines); } - if (ui->actionAddressesHosts->isChecked()) { - lines = "\n"; - lines.append(tr("# Hosts\n#\n# ")); - if (!host_addresses_.isEmpty()) { - lines.append(entry_count_.arg(host_addresses_.length())); - lines.append("\n\n"); - lines.append(host_addresses_.join("\n")); - } else { - lines.append(no_entries_); - } - ui->plainTextEdit->appendPlainText(lines); - } - - if (ui->actionIPv4HashTable->isChecked()) { - lines = "\n"; - lines.append(tr("# IPv4 Hash Table\n#\n# ")); - if (!v4_hash_addrs_.isEmpty()) { - lines.append(entry_count_.arg(v4_hash_addrs_.length())); - lines.append(tr("\n\n")); - lines.append(v4_hash_addrs_.join("\n")); - } else { - lines.append(no_entries_); - } - ui->plainTextEdit->appendPlainText(lines); - } - - if (ui->actionIPv6HashTable->isChecked()) { - lines = "\n"; - lines.append(tr("# IPv6 Hash Table\n#\n# ")); - if (!v6_hash_addrs_.isEmpty()) { - lines.append(entry_count_.arg(v6_hash_addrs_.length())); - lines.append(tr("\n\n")); - lines.append(v6_hash_addrs_.join("\n")); - } else { - lines.append(no_entries_); - } - ui->plainTextEdit->appendPlainText(lines); - } - - if (ui->actionPortNames->isChecked()) { - lines = "\n"; - lines.append(tr("# Services\n#\n# ")); - if (!service_ports_.isEmpty()) { - lines.append(entry_count_.arg(service_ports_.length())); - lines.append(tr("\n\n")); - lines.append(service_ports_.join("\n")); - } else { - lines.append(no_entries_); - } - ui->plainTextEdit->appendPlainText(lines); - } - - if (ui->actionEthernetAddresses->isChecked()) { - lines = "\n"; - lines.append(tr("# Ethernet addresses\n#\n# ")); - if (!ethernet_addresses_.isEmpty()) { - lines.append(entry_count_.arg(ethernet_addresses_.length())); - lines.append(tr("\n\n")); - lines.append(ethernet_addresses_.join("\n")); - } else { - lines.append(no_entries_); - } - ui->plainTextEdit->appendPlainText(lines); - } - - if (ui->actionEthernetManufacturers->isChecked()) { - lines = "\n"; - lines.append(tr("# Ethernet manufacturers\n#\n# ")); - if (!ethernet_manufacturers_.isEmpty()) { - lines.append(entry_count_.arg(ethernet_manufacturers_.length())); - lines.append(tr("\n\n")); - lines.append(ethernet_manufacturers_.join("\n")); - } else { - lines.append(no_entries_); - } - ui->plainTextEdit->appendPlainText(lines); - } - - if (ui->actionEthernetWKA->isChecked()) { - lines = "\n"; - lines.append(tr("# Well known Ethernet addresses\n#\n# ")); - if (!ethernet_well_known_.isEmpty()) { - lines.append(entry_count_.arg(ethernet_well_known_.length())); - lines.append(tr("\n\n")); - lines.append(ethernet_well_known_.join("\n")); - } else { - lines.append(no_entries_); - } - ui->plainTextEdit->appendPlainText(lines); - } - ui->plainTextEdit->moveCursor(QTextCursor::Start); setUpdatesEnabled(true); } -void ResolvedAddressesDialog::on_actionAddressesHosts_triggered() -{ - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionComment_triggered() -{ - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionIPv4HashTable_triggered() -{ - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionIPv6HashTable_triggered() -{ - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionPortNames_triggered() -{ - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionEthernetAddresses_triggered() -{ - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionEthernetManufacturers_triggered() -{ - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionEthernetWKA_triggered() -{ - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionShowAll_triggered() -{ - ui->actionAddressesHosts->setChecked(true); - ui->actionComment->setChecked(true); - ui->actionIPv4HashTable->setChecked(true); - ui->actionIPv6HashTable->setChecked(true); - ui->actionPortNames->setChecked(true); - ui->actionEthernetAddresses->setChecked(true); - ui->actionEthernetManufacturers->setChecked(true); - ui->actionEthernetWKA->setChecked(true); - - fillBlocks(); -} - -void ResolvedAddressesDialog::on_actionHideAll_triggered() -{ - ui->actionAddressesHosts->setChecked(false); - ui->actionComment->setChecked(false); - ui->actionIPv4HashTable->setChecked(false); - ui->actionIPv6HashTable->setChecked(false); - ui->actionPortNames->setChecked(false); - ui->actionEthernetAddresses->setChecked(false); - ui->actionEthernetManufacturers->setChecked(false); - ui->actionEthernetWKA->setChecked(false); - - fillBlocks(); -} - /* * Editor modelines * diff --git a/ui/qt/resolved_addresses_dialog.h b/ui/qt/resolved_addresses_dialog.h index 99735ca3c1..58272d55f1 100644 --- a/ui/qt/resolved_addresses_dialog.h +++ b/ui/qt/resolved_addresses_dialog.h @@ -13,7 +13,7 @@ #include "geometry_state_dialog.h" class CaptureFile; -class QTextBlock; +class AStringListListSortFilterProxyModel; namespace Ui { class ResolvedAddressesDialog; @@ -28,34 +28,23 @@ public: ~ResolvedAddressesDialog(); protected slots: + void on_cmbDataType_currentIndexChanged(QString val); + void on_txtSearchFilter_textChanged(QString text); + void on_cmbPortFilterType_currentIndexChanged(QString val); + void on_txtPortFilter_textChanged(QString text); + void changeEvent(QEvent* event); -private slots: - void on_actionAddressesHosts_triggered(); - void on_actionComment_triggered(); - void on_actionIPv4HashTable_triggered(); - void on_actionIPv6HashTable_triggered(); - void on_actionPortNames_triggered(); - void on_actionEthernetAddresses_triggered(); - void on_actionEthernetManufacturers_triggered(); - void on_actionEthernetWKA_triggered(); - - void on_actionShowAll_triggered(); - void on_actionHideAll_triggered(); - private: Ui::ResolvedAddressesDialog *ui; QString file_name_; QString comment_; - QStringList host_addresses_; - QStringList v4_hash_addrs_; - QStringList v6_hash_addrs_; - QStringList service_ports_; - QStringList ethernet_addresses_; - QStringList ethernet_manufacturers_; - QStringList ethernet_well_known_; - void fillShowMenu(); + AStringListListSortFilterProxyModel * ethSortModel; + AStringListListSortFilterProxyModel * ethTypeModel; + AStringListListSortFilterProxyModel * portSortModel; + AStringListListSortFilterProxyModel * portTypeModel; + void fillBlocks(); }; diff --git a/ui/qt/resolved_addresses_dialog.ui b/ui/qt/resolved_addresses_dialog.ui index c5ab5c6946..a1a194e9d4 100644 --- a/ui/qt/resolved_addresses_dialog.ui +++ b/ui/qt/resolved_addresses_dialog.ui @@ -13,9 +13,94 @@ Dialog - + - + + + 0 + + + + Hosts + + + + + + + + Search for entry (min 3 characters) + + + + + + + + + + + + QAbstractItemView::NoEditTriggers + + + true + + + true + + + true + + + false + + + + + + + + Ports + + + + + + + + Search for port or name + + + + + + + + + + + + true + + + false + + + + + + + + Capture File Comments + + + + + + + + @@ -23,7 +108,7 @@ Qt::Horizontal - QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::Close