2014-08-06 17:07:42 +00:00
|
|
|
/* traffic_table_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 "traffic_table_dialog.h"
|
|
|
|
#include "ui_traffic_table_dialog.h"
|
|
|
|
|
|
|
|
#include <epan/addr_resolv.h>
|
|
|
|
#include <epan/prefs.h>
|
2014-11-14 18:51:40 +00:00
|
|
|
#include <epan/stat_tap_ui.h>
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
//#include <epan/dissectors/packet-tcp.h>
|
|
|
|
|
|
|
|
#include "ui/recent.h"
|
|
|
|
//#include "ui/tap-tcp-stream.h"
|
|
|
|
|
|
|
|
#include "wireshark_application.h"
|
|
|
|
|
|
|
|
#include <QCheckBox>
|
|
|
|
#include <QClipboard>
|
|
|
|
#include <QContextMenuEvent>
|
|
|
|
#include <QList>
|
|
|
|
#include <QMap>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPushButton>
|
|
|
|
#include <QTreeWidget>
|
|
|
|
#include <QTextStream>
|
|
|
|
#include <QToolButton>
|
|
|
|
|
|
|
|
// Bugs:
|
|
|
|
// - Name resolution doesn't do anything if its preference is disabled.
|
|
|
|
// - Columns don't resize correctly.
|
|
|
|
// - Closing the capture file clears conversation data.
|
|
|
|
|
2014-12-22 23:51:36 +00:00
|
|
|
TrafficTableDialog::TrafficTableDialog(QWidget &parent, CaptureFile &cf, const char *filter, const QString &table_name) :
|
|
|
|
WiresharkDialog(parent, cf),
|
2014-08-06 17:07:42 +00:00
|
|
|
ui(new Ui::TrafficTableDialog),
|
|
|
|
cap_file_(cf),
|
2014-12-22 23:51:36 +00:00
|
|
|
file_closed_(false),
|
2014-08-06 17:07:42 +00:00
|
|
|
filter_(filter)
|
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
2014-12-21 21:23:02 +00:00
|
|
|
// setAttribute(Qt::WA_DeleteOnClose, true);
|
2014-08-06 17:07:42 +00:00
|
|
|
|
2014-12-22 23:51:36 +00:00
|
|
|
QString window_name = QString("%1s").arg(table_name);
|
|
|
|
setWindowSubtitle(window_name);
|
|
|
|
ui->enabledTypesPushButton->setText(tr("%1 Types").arg(window_name));
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
// XXX Use recent settings instead
|
2014-12-22 23:51:36 +00:00
|
|
|
resize(parent.width(), parent.height() * 3 / 4);
|
2014-08-06 17:07:42 +00:00
|
|
|
|
|
|
|
QMenu *copy_menu = new QMenu();
|
|
|
|
QAction *ca;
|
|
|
|
copy_bt_ = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
|
|
|
|
ca = copy_menu->addAction(tr("as CSV"));
|
|
|
|
ca->setToolTip(tr("Copy all values of this page to the clipboard in CSV (Comma Separated Values) format."));
|
|
|
|
connect(ca, SIGNAL(triggered()), this, SLOT(copyAsCsv()));
|
|
|
|
ca = copy_menu->addAction(tr("as YAML"));
|
|
|
|
ca->setToolTip(tr("Copy all values of this page to the clipboard in the YAML data serialization format."));
|
|
|
|
connect(ca, SIGNAL(triggered()), this, SLOT(copyAsYaml()));
|
|
|
|
copy_bt_->setMenu(copy_menu);
|
|
|
|
|
|
|
|
ui->enabledTypesPushButton->setMenu(&traffic_type_menu_);
|
|
|
|
ui->nameResolutionCheckBox->setChecked(gbl_resolv_flags.network_name);
|
|
|
|
ui->trafficTableTabWidget->setFocus();
|
|
|
|
|
|
|
|
connect(ui->trafficTableTabWidget, SIGNAL(currentChanged(int)),
|
|
|
|
this, SLOT(itemSelectionChanged()));
|
2014-12-21 21:23:02 +00:00
|
|
|
connect(&cap_file_, SIGNAL(captureFileClosing()), this, SLOT(captureFileClosing()));
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TrafficTableDialog::~TrafficTableDialog()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QList<int> TrafficTableDialog::defaultProtos() const
|
|
|
|
{
|
|
|
|
// Reasonable defaults?
|
|
|
|
return QList<int>() << proto_get_id_by_filter_name( "tcp" ) << proto_get_id_by_filter_name( "eth" )
|
|
|
|
<< proto_get_id_by_filter_name( "ip" ) << proto_get_id_by_filter_name( "ipv6" )
|
|
|
|
<< proto_get_id_by_filter_name( "udp" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableDialog::fillTypeMenu(QList<int> &enabled_protos)
|
|
|
|
{
|
|
|
|
for (guint i = 0; i < conversation_table_get_num(); i++) {
|
|
|
|
int proto_id = get_conversation_proto_id(get_conversation_table_by_num(i));
|
|
|
|
if (proto_id < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
QString title = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
|
|
|
|
|
|
|
|
QAction *endp_action = new QAction(title, this);
|
|
|
|
endp_action->setData(qVariantFromValue(proto_id));
|
|
|
|
endp_action->setCheckable(true);
|
|
|
|
endp_action->setChecked(enabled_protos.contains(proto_id));
|
2014-09-05 18:17:17 +00:00
|
|
|
connect(endp_action, SIGNAL(triggered()), this, SLOT(toggleTable()));
|
2014-08-06 17:07:42 +00:00
|
|
|
traffic_type_menu_.addAction(endp_action);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QDialogButtonBox *TrafficTableDialog::buttonBox() const
|
|
|
|
{
|
|
|
|
return ui->buttonBox;
|
|
|
|
}
|
|
|
|
|
|
|
|
QTabWidget *TrafficTableDialog::trafficTableTabWidget() const
|
|
|
|
{
|
|
|
|
return ui->trafficTableTabWidget;
|
|
|
|
}
|
|
|
|
|
|
|
|
QCheckBox *TrafficTableDialog::displayFilterCheckBox() const
|
|
|
|
{
|
|
|
|
return ui->displayFilterCheckBox;
|
|
|
|
}
|
|
|
|
|
|
|
|
QCheckBox *TrafficTableDialog::nameResolutionCheckBox() const
|
|
|
|
{
|
|
|
|
return ui->nameResolutionCheckBox;
|
|
|
|
}
|
|
|
|
|
|
|
|
QPushButton *TrafficTableDialog::enabledTypesPushButton() const
|
|
|
|
{
|
|
|
|
return ui->enabledTypesPushButton;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableDialog::on_nameResolutionCheckBox_toggled(bool checked)
|
|
|
|
{
|
|
|
|
Q_UNUSED(checked);
|
|
|
|
updateWidgets();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableDialog::on_displayFilterCheckBox_toggled(bool checked)
|
|
|
|
{
|
2014-12-21 21:23:02 +00:00
|
|
|
if (!cap_file_.isValid()) {
|
2014-08-06 17:07:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-29 18:29:26 +00:00
|
|
|
QByteArray filter_utf8;
|
2014-08-06 17:07:42 +00:00
|
|
|
const char *filter = NULL;
|
|
|
|
if (checked) {
|
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
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < ui->trafficTableTabWidget->count(); i++) {
|
2014-12-31 16:36:13 +00:00
|
|
|
TrafficTableTreeWidget *cur_tree = qobject_cast<TrafficTableTreeWidget *>(ui->trafficTableTabWidget->widget(i));
|
|
|
|
set_tap_dfilter(cur_tree->trafficTreeHash(), filter);
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
|
2014-12-21 21:23:02 +00:00
|
|
|
cap_file_.retapPackets();
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableDialog::setTabText(QWidget *tree, const QString &text)
|
|
|
|
{
|
|
|
|
// Could use QObject::sender as well
|
|
|
|
int index = ui->trafficTableTabWidget->indexOf(tree);
|
|
|
|
if (index >= 0) {
|
|
|
|
ui->trafficTableTabWidget->setTabText(index, text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-05 18:17:17 +00:00
|
|
|
void TrafficTableDialog::toggleTable()
|
2014-08-06 17:07:42 +00:00
|
|
|
{
|
|
|
|
QAction *ca = qobject_cast<QAction *>(QObject::sender());
|
|
|
|
if (!ca) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int proto_id = ca->data().value<int>();
|
|
|
|
register_ct_t* table = get_conversation_by_proto_id(proto_id);
|
|
|
|
|
|
|
|
bool new_table = addTrafficTable(table);
|
|
|
|
updateWidgets();
|
|
|
|
|
|
|
|
if (ca->isChecked()) {
|
|
|
|
ui->trafficTableTabWidget->setCurrentWidget(proto_id_to_tree_[proto_id]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_table) {
|
2014-12-21 21:23:02 +00:00
|
|
|
cap_file_.retapPackets();
|
2014-08-06 17:07:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableDialog::updateWidgets()
|
|
|
|
{
|
|
|
|
QWidget *cur_w = ui->trafficTableTabWidget->currentWidget();
|
|
|
|
ui->trafficTableTabWidget->setUpdatesEnabled(false);
|
|
|
|
ui->trafficTableTabWidget->clear();
|
|
|
|
foreach (QAction *ca, traffic_type_menu_.actions()) {
|
|
|
|
int proto_id = ca->data().value<int>();
|
|
|
|
if (proto_id_to_tree_.contains(proto_id) && ca->isChecked()) {
|
|
|
|
ui->trafficTableTabWidget->addTab(proto_id_to_tree_[proto_id],
|
|
|
|
proto_id_to_tree_[proto_id]->trafficTreeTitle());
|
|
|
|
proto_id_to_tree_[proto_id]->setNameResolutionEnabled(ui->nameResolutionCheckBox->isChecked());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ui->trafficTableTabWidget->setCurrentWidget(cur_w);
|
|
|
|
ui->trafficTableTabWidget->setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QVariant> TrafficTableDialog::curTreeRowData(int row) const
|
|
|
|
{
|
|
|
|
TrafficTableTreeWidget *cur_tree = qobject_cast<TrafficTableTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
|
|
|
|
if (!cur_tree) {
|
|
|
|
return QList<QVariant>();
|
|
|
|
}
|
|
|
|
|
|
|
|
return cur_tree->rowData(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableDialog::copyAsCsv()
|
|
|
|
{
|
|
|
|
QTreeWidget *cur_tree = qobject_cast<QTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
|
|
|
|
if (!cur_tree) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString csv;
|
|
|
|
QTextStream stream(&csv, QIODevice::Text);
|
|
|
|
for (int row = -1; row < cur_tree->topLevelItemCount(); row ++) {
|
|
|
|
QStringList rdsl;
|
|
|
|
foreach (QVariant v, curTreeRowData(row)) {
|
|
|
|
if (!v.isValid()) {
|
|
|
|
rdsl << "\"\"";
|
|
|
|
} else if ((int) v.type() == (int) QMetaType::QString) {
|
|
|
|
rdsl << QString("\"%1\"").arg(v.toString());
|
|
|
|
} else {
|
|
|
|
rdsl << v.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stream << rdsl.join(",") << endl;
|
|
|
|
}
|
|
|
|
wsApp->clipboard()->setText(stream.readAll());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableDialog::copyAsYaml()
|
|
|
|
{
|
|
|
|
QTreeWidget *cur_tree = qobject_cast<QTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
|
|
|
|
if (!cur_tree) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString yaml;
|
|
|
|
QTextStream stream(&yaml, QIODevice::Text);
|
|
|
|
stream << "---" << endl;
|
|
|
|
for (int row = -1; row < cur_tree->topLevelItemCount(); row ++) {
|
|
|
|
stream << "-" << endl;
|
|
|
|
foreach (QVariant v, curTreeRowData(row)) {
|
|
|
|
stream << " - " << v.toString() << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
wsApp->clipboard()->setText(stream.readAll());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TrafficTableTreeWidget::TrafficTableTreeWidget(QWidget *parent, register_ct_t *table) :
|
|
|
|
QTreeWidget(parent),
|
|
|
|
table_(table),
|
|
|
|
hash_(),
|
|
|
|
resolve_names_(false)
|
|
|
|
{
|
|
|
|
setRootIsDecorated(false);
|
|
|
|
sortByColumn(0, Qt::AscendingOrder);
|
|
|
|
|
|
|
|
connect(wsApp, SIGNAL(addressResolutionChanged()), this, SLOT(updateItems()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TrafficTableTreeWidget::~TrafficTableTreeWidget()
|
|
|
|
{
|
|
|
|
remove_tap_listener(&hash_);
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QVariant> TrafficTableTreeWidget::rowData(int row) const
|
|
|
|
{
|
|
|
|
QList<QVariant> row_data;
|
|
|
|
|
|
|
|
if (row >= topLevelItemCount()) {
|
|
|
|
return row_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int col = 0; col < columnCount(); col++) {
|
|
|
|
if (isColumnHidden(col)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (row < 0) {
|
|
|
|
row_data << headerItem()->text(col);
|
|
|
|
} else {
|
|
|
|
TrafficTableTreeWidgetItem *ti = static_cast<TrafficTableTreeWidgetItem *>(topLevelItem(row));
|
|
|
|
if (ti) {
|
|
|
|
row_data << ti->colData(col, resolve_names_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return row_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableTreeWidget::setNameResolutionEnabled(bool enable)
|
|
|
|
{
|
|
|
|
if (resolve_names_ != enable) {
|
|
|
|
resolve_names_ = enable;
|
|
|
|
updateItems();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TrafficTableTreeWidget::contextMenuEvent(QContextMenuEvent *event)
|
|
|
|
{
|
|
|
|
bool enable = currentItem() != NULL ? true : false;
|
|
|
|
|
|
|
|
foreach (QMenu *submenu, ctx_menu_.findChildren<QMenu*>()) {
|
|
|
|
submenu->setEnabled(enable);
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx_menu_.exec(event->globalPos());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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:
|
|
|
|
*/
|