Extract pcapfileformatoptions into separate files
This commit is contained in:
parent
4d0f6849f6
commit
7014db8447
@ -24,6 +24,9 @@ HEADERS = \
|
|||||||
sessionfileformat.h \
|
sessionfileformat.h \
|
||||||
streamfileformat.h
|
streamfileformat.h
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
pcapfileformatoptions.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
ostprotolib.cpp \
|
ostprotolib.cpp \
|
||||||
nativefileformat.cpp \
|
nativefileformat.cpp \
|
||||||
@ -39,6 +42,9 @@ SOURCES += \
|
|||||||
streamfileformat.cpp \
|
streamfileformat.cpp \
|
||||||
spinboxdelegate.cpp
|
spinboxdelegate.cpp
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
pcapfileformatoptions.cpp
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
vlanpdml.cpp \
|
vlanpdml.cpp \
|
||||||
svlanpdml.cpp \
|
svlanpdml.cpp \
|
||||||
|
@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include "pcapfileformat.h"
|
#include "pcapfileformat.h"
|
||||||
|
|
||||||
|
#include "pcapfileformatoptions.h"
|
||||||
|
|
||||||
#include "pdmlreader.h"
|
#include "pdmlreader.h"
|
||||||
#include "ostprotolib.h"
|
#include "ostprotolib.h"
|
||||||
#include "streambase.h"
|
#include "streambase.h"
|
||||||
@ -42,38 +44,6 @@ const quint32 kDltEthernet = 1;
|
|||||||
|
|
||||||
PcapFileFormat pcapFileFormat;
|
PcapFileFormat pcapFileFormat;
|
||||||
|
|
||||||
PcapImportOptionsDialog::PcapImportOptionsDialog(QVariantMap *options)
|
|
||||||
: QDialog(NULL)
|
|
||||||
{
|
|
||||||
setupUi(this);
|
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
|
||||||
options_ = options;
|
|
||||||
|
|
||||||
viaPdml->setChecked(options_->value("ViaPdml").toBool());
|
|
||||||
// XXX: By default this key is absent - so that pcap import tests
|
|
||||||
// evaluate to false and hence show minimal diffs.
|
|
||||||
// However, for the GUI user, this should be enabled by default.
|
|
||||||
recalculateCksums->setChecked(
|
|
||||||
options_->value("RecalculateCksums", QVariant(true))
|
|
||||||
.toBool());
|
|
||||||
doDiff->setChecked(options_->value("DoDiff").toBool());
|
|
||||||
|
|
||||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
|
||||||
}
|
|
||||||
|
|
||||||
PcapImportOptionsDialog::~PcapImportOptionsDialog()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PcapImportOptionsDialog::accept()
|
|
||||||
{
|
|
||||||
options_->insert("ViaPdml", viaPdml->isChecked());
|
|
||||||
options_->insert("RecalculateCksums", recalculateCksums->isChecked());
|
|
||||||
options_->insert("DoDiff", doDiff->isChecked());
|
|
||||||
|
|
||||||
QDialog::accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
PcapFileFormat::PcapFileFormat()
|
PcapFileFormat::PcapFileFormat()
|
||||||
{
|
{
|
||||||
importOptions_.insert("ViaPdml", true);
|
importOptions_.insert("ViaPdml", true);
|
||||||
|
@ -20,24 +20,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#define _PCAP_FILE_FORMAT_H
|
#define _PCAP_FILE_FORMAT_H
|
||||||
|
|
||||||
#include "streamfileformat.h"
|
#include "streamfileformat.h"
|
||||||
#include "ui_pcapfileimport.h"
|
|
||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
|
|
||||||
class PcapImportOptionsDialog: public QDialog, public Ui::PcapFileImport
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PcapImportOptionsDialog(QVariantMap *options);
|
|
||||||
~PcapImportOptionsDialog();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void accept();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVariantMap *options_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PdmlReader;
|
class PdmlReader;
|
||||||
class PcapFileFormat : public StreamFileFormat
|
class PcapFileFormat : public StreamFileFormat
|
||||||
{
|
{
|
||||||
|
@ -17,30 +17,7 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pcapfileformat.h"
|
#include "pcapfileformatoptions.h"
|
||||||
|
|
||||||
#include "pdmlreader.h"
|
|
||||||
#include "ostprotolib.h"
|
|
||||||
#include "streambase.h"
|
|
||||||
#include "hexdump.pb.h"
|
|
||||||
|
|
||||||
#include <QDataStream>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QTemporaryFile>
|
|
||||||
#include <QtGlobal>
|
|
||||||
|
|
||||||
const quint32 kPcapFileMagic = 0xa1b2c3d4;
|
|
||||||
const quint32 kPcapFileMagicSwapped = 0xd4c3b2a1;
|
|
||||||
const quint32 kNanoSecondPcapFileMagic = 0xa1b23c4d;
|
|
||||||
const quint32 kNanoSecondPcapFileMagicSwapped = 0x4d3cb2a1;
|
|
||||||
const quint16 kPcapFileVersionMajor = 2;
|
|
||||||
const quint16 kPcapFileVersionMinor = 4;
|
|
||||||
const quint32 kMaxSnapLen = 65535;
|
|
||||||
const quint32 kDltEthernet = 1;
|
|
||||||
|
|
||||||
PcapFileFormat pcapFileFormat;
|
|
||||||
|
|
||||||
PcapImportOptionsDialog::PcapImportOptionsDialog(QVariantMap *options)
|
PcapImportOptionsDialog::PcapImportOptionsDialog(QVariantMap *options)
|
||||||
: QDialog(NULL)
|
: QDialog(NULL)
|
||||||
@ -74,678 +51,3 @@ void PcapImportOptionsDialog::accept()
|
|||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
PcapFileFormat::PcapFileFormat()
|
|
||||||
{
|
|
||||||
importOptions_.insert("ViaPdml", true);
|
|
||||||
importOptions_.insert("DoDiff", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
PcapFileFormat::~PcapFileFormat()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PcapFileFormat::open(const QString fileName,
|
|
||||||
OstProto::StreamConfigList &streams, QString &error)
|
|
||||||
{
|
|
||||||
bool isOk = false;
|
|
||||||
QFile file(fileName);
|
|
||||||
QTemporaryFile file2;
|
|
||||||
quint32 magic;
|
|
||||||
uchar gzipMagic[2];
|
|
||||||
bool nsecResolution = false;
|
|
||||||
int len;
|
|
||||||
PcapFileHeader fileHdr;
|
|
||||||
PcapPacketHeader pktHdr;
|
|
||||||
OstProto::Stream *prevStream = NULL;
|
|
||||||
quint64 lastXsec = 0;
|
|
||||||
int pktCount;
|
|
||||||
qint64 byteCount = 0;
|
|
||||||
qint64 byteTotal;
|
|
||||||
QByteArray pktBuf;
|
|
||||||
bool tryConvert = true;
|
|
||||||
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
goto _err_open;
|
|
||||||
|
|
||||||
len = file.peek((char*)gzipMagic, sizeof(gzipMagic));
|
|
||||||
if (len < int(sizeof(gzipMagic)))
|
|
||||||
goto _err_reading_magic;
|
|
||||||
|
|
||||||
if ((gzipMagic[0] == 0x1f) && (gzipMagic[1] == 0x8b))
|
|
||||||
{
|
|
||||||
QProcess gzip;
|
|
||||||
|
|
||||||
emit status("Decompressing...");
|
|
||||||
emit target(0);
|
|
||||||
|
|
||||||
if (!file2.open())
|
|
||||||
{
|
|
||||||
error.append("Unable to open temporary file to uncompress .gz\n");
|
|
||||||
goto _err_unzip_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug("decompressing to %s", qPrintable(file2.fileName()));
|
|
||||||
|
|
||||||
gzip.setStandardOutputFile(file2.fileName());
|
|
||||||
gzip.start(OstProtoLib::gzipPath(),
|
|
||||||
QStringList()
|
|
||||||
<< "-d"
|
|
||||||
<< "-c"
|
|
||||||
<< fileName);
|
|
||||||
if (!gzip.waitForStarted(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Unable to start gzip. Check path in Preferences.\n"));
|
|
||||||
goto _err_unzip_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gzip.waitForFinished(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Error running gzip\n"));
|
|
||||||
goto _err_unzip_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
file2.seek(0);
|
|
||||||
|
|
||||||
fd_.setDevice(&file2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fd_.setDevice(&file);
|
|
||||||
}
|
|
||||||
|
|
||||||
_retry:
|
|
||||||
byteTotal = fd_.device()->size() - sizeof(fileHdr);
|
|
||||||
|
|
||||||
emit status("Reading File Header...");
|
|
||||||
emit target(0);
|
|
||||||
|
|
||||||
fd_ >> magic;
|
|
||||||
|
|
||||||
qDebug("magic = %08x", magic);
|
|
||||||
|
|
||||||
if (magic == kPcapFileMagic)
|
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
else if (magic == kNanoSecondPcapFileMagic)
|
|
||||||
{
|
|
||||||
nsecResolution = true;
|
|
||||||
}
|
|
||||||
else if ((magic == kPcapFileMagicSwapped)
|
|
||||||
|| (magic == kNanoSecondPcapFileMagicSwapped))
|
|
||||||
{
|
|
||||||
// Toggle Byte order
|
|
||||||
if (fd_.byteOrder() == QDataStream::BigEndian)
|
|
||||||
fd_.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
else
|
|
||||||
fd_.setByteOrder(QDataStream::BigEndian);
|
|
||||||
|
|
||||||
nsecResolution = (magic == kNanoSecondPcapFileMagicSwapped);
|
|
||||||
}
|
|
||||||
else // Not a pcap file (could be pcapng or something else)
|
|
||||||
{
|
|
||||||
if (tryConvert)
|
|
||||||
{
|
|
||||||
// Close and reopen the temp file to be safe
|
|
||||||
file2.close();
|
|
||||||
if (!file2.open())
|
|
||||||
{
|
|
||||||
error.append("Unable to open temporary file to convert to PCAP\n");
|
|
||||||
goto _err_convert2pcap;
|
|
||||||
}
|
|
||||||
fd_.setDevice(0); // disconnect data stream from file
|
|
||||||
|
|
||||||
if (convertToStandardPcap(fileName, file2.fileName(), error))
|
|
||||||
{
|
|
||||||
fd_.setDevice(&file2);
|
|
||||||
tryConvert = false;
|
|
||||||
goto _retry;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error = QString(tr("Unable to convert %1 to standard PCAP format"))
|
|
||||||
.arg(fileName);
|
|
||||||
goto _err_convert2pcap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
goto _err_bad_magic;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug("reading filehdr");
|
|
||||||
|
|
||||||
fd_ >> fileHdr.versionMajor;
|
|
||||||
fd_ >> fileHdr.versionMinor;
|
|
||||||
fd_ >> fileHdr.thisZone;
|
|
||||||
fd_ >> fileHdr.sigfigs;
|
|
||||||
fd_ >> fileHdr.snapLen;
|
|
||||||
fd_ >> fileHdr.network;
|
|
||||||
|
|
||||||
qDebug("version check");
|
|
||||||
if ((fileHdr.versionMajor != kPcapFileVersionMajor) ||
|
|
||||||
(fileHdr.versionMinor != kPcapFileVersionMinor))
|
|
||||||
goto _err_unsupported_version;
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// XXX: we support only Ethernet, for now
|
|
||||||
if (fileHdr.network != kDltEthernet)
|
|
||||||
goto _err_unsupported_encap;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pktBuf.resize(fileHdr.snapLen);
|
|
||||||
|
|
||||||
// XXX: PDML also needs the PCAP file to cross check packet bytes
|
|
||||||
// with the PDML data, so we can't do PDML conversion any earlier
|
|
||||||
// than this
|
|
||||||
qDebug("pdml check");
|
|
||||||
if (importOptions_.value("ViaPdml").toBool())
|
|
||||||
{
|
|
||||||
QProcess tshark;
|
|
||||||
QTemporaryFile pdmlFile;
|
|
||||||
PdmlReader reader(&streams, importOptions_);
|
|
||||||
|
|
||||||
if (!pdmlFile.open())
|
|
||||||
{
|
|
||||||
error.append("Unable to open temporary file to create PDML\n");
|
|
||||||
goto _non_pdml;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug("generating PDML %s", qPrintable(pdmlFile.fileName()));
|
|
||||||
emit status("Generating PDML...");
|
|
||||||
emit target(0);
|
|
||||||
|
|
||||||
tshark.setStandardOutputFile(pdmlFile.fileName());
|
|
||||||
tshark.start(OstProtoLib::tsharkPath(),
|
|
||||||
QStringList()
|
|
||||||
<< QString("-r%1").arg(fileName)
|
|
||||||
<< "-otcp.desegment_tcp_streams:FALSE"
|
|
||||||
<< "-Tpdml");
|
|
||||||
if (!tshark.waitForStarted(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Unable to start tshark. Check path in preferences.\n"));
|
|
||||||
goto _non_pdml;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tshark.waitForFinished(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Error running tshark\n"));
|
|
||||||
goto _non_pdml;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(&reader, SIGNAL(progress(int)), this, SIGNAL(progress(int)));
|
|
||||||
|
|
||||||
emit status("Reading PDML packets...");
|
|
||||||
emit target(100); // in percentage
|
|
||||||
|
|
||||||
// pdml reader needs pcap, so pass self
|
|
||||||
isOk = reader.read(&pdmlFile, this, &stop_);
|
|
||||||
|
|
||||||
if (stop_)
|
|
||||||
goto _user_cancel;
|
|
||||||
|
|
||||||
if (!isOk)
|
|
||||||
{
|
|
||||||
error.append(QString("Error processing PDML (%1, %2): %3\n")
|
|
||||||
.arg(reader.lineNumber())
|
|
||||||
.arg(reader.columnNumber())
|
|
||||||
.arg(reader.errorString()));
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!importOptions_.value("DoDiff").toBool())
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
|
|
||||||
// !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
|
|
||||||
// Let's do the diff ...
|
|
||||||
// !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
|
|
||||||
|
|
||||||
QProcess awk;
|
|
||||||
QProcess diff;
|
|
||||||
QTemporaryFile originalTextFile;
|
|
||||||
QTemporaryFile importedPcapFile;
|
|
||||||
QTemporaryFile importedTextFile;
|
|
||||||
QTemporaryFile diffFile;
|
|
||||||
const QString kAwkFilter =
|
|
||||||
"/^[^0]/ { "
|
|
||||||
"printf \" %s \", $1;"
|
|
||||||
"for (i=4; i<NF; i++) printf \"%s \", $i;"
|
|
||||||
"next;"
|
|
||||||
"}"
|
|
||||||
"// {print}";
|
|
||||||
|
|
||||||
// Convert original file to text ...
|
|
||||||
if (!originalTextFile.open())
|
|
||||||
{
|
|
||||||
error.append("Unable to open temporary file to create text file "
|
|
||||||
"(original) for diff\n");
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
qDebug("generating text file (original) %s",
|
|
||||||
qPrintable(originalTextFile.fileName()));
|
|
||||||
|
|
||||||
emit status("Preparing original PCAP for diff...");
|
|
||||||
emit target(0);
|
|
||||||
|
|
||||||
tshark.setStandardOutputProcess(&awk);
|
|
||||||
awk.setStandardOutputFile(originalTextFile.fileName());
|
|
||||||
tshark.start(OstProtoLib::tsharkPath(),
|
|
||||||
QStringList()
|
|
||||||
<< QString("-r%1").arg(fileName)
|
|
||||||
<< "-otcp.desegment_tcp_streams:FALSE"
|
|
||||||
<< "-P"
|
|
||||||
<< "-x");
|
|
||||||
if (!tshark.waitForStarted(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Unable to start tshark. Check path in Preferences.\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
awk.start(OstProtoLib::awkPath(),
|
|
||||||
QStringList() << kAwkFilter);
|
|
||||||
if (!awk.waitForStarted(-1))
|
|
||||||
{
|
|
||||||
tshark.kill();
|
|
||||||
error.append(QString("Unable to start awk. Check path in Preferences.\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tshark.waitForFinished(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Error running tshark\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
if (!awk.waitForFinished(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Error running awk\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save imported file as PCAP
|
|
||||||
if (!importedPcapFile.open())
|
|
||||||
{
|
|
||||||
error.append("Unable to open temporary file to create pcap file "
|
|
||||||
"from imported streams for diff\n");
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!save(streams, importedPcapFile.fileName(), error))
|
|
||||||
{
|
|
||||||
error.append("Error saving imported streams as PCAP for diff");
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert imported file to text ...
|
|
||||||
if (!importedTextFile.open())
|
|
||||||
{
|
|
||||||
error.append("Unable to open temporary file to create text file "
|
|
||||||
"(imported) for diff\n");
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
qDebug("generating text file (imported) %s",
|
|
||||||
qPrintable(importedTextFile.fileName()));
|
|
||||||
|
|
||||||
emit status("Preparing imported PCAP for diff...");
|
|
||||||
emit target(0);
|
|
||||||
|
|
||||||
tshark.setStandardOutputProcess(&awk);
|
|
||||||
awk.setStandardOutputFile(importedTextFile.fileName());
|
|
||||||
tshark.start(OstProtoLib::tsharkPath(),
|
|
||||||
QStringList()
|
|
||||||
<< QString("-r%1").arg(importedPcapFile.fileName())
|
|
||||||
<< "-otcp.desegment_tcp_streams:FALSE"
|
|
||||||
<< "-P"
|
|
||||||
<< "-x");
|
|
||||||
if (!tshark.waitForStarted(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Unable to start tshark. Check path in Preferences.\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
awk.start(OstProtoLib::awkPath(),
|
|
||||||
QStringList() << kAwkFilter);
|
|
||||||
if (!awk.waitForStarted(-1))
|
|
||||||
{
|
|
||||||
tshark.kill();
|
|
||||||
error.append(QString("Unable to start awk. Check path in Preferences.\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tshark.waitForFinished(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Error running tshark\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
if (!awk.waitForFinished(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Error running awk\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now do the diff of the two text files ...
|
|
||||||
if (!diffFile.open())
|
|
||||||
{
|
|
||||||
error.append("Unable to open temporary file to store diff\n");
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
qDebug("diffing %s and %s > %s",
|
|
||||||
qPrintable(originalTextFile.fileName()),
|
|
||||||
qPrintable(importedTextFile.fileName()),
|
|
||||||
qPrintable(diffFile.fileName()));
|
|
||||||
|
|
||||||
emit status("Taking diff...");
|
|
||||||
emit target(0);
|
|
||||||
|
|
||||||
diff.setStandardOutputFile(diffFile.fileName());
|
|
||||||
diff.start(OstProtoLib::diffPath(),
|
|
||||||
QStringList()
|
|
||||||
<< "-u"
|
|
||||||
<< "-F^ [1-9]"
|
|
||||||
<< QString("--label=%1 (actual)")
|
|
||||||
.arg(QFileInfo(fileName).fileName())
|
|
||||||
<< QString("--label=%1 (imported)")
|
|
||||||
.arg(QFileInfo(fileName).fileName())
|
|
||||||
<< originalTextFile.fileName()
|
|
||||||
<< importedTextFile.fileName());
|
|
||||||
if (!diff.waitForStarted(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Unable to start diff. Check path in Preferences.\n")
|
|
||||||
.arg(diff.exitCode()));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!diff.waitForFinished(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Error running diff\n"));
|
|
||||||
goto _diff_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
diffFile.close();
|
|
||||||
if (diffFile.size())
|
|
||||||
{
|
|
||||||
error.append(tr("<p>There is a diff between the original and imported streams. See details to review the diff.</p><p>Why a diff? See <a href='%1'>possible reasons</a>.</p>\n\n\n\n").arg("https://jump.ostinato.org/pcapdiff"));
|
|
||||||
diffFile.open();
|
|
||||||
diffFile.seek(0);
|
|
||||||
error.append(QString(diffFile.readAll()));
|
|
||||||
}
|
|
||||||
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
_non_pdml:
|
|
||||||
qDebug("pcap resolution: %s", nsecResolution ? "nsec" : "usec");
|
|
||||||
emit status("Reading Packets...");
|
|
||||||
emit target(100); // in percentage
|
|
||||||
pktCount = 1;
|
|
||||||
while (!fd_.atEnd())
|
|
||||||
{
|
|
||||||
OstProto::Stream *stream = streams.add_stream();
|
|
||||||
OstProto::Protocol *proto = stream->add_protocol();
|
|
||||||
OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump);
|
|
||||||
|
|
||||||
proto->mutable_protocol_id()->set_id(
|
|
||||||
OstProto::Protocol::kHexDumpFieldNumber);
|
|
||||||
|
|
||||||
readPacket(pktHdr, pktBuf);
|
|
||||||
|
|
||||||
// validations on inclLen <= origLen && inclLen <= snapLen
|
|
||||||
Q_ASSERT(pktHdr.inclLen <= fileHdr.snapLen); // TODO: convert to if
|
|
||||||
|
|
||||||
hexDump->set_content(pktBuf.data(), pktHdr.inclLen);
|
|
||||||
hexDump->set_pad_until_end(false);
|
|
||||||
|
|
||||||
stream->mutable_stream_id()->set_id(pktCount);
|
|
||||||
stream->mutable_core()->set_is_enabled(true);
|
|
||||||
stream->mutable_core()->set_frame_len(pktHdr.inclLen+4); // FCS
|
|
||||||
|
|
||||||
stream->mutable_control()->set_num_packets(1);
|
|
||||||
|
|
||||||
// setup packet rate to the timing in pcap (as close as possible)
|
|
||||||
// use quint64 rather than double to store micro/nano second as
|
|
||||||
// it has a larger range (~580 years) and therefore better accuracy
|
|
||||||
const quint64 kXsecsInSec = nsecResolution ? 1e9 : 1e6;
|
|
||||||
quint64 xsec = (pktHdr.tsSec*kXsecsInSec + pktHdr.tsUsec);
|
|
||||||
quint64 delta = xsec - lastXsec;
|
|
||||||
qDebug("pktCount = %d, delta = %llu", pktCount, delta);
|
|
||||||
|
|
||||||
if ((pktCount != 1) && delta)
|
|
||||||
stream->mutable_control()->set_packets_per_sec(double(kXsecsInSec)/delta);
|
|
||||||
|
|
||||||
if (prevStream)
|
|
||||||
prevStream->mutable_control()->CopyFrom(stream->control());
|
|
||||||
|
|
||||||
lastXsec = xsec;
|
|
||||||
prevStream = stream;
|
|
||||||
pktCount++;
|
|
||||||
byteCount += pktHdr.inclLen + sizeof(pktHdr);
|
|
||||||
emit progress(int(byteCount*100/byteTotal)); // in percentage
|
|
||||||
if (stop_)
|
|
||||||
goto _user_cancel;
|
|
||||||
}
|
|
||||||
|
|
||||||
isOk = true;
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_user_cancel:
|
|
||||||
isOk = true;
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_diff_fail:
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_err_unsupported_encap:
|
|
||||||
error = QString(tr("%1 has non-ethernet encapsulation (%2) which is "
|
|
||||||
"not supported - Sorry!"))
|
|
||||||
.arg(QFileInfo(fileName).fileName()).arg(fileHdr.network);
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_err_unsupported_version:
|
|
||||||
error = QString(tr("%1 is in PCAP version %2.%3 format which is "
|
|
||||||
"not supported - Sorry!"))
|
|
||||||
.arg(fileName).arg(fileHdr.versionMajor).arg(fileHdr.versionMinor);
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_err_bad_magic:
|
|
||||||
error = QString(tr("%1 is not a valid PCAP file")).arg(fileName);
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
_err_truncated:
|
|
||||||
error = QString(tr("%1 is too short")).arg(fileName);
|
|
||||||
goto _exit;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_err_unzip_fail:
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_err_reading_magic:
|
|
||||||
error = QString(tr("Unable to read magic from %1")).arg(fileName);
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_err_convert2pcap:
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_err_open:
|
|
||||||
error = QString(tr("Unable to open file: %1")).arg(fileName);
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_exit:
|
|
||||||
if (!error.isEmpty())
|
|
||||||
qDebug("%s", qPrintable(error));
|
|
||||||
file.close();
|
|
||||||
return isOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Converts a non-PCAP capture file to standard PCAP file format using tshark
|
|
||||||
|
|
||||||
Returns true if conversion was successful, false otherwise.
|
|
||||||
*/
|
|
||||||
bool PcapFileFormat::convertToStandardPcap(
|
|
||||||
QString fileName, QString outputFileName, QString &error)
|
|
||||||
{
|
|
||||||
qDebug("converting to PCAP %s", qPrintable(outputFileName));
|
|
||||||
emit status("Unsupported format. Converting to standard PCAP format...");
|
|
||||||
emit target(0);
|
|
||||||
|
|
||||||
QProcess tshark;
|
|
||||||
tshark.start(OstProtoLib::tsharkPath(),
|
|
||||||
QStringList()
|
|
||||||
<< QString("-r%1").arg(fileName)
|
|
||||||
<< "-Fnsecpcap"
|
|
||||||
<< QString("-w%1").arg(outputFileName));
|
|
||||||
if (!tshark.waitForStarted(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Unable to start tshark. Check path in preferences.\n"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tshark.waitForFinished(-1))
|
|
||||||
{
|
|
||||||
error.append(QString("Error running tshark\n"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Reads packet meta data into pktHdr and packet content into buf.
|
|
||||||
|
|
||||||
Returns true if packet is read successfully, false otherwise.
|
|
||||||
*/
|
|
||||||
bool PcapFileFormat::readPacket(PcapPacketHeader &pktHdr, QByteArray &pktBuf)
|
|
||||||
{
|
|
||||||
quint32 len;
|
|
||||||
|
|
||||||
// TODO: chk fd_.status()
|
|
||||||
|
|
||||||
// read PcapPacketHeader
|
|
||||||
fd_ >> pktHdr.tsSec;
|
|
||||||
fd_ >> pktHdr.tsUsec;
|
|
||||||
fd_ >> pktHdr.inclLen;
|
|
||||||
fd_ >> pktHdr.origLen;
|
|
||||||
|
|
||||||
// TODO: chk fd_.status()
|
|
||||||
|
|
||||||
// XXX: should never be required, but we play safe
|
|
||||||
if (quint32(pktBuf.size()) < pktHdr.inclLen)
|
|
||||||
pktBuf.resize(pktHdr.inclLen);
|
|
||||||
|
|
||||||
// read Pkt contents
|
|
||||||
len = fd_.readRawData(pktBuf.data(), pktHdr.inclLen); // TODO: use while?
|
|
||||||
|
|
||||||
Q_ASSERT(len == pktHdr.inclLen); // TODO: remove assert
|
|
||||||
pktBuf.resize(len);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PcapFileFormat::save(const OstProto::StreamConfigList streams,
|
|
||||||
const QString fileName, QString &error)
|
|
||||||
{
|
|
||||||
bool isOk = false;
|
|
||||||
QFile file(fileName);
|
|
||||||
PcapFileHeader fileHdr;
|
|
||||||
PcapPacketHeader pktHdr;
|
|
||||||
QByteArray pktBuf;
|
|
||||||
|
|
||||||
if (!file.open(QIODevice::WriteOnly))
|
|
||||||
goto _err_open;
|
|
||||||
|
|
||||||
fd_.setDevice(&file);
|
|
||||||
|
|
||||||
fileHdr.magicNumber = kNanoSecondPcapFileMagic;
|
|
||||||
fileHdr.versionMajor = kPcapFileVersionMajor;
|
|
||||||
fileHdr.versionMinor = kPcapFileVersionMinor;
|
|
||||||
fileHdr.thisZone = 0;
|
|
||||||
fileHdr.sigfigs = 0;
|
|
||||||
fileHdr.snapLen = kMaxSnapLen;
|
|
||||||
fileHdr.network = kDltEthernet;
|
|
||||||
|
|
||||||
fd_ << fileHdr.magicNumber;
|
|
||||||
fd_ << fileHdr.versionMajor;
|
|
||||||
fd_ << fileHdr.versionMinor;
|
|
||||||
fd_ << fileHdr.thisZone;
|
|
||||||
fd_ << fileHdr.sigfigs;
|
|
||||||
fd_ << fileHdr.snapLen;
|
|
||||||
fd_ << fileHdr.network;
|
|
||||||
|
|
||||||
pktBuf.resize(kMaxSnapLen);
|
|
||||||
|
|
||||||
emit status("Writing Packets...");
|
|
||||||
emit target(streams.stream_size());
|
|
||||||
|
|
||||||
pktHdr.tsSec = 0;
|
|
||||||
pktHdr.tsUsec = 0;
|
|
||||||
for (int i = 0; i < streams.stream_size(); i++)
|
|
||||||
{
|
|
||||||
StreamBase s;
|
|
||||||
|
|
||||||
s.setId(i);
|
|
||||||
s.protoDataCopyFrom(streams.stream(i));
|
|
||||||
// TODO: expand frameIndex for each stream
|
|
||||||
s.frameValue((uchar*)pktBuf.data(), pktBuf.size(), 0);
|
|
||||||
|
|
||||||
pktHdr.inclLen = s.frameProtocolLength(0); // FIXME: stream index = 0
|
|
||||||
pktHdr.origLen = s.frameLen() - 4; // FCS; FIXME: Hardcoding
|
|
||||||
|
|
||||||
qDebug("savepcap i=%d, incl/orig len = %d/%d", i,
|
|
||||||
pktHdr.inclLen, pktHdr.origLen);
|
|
||||||
|
|
||||||
if (pktHdr.inclLen > fileHdr.snapLen)
|
|
||||||
pktHdr.inclLen = fileHdr.snapLen;
|
|
||||||
|
|
||||||
fd_ << pktHdr.tsSec;
|
|
||||||
fd_ << pktHdr.tsUsec;
|
|
||||||
fd_ << pktHdr.inclLen;
|
|
||||||
fd_ << pktHdr.origLen;
|
|
||||||
fd_.writeRawData(pktBuf.data(), pktHdr.inclLen);
|
|
||||||
|
|
||||||
if (s.packetRate())
|
|
||||||
{
|
|
||||||
quint64 delta = quint64(1e9/s.packetRate());
|
|
||||||
pktHdr.tsSec += delta/quint32(1e9);
|
|
||||||
pktHdr.tsUsec += delta % quint32(1e9);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pktHdr.tsUsec >= quint32(1e9))
|
|
||||||
{
|
|
||||||
pktHdr.tsSec++;
|
|
||||||
pktHdr.tsUsec -= quint32(1e9);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit progress(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
isOk = true;
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_err_open:
|
|
||||||
error = QString(tr("Unable to open file: %1")).arg(fileName);
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
_exit:
|
|
||||||
return isOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDialog* PcapFileFormat::openOptionsDialog()
|
|
||||||
{
|
|
||||||
return new PcapImportOptionsDialog(&importOptions_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PcapFileFormat::isMyFileFormat(const QString /*fileName*/)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PcapFileFormat::isMyFileType(const QString fileType)
|
|
||||||
{
|
|
||||||
if (fileType.startsWith("PCAP"))
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
@ -16,13 +16,11 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
#ifndef _PCAP_FILE_FORMAT_H
|
#ifndef _PCAP_FILE_FORMAT_OPTIONS_H
|
||||||
#define _PCAP_FILE_FORMAT_H
|
#define _PCAP_FILE_FORMAT_OPTIONS_H
|
||||||
|
|
||||||
#include "streamfileformat.h"
|
|
||||||
#include "ui_pcapfileimport.h"
|
#include "ui_pcapfileimport.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
|
||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
|
|
||||||
class PcapImportOptionsDialog: public QDialog, public Ui::PcapFileImport
|
class PcapImportOptionsDialog: public QDialog, public Ui::PcapFileImport
|
||||||
@ -38,51 +36,4 @@ private:
|
|||||||
QVariantMap *options_;
|
QVariantMap *options_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PdmlReader;
|
|
||||||
class PcapFileFormat : public StreamFileFormat
|
|
||||||
{
|
|
||||||
friend class PdmlReader;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PcapFileFormat();
|
|
||||||
~PcapFileFormat();
|
|
||||||
|
|
||||||
bool open(const QString fileName,
|
|
||||||
OstProto::StreamConfigList &streams, QString &error);
|
|
||||||
bool save(const OstProto::StreamConfigList streams,
|
|
||||||
const QString fileName, QString &error);
|
|
||||||
|
|
||||||
virtual QDialog* openOptionsDialog();
|
|
||||||
|
|
||||||
bool isMyFileFormat(const QString fileName);
|
|
||||||
bool isMyFileType(const QString fileType);
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef struct {
|
|
||||||
quint32 magicNumber; /* magic number */
|
|
||||||
quint16 versionMajor; /* major version number */
|
|
||||||
quint16 versionMinor; /* minor version number */
|
|
||||||
qint32 thisZone; /* GMT to local correction */
|
|
||||||
quint32 sigfigs; /* accuracy of timestamps */
|
|
||||||
quint32 snapLen; /* max length of captured packets, in octets */
|
|
||||||
quint32 network; /* data link type */
|
|
||||||
} PcapFileHeader;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
quint32 tsSec; /* timestamp seconds */
|
|
||||||
quint32 tsUsec; /* timestamp microseconds */
|
|
||||||
quint32 inclLen; /* number of octets of packet saved in file */
|
|
||||||
quint32 origLen; /* actual length of packet */
|
|
||||||
} PcapPacketHeader;
|
|
||||||
|
|
||||||
bool convertToStandardPcap(QString fileName, QString outputFileName,
|
|
||||||
QString &error);
|
|
||||||
bool readPacket(PcapPacketHeader &pktHdr, QByteArray &pktBuf);
|
|
||||||
|
|
||||||
QDataStream fd_;
|
|
||||||
QVariantMap importOptions_;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern PcapFileFormat pcapFileFormat;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user