2013-09-09 19:30:30 +00:00
|
|
|
/* follow_stream_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 "follow_stream_dialog.h"
|
2015-06-25 16:17:03 +00:00
|
|
|
#include <ui_follow_stream_dialog.h>
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
#include "main_window.h"
|
|
|
|
#include "wireshark_application.h"
|
|
|
|
|
2013-09-11 17:39:49 +00:00
|
|
|
#include "epan/follow.h"
|
2013-11-13 22:18:01 +00:00
|
|
|
#include "epan/dissectors/packet-tcp.h"
|
2014-12-27 22:15:41 +00:00
|
|
|
#include "epan/dissectors/packet-udp.h"
|
2016-01-08 13:25:17 +00:00
|
|
|
#include "epan/dissectors/packet-ssl-utils.h"
|
2013-09-11 17:39:49 +00:00
|
|
|
#include "epan/prefs.h"
|
2013-12-21 18:19:07 +00:00
|
|
|
#include "epan/addr_resolv.h"
|
2013-09-11 17:39:49 +00:00
|
|
|
#include "epan/charsets.h"
|
|
|
|
#include "epan/epan_dissect.h"
|
|
|
|
#include "epan/tap.h"
|
|
|
|
|
|
|
|
#include "ui/alert_box.h"
|
|
|
|
#include "ui/simple_dialog.h"
|
2015-10-04 17:10:29 +00:00
|
|
|
#include <wsutil/utf8_entities.h>
|
2013-11-13 22:18:01 +00:00
|
|
|
|
2013-09-11 17:39:49 +00:00
|
|
|
#include "wsutil/file_util.h"
|
2013-11-13 22:18:01 +00:00
|
|
|
#include "wsutil/str_util.h"
|
2016-04-19 07:03:08 +00:00
|
|
|
#include "ws_version_info.h"
|
2013-11-13 22:18:01 +00:00
|
|
|
|
2013-09-11 17:39:49 +00:00
|
|
|
#include "ws_symbol_export.h"
|
|
|
|
|
2013-10-15 15:22:03 +00:00
|
|
|
#include "color_utils.h"
|
2013-09-11 17:39:49 +00:00
|
|
|
|
2015-08-24 19:33:49 +00:00
|
|
|
#include "progress_frame.h"
|
2014-11-12 22:24:16 +00:00
|
|
|
#include "qt_ui_utils.h"
|
2014-10-31 22:49:04 +00:00
|
|
|
|
2016-03-01 00:34:32 +00:00
|
|
|
#include <QElapsedTimer>
|
2013-10-14 21:17:38 +00:00
|
|
|
#include <QKeyEvent>
|
2013-09-11 17:39:49 +00:00
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPrintDialog>
|
|
|
|
#include <QPrinter>
|
2016-03-01 00:34:32 +00:00
|
|
|
#include <QScrollBar>
|
2013-10-14 21:17:38 +00:00
|
|
|
#include <QTextEdit>
|
2013-09-11 17:39:49 +00:00
|
|
|
#include <QTextStream>
|
|
|
|
|
2013-11-15 00:30:07 +00:00
|
|
|
// To do:
|
2016-03-01 00:34:32 +00:00
|
|
|
// - Show text while tapping.
|
2013-11-15 00:30:07 +00:00
|
|
|
// - Instead of calling QMessageBox, display the error message in the text
|
|
|
|
// box and disable the appropriate controls.
|
2014-12-29 22:12:43 +00:00
|
|
|
// - Add a progress bar and connect captureCaptureUpdateContinue to it
|
2013-11-15 00:30:07 +00:00
|
|
|
|
2016-03-01 00:34:32 +00:00
|
|
|
// Matches SplashOverlay.
|
|
|
|
static int info_update_freq_ = 100;
|
|
|
|
|
2014-12-29 22:12:43 +00:00
|
|
|
FollowStreamDialog::FollowStreamDialog(QWidget &parent, CaptureFile &cf, follow_type_t type) :
|
|
|
|
WiresharkDialog(parent, cf),
|
2013-11-13 22:18:01 +00:00
|
|
|
ui(new Ui::FollowStreamDialog),
|
|
|
|
follow_type_(type),
|
2016-01-08 13:25:17 +00:00
|
|
|
follower_(NULL),
|
|
|
|
show_type_(SHOW_ASCII),
|
2014-11-01 16:53:07 +00:00
|
|
|
truncated_(false),
|
2016-03-01 00:34:32 +00:00
|
|
|
client_packet_count_(0),
|
|
|
|
server_packet_count_(0),
|
|
|
|
turns_(0),
|
2016-02-14 18:34:11 +00:00
|
|
|
save_as_(false),
|
|
|
|
use_regex_find_(false)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
2016-02-28 18:23:20 +00:00
|
|
|
loadGeometry(parent.width() * 2 / 3, parent.height());
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case FOLLOW_TCP:
|
|
|
|
follower_ = get_follow_by_name("TCP");
|
|
|
|
break;
|
|
|
|
case FOLLOW_SSL:
|
|
|
|
follower_ = get_follow_by_name("SSL");
|
|
|
|
break;
|
|
|
|
case FOLLOW_UDP:
|
|
|
|
follower_ = get_follow_by_name("UDP");
|
|
|
|
break;
|
|
|
|
case FOLLOW_HTTP:
|
|
|
|
follower_ = get_follow_by_name("HTTP");
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
memset(&follow_info_, 0, sizeof(follow_info_));
|
2014-12-28 15:35:57 +00:00
|
|
|
follow_info_.show_stream = BOTH_HOSTS;
|
|
|
|
|
2013-10-14 21:17:38 +00:00
|
|
|
ui->teStreamContent->installEventFilter(this);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-02-14 18:34:11 +00:00
|
|
|
connect(ui->leFind, SIGNAL(useRegexFind(bool)), this, SLOT(useRegexFind(bool)));
|
|
|
|
|
2013-11-18 23:39:47 +00:00
|
|
|
QComboBox *cbcs = ui->cbCharset;
|
|
|
|
cbcs->blockSignals(true);
|
2014-08-29 05:48:18 +00:00
|
|
|
cbcs->addItem(tr("ASCII"), SHOW_ASCII);
|
|
|
|
cbcs->addItem(tr("C Arrays"), SHOW_CARRAY);
|
|
|
|
cbcs->addItem(tr("EBCDIC"), SHOW_EBCDIC);
|
|
|
|
cbcs->addItem(tr("Hex Dump"), SHOW_HEXDUMP);
|
2015-10-14 21:33:27 +00:00
|
|
|
cbcs->addItem(tr("UTF-8"), SHOW_UTF8);
|
2014-08-29 05:48:18 +00:00
|
|
|
cbcs->addItem(tr("YAML"), SHOW_YAML);
|
2015-10-14 21:33:27 +00:00
|
|
|
cbcs->addItem(tr("Raw"), SHOW_RAW);
|
2013-11-18 23:39:47 +00:00
|
|
|
cbcs->blockSignals(false);
|
|
|
|
|
2016-01-16 00:34:23 +00:00
|
|
|
b_filter_out_ = ui->buttonBox->addButton(tr("Filter Out This Stream"), QDialogButtonBox::ActionRole);
|
2013-11-13 22:18:01 +00:00
|
|
|
connect(b_filter_out_, SIGNAL(clicked()), this, SLOT(filterOut()));
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
b_print_ = ui->buttonBox->addButton(tr("Print"), QDialogButtonBox::ActionRole);
|
|
|
|
connect(b_print_, SIGNAL(clicked()), this, SLOT(printStream()));
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2015-07-31 17:34:43 +00:00
|
|
|
b_save_ = ui->buttonBox->addButton(tr("Save as" UTF8_HORIZONTAL_ELLIPSIS), QDialogButtonBox::ActionRole);
|
2013-11-13 22:18:01 +00:00
|
|
|
connect(b_save_, SIGNAL(clicked()), this, SLOT(saveAs()));
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2015-08-24 19:33:49 +00:00
|
|
|
ProgressFrame::addToButtonBox(ui->buttonBox, &parent);
|
|
|
|
|
2013-11-14 17:37:40 +00:00
|
|
|
connect(ui->buttonBox, SIGNAL(helpRequested()), this, SLOT(helpButton()));
|
|
|
|
connect(ui->teStreamContent, SIGNAL(mouseMovedToTextCursorPosition(int)),
|
|
|
|
this, SLOT(fillHintLabel(int)));
|
|
|
|
connect(ui->teStreamContent, SIGNAL(mouseClickedOnTextCursorPosition(int)),
|
|
|
|
this, SLOT(goToPacketForTextPos(int)));
|
2014-12-29 22:12:43 +00:00
|
|
|
connect(&cap_file_, SIGNAL(captureFileClosing()), this, SLOT(captureFileClosing()));
|
2013-11-14 17:37:40 +00:00
|
|
|
|
|
|
|
fillHintLabel(-1);
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
FollowStreamDialog::~FollowStreamDialog()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
resetStream(); // Frees payload
|
|
|
|
}
|
|
|
|
|
|
|
|
void FollowStreamDialog::printStream()
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
#ifndef QT_NO_PRINTER
|
|
|
|
QPrinter printer(QPrinter::HighResolution);
|
|
|
|
QPrintDialog dialog(&printer, this);
|
2016-01-23 12:18:30 +00:00
|
|
|
if (dialog.exec() == QDialog::Accepted)
|
2013-09-09 19:30:30 +00:00
|
|
|
ui->teStreamContent->print(&printer);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-11-14 17:37:40 +00:00
|
|
|
void FollowStreamDialog::fillHintLabel(int text_pos)
|
|
|
|
{
|
|
|
|
QString hint;
|
|
|
|
int pkt = -1;
|
|
|
|
|
|
|
|
if (text_pos >= 0) {
|
|
|
|
QMap<int, guint32>::iterator it = text_pos_to_packet_.upperBound(text_pos);
|
|
|
|
if (it != text_pos_to_packet_.end()) {
|
|
|
|
pkt = it.value();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt > 0) {
|
2014-08-29 05:48:18 +00:00
|
|
|
hint = QString(tr("Packet %1. ")).arg(pkt);
|
2013-11-14 17:37:40 +00:00
|
|
|
}
|
|
|
|
|
2014-10-31 23:12:47 +00:00
|
|
|
hint += tr("%Ln <span style=\"color: %1; background-color:%2\">client</span> pkt(s), ", "", client_packet_count_)
|
|
|
|
.arg(ColorUtils::fromColorT(prefs.st_client_fg).name())
|
|
|
|
.arg(ColorUtils::fromColorT(prefs.st_client_bg).name())
|
|
|
|
+ tr("%Ln <span style=\"color: %1; background-color:%2\">server</span> pkt(s), ", "", server_packet_count_)
|
|
|
|
.arg(ColorUtils::fromColorT(prefs.st_server_fg).name())
|
|
|
|
.arg(ColorUtils::fromColorT(prefs.st_server_bg).name())
|
2013-11-14 22:35:10 +00:00
|
|
|
+ tr("%Ln turn(s).", "", turns_);
|
2013-11-14 17:37:40 +00:00
|
|
|
|
|
|
|
if (pkt > 0) {
|
2014-08-29 05:48:18 +00:00
|
|
|
hint.append(QString(tr(" Click to select.")));
|
2013-11-14 17:37:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
hint.prepend("<small><i>");
|
|
|
|
hint.append("</i></small>");
|
|
|
|
ui->hintLabel->setText(hint);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FollowStreamDialog::goToPacketForTextPos(int text_pos)
|
|
|
|
{
|
|
|
|
int pkt = -1;
|
2014-12-29 22:12:43 +00:00
|
|
|
if (file_closed_) {
|
2014-10-31 22:49:04 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-11-14 17:37:40 +00:00
|
|
|
|
|
|
|
if (text_pos >= 0) {
|
|
|
|
QMap<int, guint32>::iterator it = text_pos_to_packet_.upperBound(text_pos);
|
|
|
|
if (it != text_pos_to_packet_.end()) {
|
|
|
|
pkt = it.value();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt > 0) {
|
|
|
|
emit goToPacket(pkt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-29 22:12:43 +00:00
|
|
|
void FollowStreamDialog::updateWidgets(bool follow_in_progress)
|
2014-10-31 22:49:04 +00:00
|
|
|
{
|
2014-12-29 22:12:43 +00:00
|
|
|
bool enable = !follow_in_progress;
|
|
|
|
if (file_closed_) {
|
|
|
|
ui->teStreamContent->setEnabled(true);
|
2014-10-31 22:49:04 +00:00
|
|
|
enable = false;
|
|
|
|
}
|
2014-12-29 22:12:43 +00:00
|
|
|
|
2014-10-31 22:49:04 +00:00
|
|
|
ui->cbDirections->setEnabled(enable);
|
|
|
|
ui->cbCharset->setEnabled(enable);
|
|
|
|
ui->streamNumberSpinBox->setEnabled(enable);
|
|
|
|
ui->leFind->setEnabled(enable);
|
|
|
|
ui->bFind->setEnabled(enable);
|
|
|
|
b_filter_out_->setEnabled(enable);
|
2016-03-01 00:34:32 +00:00
|
|
|
b_print_->setEnabled(enable);
|
|
|
|
b_save_->setEnabled(enable);
|
2015-09-25 09:05:45 +00:00
|
|
|
|
|
|
|
WiresharkDialog::updateWidgets();
|
2014-10-31 22:49:04 +00:00
|
|
|
}
|
|
|
|
|
2016-02-14 18:34:11 +00:00
|
|
|
void FollowStreamDialog::useRegexFind(bool use_regex)
|
|
|
|
{
|
|
|
|
use_regex_find_ = use_regex;
|
|
|
|
if (use_regex_find_)
|
|
|
|
ui->lFind->setText("Regex Find:");
|
|
|
|
else
|
|
|
|
ui->lFind->setText("Find:");
|
|
|
|
}
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
void FollowStreamDialog::findText(bool go_back)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
2013-10-14 21:17:38 +00:00
|
|
|
if (ui->leFind->text().isEmpty()) return;
|
|
|
|
|
2016-02-14 18:34:11 +00:00
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0))
|
|
|
|
bool found;
|
|
|
|
if (use_regex_find_) {
|
|
|
|
QRegExp regex(ui->leFind->text());
|
|
|
|
found = ui->teStreamContent->find(regex);
|
|
|
|
} else {
|
|
|
|
found = ui->teStreamContent->find(ui->leFind->text());
|
|
|
|
}
|
|
|
|
#else
|
2013-10-14 21:17:38 +00:00
|
|
|
bool found = ui->teStreamContent->find(ui->leFind->text());
|
2016-02-14 18:34:11 +00:00
|
|
|
#endif
|
2013-10-14 21:17:38 +00:00
|
|
|
|
|
|
|
if (found) {
|
|
|
|
ui->teStreamContent->setFocus();
|
|
|
|
} else if (go_back) {
|
2013-09-09 19:30:30 +00:00
|
|
|
ui->teStreamContent->moveCursor(QTextCursor::Start);
|
2013-11-13 22:18:01 +00:00
|
|
|
findText(false);
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
void FollowStreamDialog::saveAs()
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
2014-12-31 22:21:50 +00:00
|
|
|
QString file_name = QFileDialog::getSaveFileName(this, wsApp->windowTitleString(tr("Save Stream Content As" UTF8_HORIZONTAL_ELLIPSIS)));
|
2015-11-24 14:10:21 +00:00
|
|
|
if (!file_name.isEmpty()) {
|
|
|
|
QTextStream out(&file_);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-05-22 17:44:25 +00:00
|
|
|
if (!file_.open(QIODevice::WriteOnly)) {
|
|
|
|
open_failure_alert_box(file_name.toUtf8().constData(), errno, TRUE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
file_.setFileName(file_name);
|
|
|
|
|
2015-11-24 14:10:21 +00:00
|
|
|
save_as_ = true;
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2015-11-24 14:10:21 +00:00
|
|
|
readStream();
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
if ((show_type_ != SHOW_RAW) && (show_type_ != SHOW_UTF8))
|
2015-11-24 14:10:21 +00:00
|
|
|
{
|
|
|
|
out << ui->teStreamContent->toPlainText();
|
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2015-11-24 14:10:21 +00:00
|
|
|
save_as_ = false;
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2015-11-24 14:10:21 +00:00
|
|
|
file_.close();
|
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
void FollowStreamDialog::helpButton()
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
wsApp->helpTopicAction(HELP_FOLLOW_STREAM_DIALOG);
|
|
|
|
}
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
void FollowStreamDialog::filterOut()
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
2013-11-13 22:18:01 +00:00
|
|
|
emit updateFilter(filter_out_filter_, TRUE);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2014-12-29 22:12:43 +00:00
|
|
|
close();
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-01-02 13:58:08 +00:00
|
|
|
void FollowStreamDialog::on_cbDirections_currentIndexChanged(int idx)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
2016-01-02 13:58:08 +00:00
|
|
|
switch(idx)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
case 0 :
|
2013-11-13 22:18:01 +00:00
|
|
|
follow_info_.show_stream = BOTH_HOSTS;
|
2013-09-09 19:30:30 +00:00
|
|
|
break;
|
|
|
|
case 1 :
|
2013-11-13 22:18:01 +00:00
|
|
|
follow_info_.show_stream = FROM_SERVER;
|
2013-09-09 19:30:30 +00:00
|
|
|
break;
|
|
|
|
case 2 :
|
2013-11-13 22:18:01 +00:00
|
|
|
follow_info_.show_stream = FROM_CLIENT;
|
2013-09-09 19:30:30 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-01 16:53:07 +00:00
|
|
|
readStream();
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-01-02 13:58:08 +00:00
|
|
|
void FollowStreamDialog::on_cbCharset_currentIndexChanged(int idx)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
2016-01-02 13:58:08 +00:00
|
|
|
if (idx < 0) return;
|
2016-01-08 13:25:17 +00:00
|
|
|
show_type_ = static_cast<show_type_t>(ui->cbCharset->itemData(idx).toInt());
|
2014-11-01 16:53:07 +00:00
|
|
|
readStream();
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2013-10-14 21:17:38 +00:00
|
|
|
void FollowStreamDialog::on_bFind_clicked()
|
|
|
|
{
|
2013-11-13 22:18:01 +00:00
|
|
|
findText();
|
2013-10-14 21:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FollowStreamDialog::on_leFind_returnPressed()
|
|
|
|
{
|
2013-11-13 22:18:01 +00:00
|
|
|
findText();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FollowStreamDialog::on_streamNumberSpinBox_valueChanged(int stream_num)
|
|
|
|
{
|
2014-12-29 22:12:43 +00:00
|
|
|
if (file_closed_) return;
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
if (stream_num >= 0) {
|
2016-01-08 13:25:17 +00:00
|
|
|
follow(QString(), true, stream_num);
|
2013-11-13 22:18:01 +00:00
|
|
|
}
|
2013-10-14 21:17:38 +00:00
|
|
|
}
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
// Not sure why we have to do this manually.
|
2013-10-14 21:17:38 +00:00
|
|
|
void FollowStreamDialog::on_buttonBox_rejected()
|
|
|
|
{
|
2015-11-16 23:15:06 +00:00
|
|
|
WiresharkDialog::reject();
|
2013-11-13 22:18:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FollowStreamDialog::removeStreamControls()
|
|
|
|
{
|
|
|
|
ui->horizontalLayout->removeItem(ui->streamNumberSpacer);
|
|
|
|
ui->streamNumberLabel->setVisible(false);
|
|
|
|
ui->streamNumberSpinBox->setVisible(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FollowStreamDialog::resetStream()
|
|
|
|
{
|
|
|
|
GList *cur;
|
|
|
|
|
|
|
|
filter_out_filter_.clear();
|
2013-11-14 17:37:40 +00:00
|
|
|
text_pos_to_packet_.clear();
|
2013-11-15 20:25:33 +00:00
|
|
|
if (!data_out_filename_.isEmpty()) {
|
|
|
|
ws_unlink(data_out_filename_.toUtf8().constData());
|
|
|
|
}
|
2013-11-13 22:18:01 +00:00
|
|
|
for (cur = follow_info_.payload; cur; cur = g_list_next(cur)) {
|
2016-03-01 00:34:32 +00:00
|
|
|
follow_record_t *follow_record = (follow_record_t *)cur->data;
|
|
|
|
if(follow_record->data) {
|
|
|
|
g_byte_array_free(follow_record->data, TRUE);
|
|
|
|
}
|
|
|
|
g_free(follow_record);
|
2013-11-13 22:18:01 +00:00
|
|
|
}
|
|
|
|
g_list_free(follow_info_.payload);
|
|
|
|
follow_info_.payload = NULL;
|
2014-12-27 22:15:41 +00:00
|
|
|
follow_info_.client_port = 0;
|
2013-10-14 21:17:38 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 19:30:30 +00:00
|
|
|
frs_return_t
|
2014-11-01 16:53:07 +00:00
|
|
|
FollowStreamDialog::readStream()
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
ui->teStreamContent->clear();
|
2014-11-01 16:53:07 +00:00
|
|
|
truncated_ = false;
|
2013-11-18 23:39:47 +00:00
|
|
|
frs_return_t ret;
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2013-11-14 17:37:40 +00:00
|
|
|
client_buffer_count_ = 0;
|
|
|
|
server_buffer_count_ = 0;
|
|
|
|
client_packet_count_ = 0;
|
|
|
|
server_packet_count_ = 0;
|
|
|
|
last_packet_ = 0;
|
|
|
|
turns_ = 0;
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
switch(follow_type_) {
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
case FOLLOW_TCP :
|
|
|
|
case FOLLOW_UDP :
|
2016-01-03 05:58:31 +00:00
|
|
|
case FOLLOW_HTTP :
|
|
|
|
ret = readFollowStream();
|
2013-11-18 23:39:47 +00:00
|
|
|
break;
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
case FOLLOW_SSL :
|
2014-11-01 16:53:07 +00:00
|
|
|
ret = readSslStream();
|
2013-11-18 23:39:47 +00:00
|
|
|
break;
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
default :
|
|
|
|
g_assert_not_reached();
|
2013-11-18 23:39:47 +00:00
|
|
|
ret = (frs_return_t)0;
|
|
|
|
break;
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
2013-11-18 23:39:47 +00:00
|
|
|
ui->teStreamContent->moveCursor(QTextCursor::Start);
|
|
|
|
return ret;
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
|
|
|
|
* it gets handed bufferfuls. That's fine for "follow_write_raw()"
|
|
|
|
* and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
|
|
|
|
* the "print_line()" routine from "print.c", and as that routine might
|
|
|
|
* genuinely expect to be handed a line (if, for example, it's using
|
|
|
|
* some OS or desktop environment's printing API, and that API expects
|
|
|
|
* to be handed lines), "follow_print_text()" should probably accumulate
|
|
|
|
* lines in a buffer and hand them "print_line()". (If there's a
|
|
|
|
* complete line in a buffer - i.e., there's nothing of the line in
|
|
|
|
* the previous buffer or the next buffer - it can just hand that to
|
|
|
|
* "print_line()" after filtering out non-printables, as an
|
|
|
|
* optimization.)
|
|
|
|
*
|
|
|
|
* This might or might not be the reason why C arrays display
|
|
|
|
* correctly but get extra blank lines very other line when printed.
|
|
|
|
*/
|
|
|
|
frs_return_t
|
2014-11-01 16:53:07 +00:00
|
|
|
FollowStreamDialog::readSslStream()
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
guint32 global_client_pos = 0, global_server_pos = 0;
|
|
|
|
guint32 * global_pos;
|
|
|
|
GList * cur;
|
|
|
|
frs_return_t frs_return;
|
2016-03-01 00:34:32 +00:00
|
|
|
QElapsedTimer elapsed_timer;
|
|
|
|
|
|
|
|
elapsed_timer.start();
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
for (cur = follow_info_.payload; cur; cur = g_list_next(cur)) {
|
2016-03-01 00:34:32 +00:00
|
|
|
if (dialogClosed()) break;
|
|
|
|
|
2013-09-09 19:30:30 +00:00
|
|
|
SslDecryptedRecord * rec = (SslDecryptedRecord*) cur->data;
|
|
|
|
gboolean include_rec = FALSE;
|
|
|
|
|
|
|
|
if (rec->is_from_server) {
|
|
|
|
global_pos = &global_server_pos;
|
2013-11-13 22:18:01 +00:00
|
|
|
include_rec = (follow_info_.show_stream == BOTH_HOSTS) ||
|
|
|
|
(follow_info_.show_stream == FROM_SERVER);
|
2013-09-09 19:30:30 +00:00
|
|
|
} else {
|
|
|
|
global_pos = &global_client_pos;
|
2013-11-13 22:18:01 +00:00
|
|
|
include_rec = (follow_info_.show_stream == BOTH_HOSTS) ||
|
|
|
|
(follow_info_.show_stream == FROM_CLIENT);
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-03-01 00:34:32 +00:00
|
|
|
QByteArray buffer;
|
2013-09-09 19:30:30 +00:00
|
|
|
if (include_rec) {
|
|
|
|
size_t nchars = rec->data.data_len;
|
2016-03-01 00:34:32 +00:00
|
|
|
// We want a deep copy.
|
|
|
|
buffer.clear();
|
2016-04-07 00:27:55 +00:00
|
|
|
buffer.append((const char *) rec->data.data, (int)nchars);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-03-01 00:34:32 +00:00
|
|
|
frs_return = showBuffer(buffer.data(), nchars,
|
2013-11-14 17:37:40 +00:00
|
|
|
rec->is_from_server, rec->packet_num, global_pos);
|
2013-09-09 19:30:30 +00:00
|
|
|
if (frs_return == FRS_PRINT_ERROR)
|
|
|
|
return frs_return;
|
2016-03-01 00:34:32 +00:00
|
|
|
if (elapsed_timer.elapsed() > info_update_freq_) {
|
|
|
|
fillHintLabel(ui->teStreamContent->textCursor().position());
|
|
|
|
wsApp->processEvents();
|
|
|
|
elapsed_timer.start();
|
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FRS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-11-01 16:53:07 +00:00
|
|
|
FollowStreamDialog::followStream()
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
2014-11-01 16:53:07 +00:00
|
|
|
readStream();
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-03-01 00:34:32 +00:00
|
|
|
const int FollowStreamDialog::max_document_length_ = 500 * 1000 * 1000; // Just a guess
|
2014-11-01 16:53:07 +00:00
|
|
|
void FollowStreamDialog::addText(QString text, gboolean is_from_server, guint32 packet_num)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
2013-11-13 22:18:01 +00:00
|
|
|
if (save_as_ == true)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
size_t nwritten;
|
2013-11-13 22:18:01 +00:00
|
|
|
int FileDescriptor = file_.handle();
|
2016-04-11 18:31:17 +00:00
|
|
|
FILE* fh = ws_fdopen(ws_dup(FileDescriptor), "wb");
|
2016-01-08 13:25:17 +00:00
|
|
|
if (show_type_ == SHOW_RAW) {
|
2015-10-14 21:33:27 +00:00
|
|
|
QByteArray binstream = QByteArray::fromHex(text.toUtf8());
|
|
|
|
nwritten = fwrite(binstream.constData(), binstream.length(), 1, fh);
|
|
|
|
} else {
|
|
|
|
nwritten = fwrite(text.toUtf8().constData(), text.length(), 1, fh);
|
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
fclose(fh);
|
2013-11-19 07:05:34 +00:00
|
|
|
if ((int)nwritten != text.length()) {
|
2013-11-19 00:29:37 +00:00
|
|
|
#if 0
|
|
|
|
report_an_error_maybe();
|
|
|
|
#endif
|
2013-11-19 07:05:34 +00:00
|
|
|
}
|
2013-11-19 00:29:37 +00:00
|
|
|
return;
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 16:53:07 +00:00
|
|
|
if (truncated_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int char_count = ui->teStreamContent->document()->characterCount();
|
|
|
|
if (char_count + text.length() > max_document_length_) {
|
|
|
|
text.truncate(max_document_length_ - char_count);
|
|
|
|
truncated_ = true;
|
|
|
|
}
|
|
|
|
|
2016-03-01 00:34:32 +00:00
|
|
|
setUpdatesEnabled(false);
|
|
|
|
int cur_pos = ui->teStreamContent->verticalScrollBar()->value();
|
2013-10-15 15:22:03 +00:00
|
|
|
ui->teStreamContent->moveCursor(QTextCursor::End);
|
2016-03-01 00:34:32 +00:00
|
|
|
QTextCharFormat tcf = ui->teStreamContent->currentCharFormat();
|
|
|
|
if (is_from_server) {
|
|
|
|
tcf.setForeground(ColorUtils::fromColorT(prefs.st_server_fg));
|
|
|
|
tcf.setBackground(ColorUtils::fromColorT(prefs.st_server_bg));
|
|
|
|
} else {
|
|
|
|
tcf.setForeground(ColorUtils::fromColorT(prefs.st_client_fg));
|
|
|
|
tcf.setBackground(ColorUtils::fromColorT(prefs.st_client_bg));
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
2016-03-01 00:34:32 +00:00
|
|
|
ui->teStreamContent->setCurrentCharFormat(tcf);
|
|
|
|
|
2013-11-18 23:39:47 +00:00
|
|
|
ui->teStreamContent->insertPlainText(text);
|
2013-11-14 17:37:40 +00:00
|
|
|
text_pos_to_packet_[ui->teStreamContent->textCursor().anchor()] = packet_num;
|
2014-11-01 16:53:07 +00:00
|
|
|
|
|
|
|
if (truncated_) {
|
2016-03-01 00:34:32 +00:00
|
|
|
tcf = ui->teStreamContent->currentCharFormat();
|
|
|
|
tcf.setBackground(palette().window().color());
|
|
|
|
tcf.setForeground(palette().windowText().color());
|
2014-11-01 16:53:07 +00:00
|
|
|
ui->teStreamContent->insertPlainText(tr("\n[Stream output truncated]"));
|
|
|
|
ui->teStreamContent->moveCursor(QTextCursor::End);
|
2016-03-01 00:34:32 +00:00
|
|
|
} else {
|
|
|
|
ui->teStreamContent->verticalScrollBar()->setValue(cur_pos);
|
2014-11-01 16:53:07 +00:00
|
|
|
}
|
2016-03-01 00:34:32 +00:00
|
|
|
setUpdatesEnabled(true);
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2013-10-14 21:17:38 +00:00
|
|
|
// The following keyboard shortcuts should work (although
|
|
|
|
// they may not work consistently depending on focus):
|
|
|
|
// / (slash), Ctrl-F - Focus and highlight the search box
|
|
|
|
// Ctrl-G, Ctrl-N, F3 - Find next
|
|
|
|
// Should we make it so that typing any text starts searching?
|
2015-07-07 22:13:24 +00:00
|
|
|
bool FollowStreamDialog::eventFilter(QObject *, QEvent *event)
|
2013-10-14 21:17:38 +00:00
|
|
|
{
|
|
|
|
if (ui->teStreamContent->hasFocus() && event->type() == QEvent::KeyPress) {
|
|
|
|
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
2013-11-18 23:39:47 +00:00
|
|
|
if (keyEvent->matches(QKeySequence::SelectAll) || keyEvent->matches(QKeySequence::Copy)
|
|
|
|
|| keyEvent->text().isEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ui->leFind->setFocus();
|
2013-10-14 21:17:38 +00:00
|
|
|
if (keyEvent->matches(QKeySequence::Find)) {
|
|
|
|
return true;
|
|
|
|
} else if (keyEvent->matches(QKeySequence::FindNext)) {
|
2013-11-13 22:18:01 +00:00
|
|
|
findText();
|
2013-10-14 21:17:38 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FollowStreamDialog::keyPressEvent(QKeyEvent *event)
|
|
|
|
{
|
|
|
|
if (ui->leFind->hasFocus()) {
|
|
|
|
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
|
2013-11-13 22:18:01 +00:00
|
|
|
findText();
|
2013-10-14 21:17:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (event->key() == Qt::Key_Slash || event->matches(QKeySequence::Find)) {
|
|
|
|
ui->leFind->setFocus();
|
|
|
|
ui->leFind->selectAll();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-15 21:31:32 +00:00
|
|
|
if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_N && event->modifiers() & Qt::ControlModifier)) {
|
2013-11-13 22:18:01 +00:00
|
|
|
findText();
|
2013-10-14 21:17:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QDialog::keyPressEvent(event);
|
|
|
|
}
|
|
|
|
|
2013-11-18 23:39:47 +00:00
|
|
|
static inline void sanitize_buffer(char *buffer, size_t nchars) {
|
2013-11-19 00:29:37 +00:00
|
|
|
for (size_t i = 0; i < nchars; i++) {
|
2013-11-18 23:39:47 +00:00
|
|
|
if (buffer[i] == '\n' || buffer[i] == '\r' || buffer[i] == '\t')
|
|
|
|
continue;
|
2014-05-13 12:44:47 +00:00
|
|
|
if (! g_ascii_isprint((guchar)buffer[i])) {
|
2013-11-18 23:39:47 +00:00
|
|
|
buffer[i] = '.';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-09 19:30:30 +00:00
|
|
|
frs_return_t
|
2014-11-01 16:53:07 +00:00
|
|
|
FollowStreamDialog::showBuffer(char *buffer, size_t nchars, gboolean is_from_server, guint32 packet_num,
|
2013-11-14 17:37:40 +00:00
|
|
|
guint32 *global_pos)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
gchar initbuf[256];
|
|
|
|
guint32 current_pos;
|
|
|
|
static const gchar hexchars[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
switch (show_type_) {
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
case SHOW_EBCDIC:
|
2013-11-18 23:39:47 +00:00
|
|
|
{
|
2013-09-09 19:30:30 +00:00
|
|
|
/* If our native arch is ASCII, call: */
|
|
|
|
EBCDIC_to_ASCII((guint8*)buffer, (guint) nchars);
|
2013-11-18 23:39:47 +00:00
|
|
|
sanitize_buffer(buffer, nchars);
|
|
|
|
QByteArray ba = QByteArray(buffer, (int)nchars);
|
2014-11-01 16:53:07 +00:00
|
|
|
addText(ba, is_from_server, packet_num);
|
2013-09-09 19:30:30 +00:00
|
|
|
break;
|
2013-11-18 23:39:47 +00:00
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
case SHOW_ASCII:
|
2013-11-18 23:39:47 +00:00
|
|
|
{
|
2013-09-09 19:30:30 +00:00
|
|
|
/* If our native arch is EBCDIC, call:
|
|
|
|
* ASCII_TO_EBCDIC(buffer, nchars);
|
|
|
|
*/
|
2013-11-18 23:39:47 +00:00
|
|
|
sanitize_buffer(buffer, nchars);
|
|
|
|
QByteArray ba = QByteArray(buffer, (int)nchars);
|
2014-11-01 16:53:07 +00:00
|
|
|
addText(ba, is_from_server, packet_num);
|
2013-09-09 19:30:30 +00:00
|
|
|
break;
|
2013-11-18 23:39:47 +00:00
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2015-10-14 21:33:27 +00:00
|
|
|
case SHOW_UTF8: // UTF-8
|
2013-11-18 23:39:47 +00:00
|
|
|
{
|
|
|
|
// The QString docs say that invalid characters will be replaced with
|
|
|
|
// replacement characters or removed. It would be nice if we could
|
|
|
|
// explicitly choose one or the other.
|
|
|
|
QString utf8 = QString::fromUtf8(buffer, (int)nchars);
|
2014-11-01 16:53:07 +00:00
|
|
|
addText(utf8, is_from_server, packet_num);
|
2013-09-09 19:30:30 +00:00
|
|
|
break;
|
2013-11-18 23:39:47 +00:00
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
case SHOW_HEXDUMP:
|
|
|
|
current_pos = 0;
|
|
|
|
while (current_pos < nchars) {
|
|
|
|
gchar hexbuf[256];
|
|
|
|
int i;
|
|
|
|
gchar *cur = hexbuf, *ascii_start;
|
|
|
|
|
|
|
|
/* is_from_server indentation : put 4 spaces at the
|
|
|
|
* beginning of the string */
|
|
|
|
/* XXX - We might want to prepend each line with "C" or "S" instead. */
|
2013-11-13 22:18:01 +00:00
|
|
|
if (is_from_server && follow_info_.show_stream == BOTH_HOSTS) {
|
2013-09-09 19:30:30 +00:00
|
|
|
memset(cur, ' ', 4);
|
|
|
|
cur += 4;
|
|
|
|
}
|
|
|
|
cur += g_snprintf(cur, 20, "%08X ", *global_pos);
|
|
|
|
/* 49 is space consumed by hex chars */
|
2016-02-10 08:08:33 +00:00
|
|
|
ascii_start = cur + 49 + 2;
|
2013-09-09 19:30:30 +00:00
|
|
|
for (i = 0; i < 16 && current_pos + i < nchars; i++) {
|
|
|
|
*cur++ =
|
|
|
|
hexchars[(buffer[current_pos + i] & 0xf0) >> 4];
|
|
|
|
*cur++ =
|
|
|
|
hexchars[buffer[current_pos + i] & 0x0f];
|
|
|
|
*cur++ = ' ';
|
|
|
|
if (i == 7)
|
|
|
|
*cur++ = ' ';
|
|
|
|
}
|
|
|
|
/* Fill it up if column isn't complete */
|
|
|
|
while (cur < ascii_start)
|
|
|
|
*cur++ = ' ';
|
|
|
|
|
|
|
|
/* Now dump bytes as text */
|
|
|
|
for (i = 0; i < 16 && current_pos + i < nchars; i++) {
|
|
|
|
*cur++ =
|
2014-05-13 12:44:47 +00:00
|
|
|
(g_ascii_isprint((guchar)buffer[current_pos + i]) ?
|
2016-01-23 12:18:30 +00:00
|
|
|
buffer[current_pos + i] : '.');
|
2013-09-09 19:30:30 +00:00
|
|
|
if (i == 7) {
|
|
|
|
*cur++ = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
current_pos += i;
|
|
|
|
(*global_pos) += i;
|
|
|
|
*cur++ = '\n';
|
|
|
|
*cur = 0;
|
|
|
|
|
2014-11-01 16:53:07 +00:00
|
|
|
addText(hexbuf, is_from_server, packet_num);
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHOW_CARRAY:
|
|
|
|
current_pos = 0;
|
2013-11-14 17:37:40 +00:00
|
|
|
g_snprintf(initbuf, sizeof(initbuf), "char peer%d_%d[] = { /* Packet %u */\n",
|
2013-09-09 19:30:30 +00:00
|
|
|
is_from_server ? 1 : 0,
|
2013-11-14 17:37:40 +00:00
|
|
|
is_from_server ? server_buffer_count_++ : client_buffer_count_++,
|
|
|
|
packet_num);
|
2014-11-01 16:53:07 +00:00
|
|
|
addText(initbuf, is_from_server, packet_num);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
while (current_pos < nchars) {
|
|
|
|
gchar hexbuf[256];
|
|
|
|
int i, cur;
|
|
|
|
|
|
|
|
cur = 0;
|
|
|
|
for (i = 0; i < 8 && current_pos + i < nchars; i++) {
|
|
|
|
/* Prepend entries with "0x" */
|
|
|
|
hexbuf[cur++] = '0';
|
|
|
|
hexbuf[cur++] = 'x';
|
|
|
|
hexbuf[cur++] =
|
|
|
|
hexchars[(buffer[current_pos + i] & 0xf0) >> 4];
|
|
|
|
hexbuf[cur++] =
|
|
|
|
hexchars[buffer[current_pos + i] & 0x0f];
|
|
|
|
|
|
|
|
/* Delimit array entries with a comma */
|
|
|
|
if (current_pos + i + 1 < nchars)
|
|
|
|
hexbuf[cur++] = ',';
|
|
|
|
|
|
|
|
hexbuf[cur++] = ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Terminate the array if we are at the end */
|
|
|
|
if (current_pos + i == nchars) {
|
|
|
|
hexbuf[cur++] = '}';
|
|
|
|
hexbuf[cur++] = ';';
|
|
|
|
}
|
|
|
|
|
|
|
|
current_pos += i;
|
|
|
|
(*global_pos) += i;
|
|
|
|
hexbuf[cur++] = '\n';
|
|
|
|
hexbuf[cur] = 0;
|
2014-11-01 16:53:07 +00:00
|
|
|
addText(hexbuf, is_from_server, packet_num);
|
2013-11-18 23:39:47 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SHOW_YAML:
|
|
|
|
{
|
2013-11-19 20:29:58 +00:00
|
|
|
QString yaml_text;
|
2013-11-18 23:39:47 +00:00
|
|
|
|
|
|
|
const int base64_raw_len = 57; // Encodes to 76 bytes, common in RFCs
|
|
|
|
current_pos = 0;
|
|
|
|
|
2013-11-19 20:29:58 +00:00
|
|
|
if (packet_num != last_packet_) {
|
|
|
|
yaml_text.append(QString("# Packet %1\npeer%2_%3: !!binary |\n")
|
|
|
|
.arg(packet_num)
|
|
|
|
.arg(is_from_server ? 1 : 0)
|
|
|
|
.arg(is_from_server ? server_buffer_count_++ : client_buffer_count_++));
|
|
|
|
}
|
2013-11-18 23:39:47 +00:00
|
|
|
while (current_pos < nchars) {
|
|
|
|
int len = current_pos + base64_raw_len < nchars ? base64_raw_len : (int) nchars - current_pos;
|
|
|
|
QByteArray base64_data(&buffer[current_pos], len);
|
|
|
|
|
|
|
|
yaml_text += " " + base64_data.toBase64() + "\n";
|
|
|
|
|
|
|
|
current_pos += len;
|
|
|
|
(*global_pos) += len;
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
2014-11-01 16:53:07 +00:00
|
|
|
addText(yaml_text, is_from_server, packet_num);
|
2013-09-09 19:30:30 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-10-14 21:33:27 +00:00
|
|
|
|
|
|
|
case SHOW_RAW:
|
|
|
|
{
|
|
|
|
QByteArray ba = QByteArray(buffer, (int)nchars).toHex();
|
|
|
|
ba += '\n';
|
|
|
|
addText(ba, is_from_server, packet_num);
|
|
|
|
break;
|
|
|
|
}
|
2013-11-18 23:39:47 +00:00
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2013-11-14 17:37:40 +00:00
|
|
|
if (last_packet_ == 0) {
|
|
|
|
last_from_server_ = is_from_server;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (packet_num != last_packet_) {
|
|
|
|
last_packet_ = packet_num;
|
|
|
|
if (is_from_server) {
|
|
|
|
server_packet_count_++;
|
|
|
|
} else {
|
|
|
|
client_packet_count_++;
|
|
|
|
}
|
|
|
|
if (last_from_server_ != is_from_server) {
|
|
|
|
last_from_server_ = is_from_server;
|
|
|
|
turns_++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-09 19:30:30 +00:00
|
|
|
return FRS_OK;
|
|
|
|
}
|
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
bool FollowStreamDialog::follow(QString previous_filter, bool use_stream_index, int stream_num)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
2013-11-13 22:18:01 +00:00
|
|
|
QString follow_filter;
|
2013-09-09 19:30:30 +00:00
|
|
|
const char *hostname0 = NULL, *hostname1 = NULL;
|
|
|
|
char *port0 = NULL, *port1 = NULL;
|
2013-11-13 22:18:01 +00:00
|
|
|
QString server_to_client_string;
|
|
|
|
QString client_to_server_string;
|
|
|
|
QString both_directions_string;
|
2016-01-08 13:25:17 +00:00
|
|
|
gboolean is_follower = FALSE;
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
resetStream();
|
|
|
|
|
2014-12-29 22:12:43 +00:00
|
|
|
if (file_closed_)
|
2013-11-13 22:18:01 +00:00
|
|
|
{
|
|
|
|
QMessageBox::warning(this, tr("No capture file."), tr("Please make sure you have a capture file opened."));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-12-29 22:12:43 +00:00
|
|
|
if (cap_file_.capFile()->edt == NULL)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
QMessageBox::warning(this, tr("Error following stream."), tr("Capture file invalid."));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
is_follower = proto_is_frame_protocol(cap_file_.capFile()->edt->pi.layers, proto_get_protocol_filter_name(get_follow_proto_id(follower_)));
|
|
|
|
if (!is_follower) {
|
|
|
|
QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a %1 packet selected.").arg
|
|
|
|
(proto_get_protocol_short_name(find_protocol_by_id(get_follow_proto_id(follower_)))));
|
|
|
|
return false;
|
|
|
|
}
|
2013-11-21 16:42:10 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
if (follow_type_ == FOLLOW_SSL)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
/* we got ssl so we can follow */
|
2013-11-13 22:18:01 +00:00
|
|
|
removeStreamControls();
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
follow_reset_stream(&follow_info_);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
/* Create a new filter that matches all packets in the TCP stream,
|
|
|
|
and set the display filter entry accordingly */
|
2014-12-27 22:15:41 +00:00
|
|
|
if (use_stream_index) {
|
2016-01-08 13:25:17 +00:00
|
|
|
follow_filter = gchar_free_to_qstring(get_follow_index_func(follower_)(stream_num));
|
2013-11-13 22:18:01 +00:00
|
|
|
} else {
|
2016-01-08 13:25:17 +00:00
|
|
|
follow_filter = gchar_free_to_qstring(get_follow_conv_func(follower_)(&cap_file_.capFile()->edt->pi, &stream_num));
|
2013-11-13 22:18:01 +00:00
|
|
|
}
|
|
|
|
if (follow_filter.isEmpty()) {
|
2013-09-09 19:30:30 +00:00
|
|
|
QMessageBox::warning(this,
|
|
|
|
tr("Error creating filter for this stream."),
|
|
|
|
tr("A transport or network layer header is needed."));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* append the negation */
|
2013-11-13 22:18:01 +00:00
|
|
|
if(!previous_filter.isEmpty()) {
|
|
|
|
filter_out_filter_ = QString("%1 and !(%2)")
|
|
|
|
.arg(previous_filter).arg(follow_filter);
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-11-13 22:18:01 +00:00
|
|
|
filter_out_filter_ = QString("!(%1)").arg(follow_filter);
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
/* data will be passed via tap callback*/
|
|
|
|
if (!registerTapListener(get_follow_tap_string(follower_), &follow_info_,
|
|
|
|
follow_filter.toUtf8().constData(),
|
|
|
|
0, NULL, get_follow_tap_handler(follower_), NULL)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
switch (follow_type_)
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
case FOLLOW_TCP:
|
2014-01-04 01:13:01 +00:00
|
|
|
{
|
2015-12-15 07:52:09 +00:00
|
|
|
int stream_count = get_tcp_stream_count();
|
2013-11-13 22:18:01 +00:00
|
|
|
ui->streamNumberSpinBox->blockSignals(true);
|
2015-12-15 07:52:09 +00:00
|
|
|
ui->streamNumberSpinBox->setMaximum(stream_count-1);
|
2016-01-08 13:25:17 +00:00
|
|
|
ui->streamNumberSpinBox->setValue(stream_num);
|
2013-11-13 22:18:01 +00:00
|
|
|
ui->streamNumberSpinBox->blockSignals(false);
|
2014-01-04 01:13:01 +00:00
|
|
|
ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count));
|
|
|
|
ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip());
|
2013-09-09 19:30:30 +00:00
|
|
|
|
|
|
|
break;
|
2014-01-04 01:13:01 +00:00
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
case FOLLOW_UDP:
|
2014-12-27 22:15:41 +00:00
|
|
|
{
|
2015-12-15 07:52:09 +00:00
|
|
|
int stream_count = get_udp_stream_count();
|
2014-12-27 22:15:41 +00:00
|
|
|
ui->streamNumberSpinBox->blockSignals(true);
|
2015-12-15 07:52:09 +00:00
|
|
|
ui->streamNumberSpinBox->setMaximum(stream_count-1);
|
2016-01-08 13:25:17 +00:00
|
|
|
ui->streamNumberSpinBox->setValue(stream_num);
|
2014-12-27 22:15:41 +00:00
|
|
|
ui->streamNumberSpinBox->blockSignals(false);
|
|
|
|
ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count));
|
|
|
|
ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip());
|
|
|
|
|
2013-09-09 19:30:30 +00:00
|
|
|
break;
|
2014-12-27 22:15:41 +00:00
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
case FOLLOW_SSL:
|
2016-01-02 13:58:08 +00:00
|
|
|
case FOLLOW_HTTP:
|
2016-01-08 13:25:17 +00:00
|
|
|
/* No extra handling */
|
2016-01-02 13:58:08 +00:00
|
|
|
break;
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
|
2015-11-16 23:15:06 +00:00
|
|
|
beginRetapPackets();
|
|
|
|
updateWidgets(true);
|
|
|
|
|
2013-09-09 19:30:30 +00:00
|
|
|
/* Run the display filter so it goes in effect - even if it's the
|
|
|
|
same as the previous display filter. */
|
2013-11-13 22:18:01 +00:00
|
|
|
emit updateFilter(follow_filter, TRUE);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
removeTapListeners();
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
hostname0 = address_to_name(&follow_info_.client_ip);
|
|
|
|
hostname1 = address_to_name(&follow_info_.server_ip);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
port0 = get_follow_port_to_display(follower_)(NULL, follow_info_.client_port);
|
|
|
|
port1 = get_follow_port_to_display(follower_)(NULL, follow_info_.server_port);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
server_to_client_string =
|
|
|
|
QString("%1:%2 %3 %4:%5 (%6)")
|
|
|
|
.arg(hostname0).arg(port0)
|
|
|
|
.arg(UTF8_RIGHTWARDS_ARROW)
|
|
|
|
.arg(hostname1).arg(port1)
|
|
|
|
.arg(gchar_free_to_qstring(format_size(
|
|
|
|
follow_info_.bytes_written[0],
|
|
|
|
format_size_unit_bytes|format_size_prefix_si)));
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
client_to_server_string =
|
|
|
|
QString("%1:%2 %3 %4:%5 (%6)")
|
|
|
|
.arg(hostname1).arg(port1)
|
|
|
|
.arg(UTF8_RIGHTWARDS_ARROW)
|
|
|
|
.arg(hostname0).arg(port0)
|
|
|
|
.arg(gchar_free_to_qstring(format_size(
|
|
|
|
follow_info_.bytes_written[1],
|
|
|
|
format_size_unit_bytes|format_size_prefix_si)));
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2015-01-07 21:24:17 +00:00
|
|
|
wmem_free(NULL, port0);
|
|
|
|
wmem_free(NULL, port1);
|
|
|
|
|
2016-01-08 13:25:17 +00:00
|
|
|
both_directions_string = QString("Entire conversation (%1)")
|
|
|
|
.arg(gchar_free_to_qstring(format_size(
|
|
|
|
follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
|
|
|
|
format_size_unit_bytes|format_size_prefix_si)));
|
|
|
|
setWindowSubtitle(tr("Follow %1 Stream (%2)").arg(proto_get_protocol_short_name(find_protocol_by_id(get_follow_proto_id(follower_))))
|
|
|
|
.arg(follow_filter));
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2016-03-01 00:34:32 +00:00
|
|
|
ui->cbDirections->blockSignals(true);
|
2013-09-09 19:30:30 +00:00
|
|
|
ui->cbDirections->clear();
|
2014-12-29 22:12:43 +00:00
|
|
|
ui->cbDirections->addItem(both_directions_string);
|
|
|
|
ui->cbDirections->addItem(client_to_server_string);
|
|
|
|
ui->cbDirections->addItem(server_to_client_string);
|
2016-03-01 00:34:32 +00:00
|
|
|
ui->cbDirections->blockSignals(false);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2014-11-01 16:53:07 +00:00
|
|
|
followStream();
|
2013-11-14 17:37:40 +00:00
|
|
|
fillHintLabel(-1);
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2015-11-16 23:15:06 +00:00
|
|
|
updateWidgets(false);
|
2015-08-24 19:30:56 +00:00
|
|
|
endRetapPackets();
|
2013-09-09 19:30:30 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-29 22:12:43 +00:00
|
|
|
void FollowStreamDialog::captureFileClosing()
|
|
|
|
{
|
|
|
|
QString tooltip = tr("File closed.");
|
|
|
|
ui->streamNumberSpinBox->setToolTip(tooltip);
|
|
|
|
ui->streamNumberLabel->setToolTip(tooltip);
|
|
|
|
WiresharkDialog::captureFileClosing();
|
|
|
|
}
|
|
|
|
|
2013-09-09 19:30:30 +00:00
|
|
|
/*
|
|
|
|
* XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
|
|
|
|
* it gets handed bufferfuls. That's fine for "follow_write_raw()"
|
|
|
|
* and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
|
|
|
|
* the "print_line()" routine from "print.c", and as that routine might
|
|
|
|
* genuinely expect to be handed a line (if, for example, it's using
|
|
|
|
* some OS or desktop environment's printing API, and that API expects
|
|
|
|
* to be handed lines), "follow_print_text()" should probably accumulate
|
|
|
|
* lines in a buffer and hand them "print_line()". (If there's a
|
|
|
|
* complete line in a buffer - i.e., there's nothing of the line in
|
|
|
|
* the previous buffer or the next buffer - it can just hand that to
|
|
|
|
* "print_line()" after filtering out non-printables, as an
|
|
|
|
* optimization.)
|
|
|
|
*
|
|
|
|
* This might or might not be the reason why C arrays display
|
|
|
|
* correctly but get extra blank lines very other line when printed.
|
|
|
|
*/
|
|
|
|
frs_return_t
|
2016-01-03 05:58:31 +00:00
|
|
|
FollowStreamDialog::readFollowStream()
|
2013-09-09 19:30:30 +00:00
|
|
|
{
|
|
|
|
guint32 global_client_pos = 0, global_server_pos = 0;
|
|
|
|
guint32 *global_pos;
|
|
|
|
gboolean skip;
|
|
|
|
GList* cur;
|
|
|
|
frs_return_t frs_return;
|
|
|
|
follow_record_t *follow_record;
|
2016-03-01 00:34:32 +00:00
|
|
|
QElapsedTimer elapsed_timer;
|
|
|
|
|
|
|
|
elapsed_timer.start();
|
2013-09-09 19:30:30 +00:00
|
|
|
|
2013-11-13 22:18:01 +00:00
|
|
|
for (cur = follow_info_.payload; cur; cur = g_list_next(cur)) {
|
2016-03-01 00:34:32 +00:00
|
|
|
if (dialogClosed()) break;
|
|
|
|
|
2013-09-09 19:30:30 +00:00
|
|
|
follow_record = (follow_record_t *)cur->data;
|
|
|
|
skip = FALSE;
|
|
|
|
if (!follow_record->is_server) {
|
|
|
|
global_pos = &global_client_pos;
|
2013-11-13 22:18:01 +00:00
|
|
|
if(follow_info_.show_stream == FROM_SERVER) {
|
2013-09-09 19:30:30 +00:00
|
|
|
skip = TRUE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
global_pos = &global_server_pos;
|
2013-11-13 22:18:01 +00:00
|
|
|
if (follow_info_.show_stream == FROM_CLIENT) {
|
2013-09-09 19:30:30 +00:00
|
|
|
skip = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 00:34:32 +00:00
|
|
|
QByteArray buffer;
|
2013-09-09 19:30:30 +00:00
|
|
|
if (!skip) {
|
2016-03-01 00:34:32 +00:00
|
|
|
// We want a deep copy.
|
|
|
|
buffer.clear();
|
|
|
|
buffer.append((const char *) follow_record->data->data,
|
|
|
|
follow_record->data->len);
|
2014-11-01 16:53:07 +00:00
|
|
|
frs_return = showBuffer(
|
2016-03-01 00:34:32 +00:00
|
|
|
buffer.data(),
|
2013-09-09 19:30:30 +00:00
|
|
|
follow_record->data->len,
|
|
|
|
follow_record->is_server,
|
2013-11-14 17:37:40 +00:00
|
|
|
follow_record->packet_num,
|
|
|
|
global_pos);
|
2013-09-09 19:30:30 +00:00
|
|
|
if(frs_return == FRS_PRINT_ERROR)
|
|
|
|
return frs_return;
|
2016-03-01 00:34:32 +00:00
|
|
|
if (elapsed_timer.elapsed() > info_update_freq_) {
|
|
|
|
fillHintLabel(ui->teStreamContent->textCursor().position());
|
|
|
|
wsApp->processEvents();
|
|
|
|
elapsed_timer.start();
|
|
|
|
}
|
2013-09-09 19:30:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FRS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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:
|
|
|
|
*/
|