2014-08-06 17:07:42 +00:00
|
|
|
/* endpoint_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 "endpoint_dialog.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
#include <GeoIP.h>
|
|
|
|
#include <epan/geoip_db.h>
|
|
|
|
#include <wsutil/pint.h>
|
|
|
|
#endif
|
|
|
|
|
2016-01-12 19:02:58 +00:00
|
|
|
#include <epan/prefs.h>
|
|
|
|
|
2014-08-06 17:07:42 +00:00
|
|
|
#include "ui/recent.h"
|
|
|
|
#include "ui/traffic_table_ui.h"
|
|
|
|
|
|
|
|
#include "wsutil/str_util.h"
|
|
|
|
|
|
|
|
#include "qt_ui_utils.h"
|
|
|
|
#include "wireshark_application.h"
|
|
|
|
|
2015-02-08 20:24:19 +00:00
|
|
|
#include <QCheckBox>
|
2014-09-05 18:17:17 +00:00
|
|
|
#include <QDesktopServices>
|
2015-02-08 20:24:19 +00:00
|
|
|
#include <QDialogButtonBox>
|
2014-08-06 17:07:42 +00:00
|
|
|
#include <QMessageBox>
|
2015-02-08 20:24:19 +00:00
|
|
|
#include <QPushButton>
|
2014-09-05 18:17:17 +00:00
|
|
|
#include <QUrl>
|
2014-08-06 17:07:42 +00:00
|
|
|
|
2016-06-22 17:56:30 +00:00
|
|
|
static const QString table_name_ = QObject::tr("Endpoint");
|
2014-12-22 23:51:36 +00:00
|
|
|
EndpointDialog::EndpointDialog(QWidget &parent, CaptureFile &cf, int cli_proto_id, const char *filter) :
|
2014-08-06 17:07:42 +00:00
|
|
|
TrafficTableDialog(parent, cf, filter, table_name_)
|
|
|
|
{
|
2014-09-05 18:17:17 +00:00
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
map_bt_ = buttonBox()->addButton(tr("Map"), QDialogButtonBox::ActionRole);
|
|
|
|
map_bt_->setToolTip(tr("Draw IPv4 or IPv6 endpoints on a map."));
|
|
|
|
connect(map_bt_, SIGNAL(clicked()), this, SLOT(createMap()));
|
|
|
|
|
|
|
|
connect(trafficTableTabWidget(), SIGNAL(currentChanged(int)), this, SLOT(tabChanged()));
|
|
|
|
#endif
|
|
|
|
|
2015-08-24 19:33:49 +00:00
|
|
|
addProgressFrame(&parent);
|
|
|
|
|
2014-08-06 17:07:42 +00:00
|
|
|
QList<int> endp_protos;
|
|
|
|
for (GList *endp_tab = recent.endpoint_tabs; endp_tab; endp_tab = endp_tab->next) {
|
|
|
|
int proto_id = proto_get_id_by_short_name((const char *)endp_tab->data);
|
|
|
|
if (proto_id > -1 && !endp_protos.contains(proto_id)) {
|
|
|
|
endp_protos.append(proto_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (endp_protos.isEmpty()) {
|
|
|
|
endp_protos = defaultProtos();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bring the command-line specified type to the front.
|
|
|
|
if (get_conversation_by_proto_id(cli_proto_id)) {
|
|
|
|
endp_protos.removeAll(cli_proto_id);
|
|
|
|
endp_protos.prepend(cli_proto_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
// QTabWidget selects the first item by default.
|
|
|
|
foreach (int endp_proto, endp_protos) {
|
|
|
|
addTrafficTable(get_conversation_by_proto_id(endp_proto));
|
|
|
|
}
|
|
|
|
|
|
|
|
fillTypeMenu(endp_protos);
|
|
|
|
|
2014-09-18 14:26:35 +00:00
|
|
|
#ifdef HAVE_GEOIP
|
2014-09-05 18:17:17 +00:00
|
|
|
tabChanged();
|
2014-09-18 14:26:35 +00:00
|
|
|
#endif
|
2016-06-23 20:10:52 +00:00
|
|
|
|
2016-09-13 11:37:11 +00:00
|
|
|
QPushButton *close_bt = buttonBox()->button(QDialogButtonBox::Close);
|
|
|
|
if (close_bt) {
|
|
|
|
close_bt->setDefault(true);
|
|
|
|
}
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
updateWidgets();
|
|
|
|
// currentTabChanged();
|
2014-08-06 17:07:42 +00:00
|
|
|
|
2015-07-29 17:36:46 +00:00
|
|
|
cap_file_.delayedRetapPackets();
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EndpointDialog::~EndpointDialog()
|
|
|
|
{
|
|
|
|
prefs_clear_string_list(recent.endpoint_tabs);
|
|
|
|
recent.endpoint_tabs = NULL;
|
|
|
|
|
|
|
|
EndpointTreeWidget *cur_tree = qobject_cast<EndpointTreeWidget *>(trafficTableTabWidget()->currentWidget());
|
|
|
|
foreach (QAction *ea, traffic_type_menu_.actions()) {
|
|
|
|
int proto_id = ea->data().value<int>();
|
|
|
|
if (proto_id_to_tree_.contains(proto_id) && ea->isChecked()) {
|
|
|
|
char *title = g_strdup(proto_get_protocol_short_name(find_protocol_by_id(proto_id)));
|
|
|
|
if (proto_id_to_tree_[proto_id] == cur_tree) {
|
|
|
|
recent.endpoint_tabs = g_list_prepend(recent.endpoint_tabs, title);
|
|
|
|
} else {
|
|
|
|
recent.endpoint_tabs = g_list_append(recent.endpoint_tabs, title);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-21 21:23:02 +00:00
|
|
|
void EndpointDialog::captureFileClosing()
|
2014-08-06 17:07:42 +00:00
|
|
|
{
|
2014-12-21 21:23:02 +00:00
|
|
|
// Keep the dialog around but disable any controls that depend
|
|
|
|
// on a live capture file.
|
|
|
|
for (int i = 0; i < trafficTableTabWidget()->count(); i++) {
|
|
|
|
EndpointTreeWidget *cur_tree = qobject_cast<EndpointTreeWidget *>(trafficTableTabWidget()->widget(i));
|
2016-06-22 19:44:02 +00:00
|
|
|
disconnect(cur_tree, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
|
|
|
|
this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
2014-12-21 21:23:02 +00:00
|
|
|
displayFilterCheckBox()->setEnabled(false);
|
|
|
|
enabledTypesPushButton()->setEnabled(false);
|
|
|
|
TrafficTableDialog::captureFileClosing();
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool EndpointDialog::addTrafficTable(register_ct_t *table)
|
|
|
|
{
|
|
|
|
int proto_id = get_conversation_proto_id(table);
|
|
|
|
|
|
|
|
if (!table || proto_id_to_tree_.contains(proto_id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
EndpointTreeWidget *endp_tree = new EndpointTreeWidget(this, table);
|
|
|
|
|
|
|
|
proto_id_to_tree_[proto_id] = endp_tree;
|
|
|
|
const char* table_name = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
|
|
|
|
|
|
|
|
trafficTableTabWidget()->addTab(endp_tree, table_name);
|
|
|
|
|
|
|
|
connect(endp_tree, SIGNAL(titleChanged(QWidget*,QString)),
|
|
|
|
this, SLOT(setTabText(QWidget*,QString)));
|
2016-06-22 19:44:02 +00:00
|
|
|
connect(endp_tree, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)),
|
|
|
|
this, SIGNAL(filterAction(QString,FilterAction::Action,FilterAction::ActionType)));
|
2014-08-06 17:07:42 +00:00
|
|
|
connect(nameResolutionCheckBox(), SIGNAL(toggled(bool)),
|
|
|
|
endp_tree, SLOT(setNameResolutionEnabled(bool)));
|
|
|
|
|
|
|
|
// XXX Move to ConversationTreeWidget ctor?
|
2014-11-29 18:29:26 +00:00
|
|
|
QByteArray filter_utf8;
|
2014-08-06 17:07:42 +00:00
|
|
|
const char *filter = NULL;
|
|
|
|
if (displayFilterCheckBox()->isChecked()) {
|
2014-12-21 21:23:02 +00:00
|
|
|
filter = cap_file_.capFile()->dfilter;
|
2014-08-06 17:07:42 +00:00
|
|
|
} else if (!filter_.isEmpty()) {
|
2014-11-29 18:29:26 +00:00
|
|
|
filter_utf8 = filter_.toUtf8();
|
|
|
|
filter = filter_utf8.constData();
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
endp_tree->trafficTreeHash()->user_data = endp_tree;
|
|
|
|
|
2015-08-24 19:30:56 +00:00
|
|
|
registerTapListener(proto_get_protocol_filter_name(proto_id), endp_tree->trafficTreeHash(), filter, 0,
|
|
|
|
EndpointTreeWidget::tapReset,
|
|
|
|
get_hostlist_packet_func(table),
|
|
|
|
EndpointTreeWidget::tapDraw);
|
2014-08-06 17:07:42 +00:00
|
|
|
|
2014-09-05 18:17:17 +00:00
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
connect(endp_tree, SIGNAL(geoIPStatusChanged()), this, SLOT(tabChanged()));
|
|
|
|
#endif
|
2014-08-06 17:07:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-05 18:17:17 +00:00
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
void EndpointDialog::tabChanged()
|
|
|
|
{
|
|
|
|
EndpointTreeWidget *cur_tree = qobject_cast<EndpointTreeWidget *>(trafficTableTabWidget()->currentWidget());
|
2014-11-08 11:30:39 +00:00
|
|
|
map_bt_->setEnabled(cur_tree && cur_tree->hasGeoIPData());
|
2014-09-05 18:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EndpointDialog::createMap()
|
|
|
|
{
|
|
|
|
EndpointTreeWidget *cur_tree = qobject_cast<EndpointTreeWidget *>(trafficTableTabWidget()->currentWidget());
|
|
|
|
if (!cur_tree) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar *err_str;
|
|
|
|
gchar *map_path = create_endpoint_geoip_map(cur_tree->trafficTreeHash()->conv_array, &err_str);
|
|
|
|
if (!map_path) {
|
2014-11-27 10:11:18 +00:00
|
|
|
QMessageBox::warning(this, tr("Map file error"), err_str);
|
2014-09-05 18:17:17 +00:00
|
|
|
g_free(err_str);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(gchar_free_to_qstring(map_path)));
|
|
|
|
}
|
2014-09-18 14:26:35 +00:00
|
|
|
#endif
|
2014-09-05 18:17:17 +00:00
|
|
|
|
2014-08-06 17:07:42 +00:00
|
|
|
void EndpointDialog::on_buttonBox_helpRequested()
|
|
|
|
{
|
|
|
|
wsApp->helpTopicAction(HELP_STATS_ENDPOINTS_DIALOG);
|
|
|
|
}
|
|
|
|
|
|
|
|
void init_endpoint_table(struct register_ct* ct, const char *filter)
|
|
|
|
{
|
|
|
|
wsApp->emitStatCommandSignal("Endpoints", filter, GINT_TO_POINTER(get_conversation_proto_id(ct)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// EndpointTreeWidgetItem
|
|
|
|
// TrafficTableTreeWidgetItem / QTreeWidgetItem subclass that allows sorting
|
|
|
|
|
2016-06-22 23:26:56 +00:00
|
|
|
#ifdef HAVE_GEOIP
|
2016-06-22 17:56:30 +00:00
|
|
|
static const char *geoip_none_ = UTF8_EM_DASH;
|
2016-06-22 23:26:56 +00:00
|
|
|
#endif
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
class EndpointTreeWidgetItem : public TrafficTableTreeWidgetItem
|
|
|
|
{
|
|
|
|
public:
|
2016-06-23 20:10:52 +00:00
|
|
|
EndpointTreeWidgetItem(GArray *conv_array, guint conv_idx, bool *resolve_names_ptr) :
|
|
|
|
TrafficTableTreeWidgetItem(NULL),
|
2016-06-22 17:56:30 +00:00
|
|
|
conv_array_(conv_array),
|
|
|
|
conv_idx_(conv_idx),
|
2016-06-23 20:10:52 +00:00
|
|
|
resolve_names_ptr_(resolve_names_ptr)
|
2016-06-22 17:56:30 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
hostlist_talker_t *hostlistTalker() {
|
|
|
|
return &g_array_index(conv_array_, hostlist_talker_t, conv_idx_);
|
|
|
|
}
|
2014-08-06 17:07:42 +00:00
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
virtual QVariant data(int column, int role) const {
|
|
|
|
if (role == Qt::DisplayRole) {
|
|
|
|
// Column text cooked representation.
|
|
|
|
hostlist_talker_t *endp_item = &g_array_index(conv_array_, hostlist_talker_t, conv_idx_);
|
|
|
|
|
|
|
|
bool resolve_names = false;
|
|
|
|
if (resolve_names_ptr_ && *resolve_names_ptr_) resolve_names = true;
|
|
|
|
switch (column) {
|
|
|
|
case ENDP_COLUMN_PACKETS:
|
|
|
|
return QString("%L1").arg(endp_item->tx_frames + endp_item->rx_frames);
|
|
|
|
case ENDP_COLUMN_BYTES:
|
|
|
|
return gchar_free_to_qstring(format_size(endp_item->tx_bytes + endp_item->rx_bytes, format_size_unit_none|format_size_prefix_si));
|
|
|
|
case ENDP_COLUMN_PKT_AB:
|
|
|
|
return QString("%L1").arg(endp_item->tx_frames);
|
|
|
|
case ENDP_COLUMN_BYTES_AB:
|
|
|
|
return gchar_free_to_qstring(format_size(endp_item->tx_bytes, format_size_unit_none|format_size_prefix_si));
|
|
|
|
case ENDP_COLUMN_PKT_BA:
|
|
|
|
return QString("%L1").arg(endp_item->rx_frames);
|
|
|
|
case ENDP_COLUMN_BYTES_BA:
|
|
|
|
return gchar_free_to_qstring(format_size(endp_item->rx_bytes, format_size_unit_none|format_size_prefix_si));
|
2014-08-06 17:07:42 +00:00
|
|
|
#ifdef HAVE_GEOIP
|
2016-06-23 20:10:52 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
QString geoip_str = colData(column, resolve_names, true).toString();
|
|
|
|
if (geoip_str.isEmpty()) geoip_str = geoip_none_;
|
|
|
|
return geoip_str;
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
2016-06-23 20:10:52 +00:00
|
|
|
#else
|
|
|
|
default:
|
|
|
|
return colData(column, resolve_names, true);
|
2014-08-06 17:07:42 +00:00
|
|
|
#endif
|
2016-06-23 20:10:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return QTreeWidgetItem::data(column, role);
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
// Column text raw representation.
|
2014-08-06 17:07:42 +00:00
|
|
|
// Return a string, qulonglong, double, or invalid QVariant representing the raw column data.
|
2016-06-27 01:38:19 +00:00
|
|
|
#ifdef HAVE_GEOIP
|
2016-06-23 20:10:52 +00:00
|
|
|
QVariant colData(int col, bool resolve_names, bool strings_only) const {
|
2016-06-27 01:38:19 +00:00
|
|
|
#else
|
|
|
|
QVariant colData(int col, bool resolve_names, bool strings_only _U_) const {
|
|
|
|
#endif
|
2016-06-22 17:56:30 +00:00
|
|
|
hostlist_talker_t *endp_item = &g_array_index(conv_array_, hostlist_talker_t, conv_idx_);
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
switch (col) {
|
|
|
|
case ENDP_COLUMN_ADDR:
|
2016-06-27 01:38:19 +00:00
|
|
|
{
|
2016-01-20 03:11:16 +00:00
|
|
|
char* addr_str = get_conversation_address(NULL, &endp_item->myaddress, resolve_names);
|
2015-01-05 02:40:05 +00:00
|
|
|
QString q_addr_str(addr_str);
|
|
|
|
wmem_free(NULL, addr_str);
|
|
|
|
return q_addr_str;
|
2016-06-27 01:38:19 +00:00
|
|
|
}
|
2014-08-06 17:07:42 +00:00
|
|
|
case ENDP_COLUMN_PORT:
|
|
|
|
if (resolve_names) {
|
2016-01-20 03:11:16 +00:00
|
|
|
char* port_str = get_conversation_port(NULL, endp_item->port, endp_item->ptype, resolve_names);
|
2015-01-07 21:24:17 +00:00
|
|
|
QString q_port_str(port_str);
|
|
|
|
wmem_free(NULL, port_str);
|
|
|
|
return q_port_str;
|
2014-08-06 17:07:42 +00:00
|
|
|
} else {
|
|
|
|
return quint32(endp_item->port);
|
|
|
|
}
|
|
|
|
case ENDP_COLUMN_PACKETS:
|
|
|
|
return quint64(endp_item->tx_frames + endp_item->rx_frames);
|
|
|
|
case ENDP_COLUMN_BYTES:
|
|
|
|
return quint64(endp_item->tx_bytes + endp_item->rx_bytes);
|
|
|
|
case ENDP_COLUMN_PKT_AB:
|
|
|
|
return quint64(endp_item->tx_frames);
|
|
|
|
case ENDP_COLUMN_BYTES_AB:
|
|
|
|
return quint64(endp_item->tx_bytes);
|
|
|
|
case ENDP_COLUMN_PKT_BA:
|
|
|
|
return quint64(endp_item->rx_frames);
|
|
|
|
case ENDP_COLUMN_BYTES_BA:
|
|
|
|
return quint64(endp_item->rx_bytes);
|
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
default:
|
|
|
|
{
|
2016-06-23 20:10:52 +00:00
|
|
|
QString geoip_str;
|
|
|
|
/* Filled in from the GeoIP config, if any */
|
|
|
|
EndpointTreeWidget *ep_tree = qobject_cast<EndpointTreeWidget *>(treeWidget());
|
|
|
|
if (!ep_tree) return geoip_str;
|
|
|
|
foreach (unsigned db, ep_tree->columnToDb(col)) {
|
|
|
|
if (endp_item->myaddress.type == AT_IPv4) {
|
|
|
|
geoip_str = geoip_db_lookup_ipv4(db, pntoh32(endp_item->myaddress.data), NULL);
|
|
|
|
} else if (endp_item->myaddress.type == AT_IPv6) {
|
|
|
|
const struct e_in6_addr *addr = (const struct e_in6_addr *) endp_item->myaddress.data;
|
|
|
|
geoip_str = geoip_db_lookup_ipv6(db, *addr, NULL);
|
|
|
|
}
|
|
|
|
if (!geoip_str.isEmpty()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strings_only) return geoip_str;
|
|
|
|
|
2014-08-06 17:07:42 +00:00
|
|
|
bool ok;
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
double dval = geoip_str.toDouble(&ok);
|
2014-08-06 17:07:42 +00:00
|
|
|
if (ok) { // Assume lat / lon
|
|
|
|
return dval;
|
|
|
|
}
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
qulonglong ullval = geoip_str.toULongLong(&ok);
|
2014-09-05 18:17:17 +00:00
|
|
|
if (ok) { // Assume uint
|
2014-08-06 17:07:42 +00:00
|
|
|
return ullval;
|
|
|
|
}
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
qlonglong llval = geoip_str.toLongLong(&ok);
|
2014-09-05 18:17:17 +00:00
|
|
|
if (ok) { // Assume int
|
2014-08-06 17:07:42 +00:00
|
|
|
return llval;
|
|
|
|
}
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
return geoip_str;
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2016-06-27 01:38:19 +00:00
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
virtual QVariant colData(int col, bool resolve_names) const { return colData(col, resolve_names, false); }
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
bool operator< (const QTreeWidgetItem &other) const
|
|
|
|
{
|
2016-06-22 17:56:30 +00:00
|
|
|
const EndpointTreeWidgetItem *other_row = static_cast<const EndpointTreeWidgetItem *>(&other);
|
|
|
|
hostlist_talker_t *endp_item = &g_array_index(conv_array_, hostlist_talker_t, conv_idx_);
|
|
|
|
hostlist_talker_t *other_item = &g_array_index(other_row->conv_array_, hostlist_talker_t, other_row->conv_idx_);
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
int sort_col = treeWidget()->sortColumn();
|
|
|
|
|
|
|
|
switch(sort_col) {
|
|
|
|
case ENDP_COLUMN_ADDR:
|
|
|
|
return cmp_address(&endp_item->myaddress, &other_item->myaddress) < 0 ? true : false;
|
|
|
|
case ENDP_COLUMN_PORT:
|
|
|
|
return endp_item->port < other_item->port;
|
|
|
|
case ENDP_COLUMN_PACKETS:
|
|
|
|
return (endp_item->tx_frames + endp_item->rx_frames) < (other_item->tx_frames + other_item->rx_frames);
|
|
|
|
case ENDP_COLUMN_BYTES:
|
|
|
|
return (endp_item->tx_bytes + endp_item->rx_bytes) < (other_item->tx_bytes + other_item->rx_bytes);
|
|
|
|
case ENDP_COLUMN_PKT_AB:
|
|
|
|
return endp_item->tx_frames < other_item->tx_frames;
|
|
|
|
case ENDP_COLUMN_BYTES_AB:
|
|
|
|
return endp_item->tx_bytes < other_item->tx_bytes;
|
|
|
|
case ENDP_COLUMN_PKT_BA:
|
|
|
|
return endp_item->rx_frames < other_item->rx_frames;
|
|
|
|
case ENDP_COLUMN_BYTES_BA:
|
|
|
|
return endp_item->rx_bytes < other_item->rx_bytes;
|
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
double ei_val, oi_val;
|
|
|
|
bool ei_ok, oi_ok;
|
|
|
|
ei_val = text(sort_col).toDouble(&ei_ok);
|
|
|
|
oi_val = other.text(sort_col).toDouble(&oi_ok);
|
|
|
|
|
|
|
|
if (ei_ok && oi_ok) { // Assume lat / lon
|
|
|
|
return ei_val < oi_val;
|
|
|
|
} else {
|
|
|
|
// XXX Fall back to string comparison. We might want to try sorting naturally
|
|
|
|
// using QCollator instead.
|
|
|
|
return text(sort_col) < other.text(sort_col);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2016-06-22 17:56:30 +00:00
|
|
|
private:
|
|
|
|
GArray *conv_array_;
|
|
|
|
guint conv_idx_;
|
2016-06-23 20:10:52 +00:00
|
|
|
bool *resolve_names_ptr_;
|
2014-08-06 17:07:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// EndpointTreeWidget
|
|
|
|
// TrafficTableTreeWidget / QTreeWidget subclass that allows tapping
|
|
|
|
//
|
|
|
|
|
|
|
|
EndpointTreeWidget::EndpointTreeWidget(QWidget *parent, register_ct_t *table) :
|
|
|
|
TrafficTableTreeWidget(parent, table)
|
2014-09-05 18:17:17 +00:00
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
, has_geoip_data_(false)
|
|
|
|
#endif
|
2014-08-06 17:07:42 +00:00
|
|
|
{
|
2014-09-05 14:42:02 +00:00
|
|
|
setColumnCount(ENDP_NUM_COLUMNS);
|
2016-06-23 20:10:52 +00:00
|
|
|
setUniformRowHeights(true);
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < ENDP_NUM_COLUMNS; i++) {
|
|
|
|
headerItem()->setText(i, endp_column_titles[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get_conversation_hide_ports(table_)) {
|
|
|
|
hideColumn(ENDP_COLUMN_PORT);
|
|
|
|
} else if (!strcmp(proto_get_protocol_filter_name(get_conversation_proto_id(table_)), "ncp")) {
|
|
|
|
headerItem()->setText(ENDP_COLUMN_PORT, endp_conn_title);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_GEOIP
|
2014-09-12 01:03:31 +00:00
|
|
|
QMap<QString, int> db_name_to_col;
|
|
|
|
for (unsigned db = 0; db < geoip_db_num_dbs(); db++) {
|
|
|
|
QString db_name = geoip_db_name(db);
|
|
|
|
int col = db_name_to_col.value(db_name, -1);
|
|
|
|
|
|
|
|
if (col < 0) {
|
|
|
|
col = columnCount();
|
|
|
|
setColumnCount(col + 1);
|
|
|
|
headerItem()->setText(col, db_name);
|
|
|
|
hideColumn(col);
|
|
|
|
db_name_to_col[db_name] = col;
|
|
|
|
}
|
|
|
|
col_to_db_[col] << db;
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int one_en = fontMetrics().height() / 2;
|
|
|
|
for (int i = 0; i < columnCount(); i++) {
|
|
|
|
switch (i) {
|
|
|
|
case ENDP_COLUMN_ADDR:
|
2014-09-05 03:42:42 +00:00
|
|
|
setColumnWidth(i, one_en * (int) strlen("000.000.000.000"));
|
2014-08-06 17:07:42 +00:00
|
|
|
break;
|
|
|
|
case ENDP_COLUMN_PORT:
|
2014-09-05 03:42:42 +00:00
|
|
|
setColumnWidth(i, one_en * (int) strlen("000000"));
|
2014-08-06 17:07:42 +00:00
|
|
|
break;
|
|
|
|
case ENDP_COLUMN_PACKETS:
|
|
|
|
case ENDP_COLUMN_PKT_AB:
|
|
|
|
case ENDP_COLUMN_PKT_BA:
|
2014-09-05 03:42:42 +00:00
|
|
|
setColumnWidth(i, one_en * (int) strlen("00,000"));
|
2014-08-06 17:07:42 +00:00
|
|
|
break;
|
|
|
|
case ENDP_COLUMN_BYTES:
|
|
|
|
case ENDP_COLUMN_BYTES_AB:
|
|
|
|
case ENDP_COLUMN_BYTES_BA:
|
2014-09-05 03:42:42 +00:00
|
|
|
setColumnWidth(i, one_en * (int) strlen("000,000"));
|
2014-08-06 17:07:42 +00:00
|
|
|
break;
|
|
|
|
default:
|
2014-09-05 03:42:42 +00:00
|
|
|
setColumnWidth(i, one_en * (int) strlen("-00.000000")); // GeoIP
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QMenu *submenu;
|
|
|
|
|
|
|
|
FilterAction::Action cur_action = FilterAction::ActionApply;
|
|
|
|
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
|
|
|
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
|
|
|
FilterAction *fa = new FilterAction(submenu, cur_action, at);
|
|
|
|
submenu->addAction(fa);
|
|
|
|
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
|
|
|
}
|
|
|
|
|
|
|
|
cur_action = FilterAction::ActionPrepare;
|
|
|
|
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
|
|
|
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
|
|
|
FilterAction *fa = new FilterAction(submenu, cur_action, at);
|
|
|
|
submenu->addAction(fa);
|
|
|
|
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
|
|
|
}
|
|
|
|
|
|
|
|
cur_action = FilterAction::ActionFind;
|
|
|
|
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
|
|
|
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
|
|
|
FilterAction *fa = new FilterAction(submenu, cur_action, at);
|
|
|
|
submenu->addAction(fa);
|
|
|
|
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
|
|
|
}
|
|
|
|
|
|
|
|
cur_action = FilterAction::ActionColorize;
|
|
|
|
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
|
|
|
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
|
|
|
FilterAction *fa = new FilterAction(submenu, cur_action, at);
|
|
|
|
submenu->addAction(fa);
|
|
|
|
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
|
|
|
}
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
updateItems();
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
EndpointTreeWidget::~EndpointTreeWidget()
|
|
|
|
{
|
|
|
|
reset_hostlist_table_data(&hash_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EndpointTreeWidget::tapReset(void *conv_hash_ptr)
|
|
|
|
{
|
|
|
|
conv_hash_t *hash = (conv_hash_t*)conv_hash_ptr;
|
2016-06-22 17:56:30 +00:00
|
|
|
EndpointTreeWidget *endp_tree = qobject_cast<EndpointTreeWidget *>((EndpointTreeWidget *)hash->user_data);
|
2014-08-06 17:07:42 +00:00
|
|
|
if (!endp_tree) return;
|
|
|
|
|
|
|
|
endp_tree->clear();
|
|
|
|
reset_hostlist_table_data(&endp_tree->hash_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EndpointTreeWidget::tapDraw(void *conv_hash_ptr)
|
|
|
|
{
|
|
|
|
conv_hash_t *hash = (conv_hash_t*)conv_hash_ptr;
|
2016-06-22 17:56:30 +00:00
|
|
|
EndpointTreeWidget *endp_tree = qobject_cast<EndpointTreeWidget *>((EndpointTreeWidget *)hash->user_data);
|
2014-08-06 17:07:42 +00:00
|
|
|
if (!endp_tree) return;
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
endp_tree->updateItems();
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
void EndpointTreeWidget::updateItems()
|
2014-08-06 17:07:42 +00:00
|
|
|
{
|
2016-06-23 20:10:52 +00:00
|
|
|
bool resize = topLevelItemCount() < resizeThreshold();
|
2014-08-06 17:07:42 +00:00
|
|
|
title_ = proto_get_protocol_short_name(find_protocol_by_id(get_conversation_proto_id(table_)));
|
|
|
|
|
|
|
|
if (hash_.conv_array && hash_.conv_array->len > 0) {
|
|
|
|
title_.append(QString(" %1 %2").arg(UTF8_MIDDLE_DOT).arg(hash_.conv_array->len));
|
|
|
|
}
|
|
|
|
emit titleChanged(this, title_);
|
|
|
|
|
|
|
|
if (!hash_.conv_array) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_GEOIP
|
|
|
|
if (topLevelItemCount() < 1 && hash_.conv_array->len > 0) {
|
|
|
|
hostlist_talker_t *endp_item = &g_array_index(hash_.conv_array, hostlist_talker_t, 0);
|
|
|
|
if (endp_item->myaddress.type == AT_IPv4 || endp_item->myaddress.type == AT_IPv6) {
|
|
|
|
for (unsigned i = 0; i < geoip_db_num_dbs(); i++) {
|
|
|
|
showColumn(ENDP_NUM_COLUMNS + i);
|
|
|
|
}
|
2014-09-05 18:17:17 +00:00
|
|
|
has_geoip_data_ = true;
|
|
|
|
emit geoIPStatusChanged();
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
setSortingEnabled(false);
|
2016-06-23 20:10:52 +00:00
|
|
|
|
|
|
|
QList<QTreeWidgetItem *>new_items;
|
2014-08-06 17:07:42 +00:00
|
|
|
for (int i = topLevelItemCount(); i < (int) hash_.conv_array->len; i++) {
|
2016-06-23 20:10:52 +00:00
|
|
|
EndpointTreeWidgetItem *etwi = new EndpointTreeWidgetItem(hash_.conv_array, i, &resolve_names_);
|
|
|
|
new_items << etwi;
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
for (int col = 0; col < columnCount(); col++) {
|
|
|
|
if (col != ENDP_COLUMN_ADDR && col < ENDP_NUM_COLUMNS) {
|
|
|
|
etwi->setTextAlignment(col, Qt::AlignRight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-23 20:10:52 +00:00
|
|
|
addTopLevelItems(new_items);
|
2014-08-06 17:07:42 +00:00
|
|
|
setSortingEnabled(true);
|
|
|
|
|
2016-06-23 20:10:52 +00:00
|
|
|
if (resize) {
|
|
|
|
for (int col = 0; col < columnCount(); col++) {
|
|
|
|
resizeColumnToContents(col);
|
|
|
|
}
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EndpointTreeWidget::filterActionTriggered()
|
|
|
|
{
|
|
|
|
EndpointTreeWidgetItem *etwi = static_cast<EndpointTreeWidgetItem *>(currentItem());
|
|
|
|
FilterAction *fa = qobject_cast<FilterAction *>(QObject::sender());
|
|
|
|
|
|
|
|
if (!fa || !etwi) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-22 17:56:30 +00:00
|
|
|
hostlist_talker_t *endp_item = etwi->hostlistTalker();
|
2014-08-06 17:07:42 +00:00
|
|
|
if (!endp_item) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString filter = get_hostlist_filter(endp_item);
|
|
|
|
emit filterAction(filter, fa->action(), fa->actionType());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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:
|
|
|
|
*/
|