diff --git a/.hgignore b/.hgignore index cd5490f..c268bf1 100644 --- a/.hgignore +++ b/.hgignore @@ -31,3 +31,5 @@ version.cpp # ctags tags + +pcaps\* diff --git a/client/port.cpp b/client/port.cpp index c1e402c..e3c873b 100644 --- a/client/port.cpp +++ b/client/port.cpp @@ -20,7 +20,7 @@ along with this program. If not, see #include "port.h" #include "fileformat.h" -#include "pdmlfileformat.h" +#include "pcapfileformat.h" #include #include @@ -229,7 +229,7 @@ bool Port::openStreams(QString fileName, bool append, QString &error) OstProto::StreamConfigList streams; //if (!fileFormat.openStreams(fileName, streams, error)) - if (!pdmlFileFormat.openStreams(fileName, streams, error)) + if (!pcapFileFormat.openStreams(fileName, streams, error)) goto _fail; if (!append) @@ -262,5 +262,6 @@ bool Port::saveStreams(QString fileName, QString &error) mStreams[i]->protoDataCopyInto(*s); } - return fileFormat.saveStreams(streams, fileName, error); + //return fileFormat.saveStreams(streams, fileName, error); + return pcapFileFormat.saveStreams(streams, fileName, error); } diff --git a/common/ostproto.pro b/common/ostproto.pro index 26aefae..ef829da 100644 --- a/common/ostproto.pro +++ b/common/ostproto.pro @@ -58,6 +58,7 @@ HEADERS += \ abstractprotocol.h \ comboprotocol.h \ fileformat.h \ + pcapfileformat.h \ pdmlfileformat.h \ pdml_p.h \ protocolmanager.h \ @@ -98,6 +99,7 @@ SOURCES += \ abstractprotocol.cpp \ crc32c.cpp \ fileformat.cpp \ + pcapfileformat.cpp \ pdmlfileformat.cpp \ pdml_p.cpp \ protocolmanager.cpp \ diff --git a/common/pcapfileformat.cpp b/common/pcapfileformat.cpp new file mode 100644 index 0000000..3ef8c76 --- /dev/null +++ b/common/pcapfileformat.cpp @@ -0,0 +1,252 @@ +/* +Copyright (C) 2010 Srivats P. + +This file is part of "Ostinato" + +This 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 3 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, see +*/ + +#include "pcapfileformat.h" +#include "streambase.h" +#include "hexdump.pb.h" + +#include +#include +#include + +static inline quint32 swap32(quint32 val) +{ + return (((val >> 24) && 0x000000FF) | + ((val >> 16) && 0x0000FF00) | + ((val << 16) && 0x00FF0000) | + ((val << 24) && 0xFF000000)); +} + +static inline quint16 swap16(quint16 val) +{ + return (((val >> 8) && 0x00FF) | + ((val << 8) && 0xFF00)); +} + +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; + +const quint32 kPcapFileMagic = 0xa1b2c3d4; +const quint32 kPcapFileMagicSwapped = 0xd4c3b2a1; +const quint16 kPcapFileVersionMajor = 2; +const quint16 kPcapFileVersionMinor = 4; +const quint32 kMaxSnapLen = 65535; + +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; + +PcapFileFormat pcapFileFormat; + +PcapFileFormat::PcapFileFormat() +{ +} + +PcapFileFormat::~PcapFileFormat() +{ +} + +bool PcapFileFormat::openStreams(const QString fileName, + OstProto::StreamConfigList &streams, QString &error) +{ + bool isOk = false; + QFile file(fileName); + QDataStream fd; + quint32 magic; + PcapFileHeader fileHdr; + PcapPacketHeader pktHdr; + quint32 len; + int pktCount = 1; + QByteArray pktBuf; + + if (!file.open(QIODevice::ReadOnly)) + goto _err_open; + + if (file.size() < sizeof(fileHdr)) + goto _err_truncated; + + fd.setDevice(&file); + + fd >> magic; + + + if (magic == kPcapFileMagicSwapped) + { + // Toggle Byte order + if (fd.byteOrder() == QDataStream::BigEndian) + fd.setByteOrder(QDataStream::LittleEndian); + else + fd.setByteOrder(QDataStream::BigEndian); + } + else if (magic != kPcapFileMagic) + goto _err_bad_magic; + + fd >> fileHdr.versionMajor; + fd >> fileHdr.versionMinor; + fd >> fileHdr.thisZone; + fd >> fileHdr.sigfigs; + fd >> fileHdr.snapLen; + fd >> fileHdr.network; + + if ((fileHdr.versionMajor != kPcapFileVersionMajor) || + (fileHdr.versionMinor != kPcapFileVersionMinor)) + goto _err_unsupported_version; + + // TODO: what do we do about non-ethernet networks? + + pktBuf.resize(fileHdr.snapLen); + + while (!fd.atEnd()) + { + OstProto::Stream *stream = streams.add_stream(); + OstProto::Protocol *proto = stream->add_protocol(); + OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump); + + stream->mutable_stream_id()->set_id(pktCount); + stream->mutable_core()->set_is_enabled(true); + proto->mutable_protocol_id()->set_id( + OstProto::Protocol::kHexDumpFieldNumber); + + // read PcapPacketHeader + fd >> pktHdr.tsSec; + fd >> pktHdr.tsUsec; + fd >> pktHdr.inclLen; + fd >> pktHdr.origLen; + + // TODO: chk fd.status() + + // validations on inclLen <= origLen && inclLen <= snapLen + Q_ASSERT(pktHdr.inclLen <= fileHdr.snapLen); // TODO: convert to if + + // read Pkt contents + len = fd.readRawData(pktBuf.data(), pktHdr.inclLen); // TODO: use while? + Q_ASSERT(len == pktHdr.inclLen); // TODO: remove assert + + hexDump->set_content(pktBuf.data(), pktHdr.inclLen); + hexDump->set_pad_until_end(false); + + stream->mutable_core()->set_frame_len(pktHdr.inclLen+4); // FCS + + pktCount++; + } + + isOk = true; + 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; + +_err_truncated: + error = QString(tr("%1 is too short")).arg(fileName); + goto _exit; + +_err_open: + error = QString(tr("Unable to open file: %1")).arg(fileName); + goto _exit; + +_exit: + return isOk; +} + +bool PcapFileFormat::saveStreams(const OstProto::StreamConfigList streams, + const QString fileName, QString &error) +{ + bool isOk = false; + QFile file(fileName); + QDataStream fd; + PcapFileHeader fileHdr; + PcapPacketHeader pktHdr; + QByteArray pktBuf; + + if (!file.open(QIODevice::WriteOnly)) + goto _err_open; + + fd.setDevice(&file); + + fileHdr.magicNumber = kPcapFileMagic; + fileHdr.versionMajor = kPcapFileVersionMajor; + fileHdr.versionMinor = kPcapFileVersionMinor; + fileHdr.thisZone = 0; + fileHdr.sigfigs = 0; + fileHdr.snapLen = kMaxSnapLen; + fileHdr.network = 1; // Ethernet; FIXME: Hardcoding + + fd << fileHdr.magicNumber; + fd << fileHdr.versionMajor; + fd << fileHdr.versionMinor; + fd << fileHdr.thisZone; + fd << fileHdr.sigfigs; + fd << fileHdr.snapLen; + fd << fileHdr.network; + + pktBuf.resize(kMaxSnapLen); + + 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); + + // TODO: write actual timing!?!? + pktHdr.tsSec = 0; + pktHdr.tsUsec = 0; + pktHdr.inclLen = pktHdr.origLen = s.frameLen() - 4; // FCS; FIXME: Hardcoding + 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); + } + + file.close(); + + isOk = true; + goto _exit; + +_err_open: + error = QString(tr("Unable to open file: %1")).arg(fileName); + goto _exit; + +_exit: + return isOk; +} + diff --git a/common/pcapfileformat.h b/common/pcapfileformat.h new file mode 100644 index 0000000..a515e32 --- /dev/null +++ b/common/pcapfileformat.h @@ -0,0 +1,42 @@ +/* +Copyright (C) 2010 Srivats P. + +This file is part of "Ostinato" + +This 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 3 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, see +*/ +#ifndef _PCAP_FILE_FORMAT_H +#define _PCAP_FILE_FORMAT_H + +#include "protocol.pb.h" + +#include + +class PcapFileFormat : public QObject +{ + Q_OBJECT + +public: + PcapFileFormat(); + ~PcapFileFormat(); + + bool openStreams(const QString fileName, + OstProto::StreamConfigList &streams, QString &error); + bool saveStreams(const OstProto::StreamConfigList streams, + const QString fileName, QString &error); +}; + +extern PcapFileFormat pcapFileFormat; + +#endif diff --git a/common/pdml_p.cpp b/common/pdml_p.cpp index e887f33..fbc4a0e 100644 --- a/common/pdml_p.cpp +++ b/common/pdml_p.cpp @@ -43,6 +43,11 @@ PdmlDefaultProtocol::~PdmlDefaultProtocol() { } +PdmlDefaultProtocol* PdmlDefaultProtocol::createInstance() +{ + return new PdmlDefaultProtocol(); +} + QString PdmlDefaultProtocol::pdmlProtoName() const { return pdmlProtoName_; @@ -64,7 +69,12 @@ int PdmlDefaultProtocol::fieldId(QString name) const } void PdmlDefaultProtocol::preProtocolHandler(QString name, - const QXmlAttributes &attributes, OstProto::Stream *stream) + const QXmlStreamAttributes &attributes, OstProto::Stream *stream) +{ + return; // do nothing! +} + +void PdmlDefaultProtocol::prematureEndHandler(int pos, OstProto::Stream *stream) { return; // do nothing! } @@ -75,13 +85,14 @@ void PdmlDefaultProtocol::postProtocolHandler(OstProto::Stream *stream) } void PdmlDefaultProtocol::unknownFieldHandler(QString name, - int pos, int size, const QXmlAttributes &attributes, + int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { return; // do nothing! } +#if 0 // ---------------------------------------------------------- // // PdmlParser // ---------------------------------------------------------- // @@ -328,6 +339,392 @@ bool PdmlParser::fatalError(const QXmlParseException &exception) .arg(extra)); return false; } +#endif + +// ---------------------------------------------------------- // +// PdmlReader // +// ---------------------------------------------------------- // +PdmlReader::PdmlReader(OstProto::StreamConfigList *streams) +{ + streams_ = streams; + + factory_.insert("hexdump", PdmlUnknownProtocol::createInstance); + factory_.insert("geninfo", PdmlGenInfoProtocol::createInstance); + factory_.insert("frame", PdmlFrameProtocol::createInstance); +#if 0 + factory_.insert("fake-field-wrapper", + new PdmlFakeFieldWrapperProtocol()); +#endif + factory_.insert("eth",PdmlEthProtocol::createInstance); + factory_.insert("ip",PdmlIp4Protocol::createInstance); + factory_.insert("ipv6",PdmlIp6Protocol::createInstance); + factory_.insert("tcp",PdmlTcpProtocol::createInstance); +} + +PdmlReader::~PdmlReader() +{ +} + +bool PdmlReader::read(QIODevice *device) +{ + setDevice(device); + packetCount_ = 0; + + while (!atEnd()) + { + readNext(); + if (isStartElement()) + { + if (name() == "pdml") + readPdml(); + else + raiseError("Not a pdml file!"); + } + } + + return !error(); +} + +// TODO: use a temp pool to avoid a lot of new/delete +PdmlDefaultProtocol* PdmlReader::allocPdmlProtocol(QString protoName) +{ + if (!factory_.contains(protoName)) + protoName = "hexdump"; + + return (*(factory_.value(protoName)))(); +} + +void PdmlReader::freePdmlProtocol(PdmlDefaultProtocol *proto) +{ + delete proto; +} + +bool PdmlReader::isDontCareProto() +{ + Q_ASSERT(isStartElement() && name() == "proto"); + + QString protoName = attributes().value("name").toString(); + + if (protoName.isEmpty() || (protoName == "expert")) + return true; + else + return false; +} + +void PdmlReader::readUnexpectedElement() +{ + Q_ASSERT(isStartElement()); + + // XXX: add to 'log' + qDebug("unexpected element - <%s>; skipping ...", + name().toString().toAscii().constData()); + while (!atEnd()) + { + readNext(); + if (isEndElement()) + break; + + if (isStartElement()) + readUnexpectedElement(); + } +} + +void PdmlReader::skipElement() +{ + Q_ASSERT(isStartElement()); + + // XXX: add to 'log' + qDebug("skipping element - <%s>", + name().toString().toAscii().constData()); + while (!atEnd()) + { + readNext(); + if (isEndElement()) + break; + + if (isStartElement()) + skipElement(); + } +} + +void PdmlReader::readPdml() +{ + Q_ASSERT(isStartElement() && name() == "pdml"); + + packetCount_ = 0; + + while (!atEnd()) + { + readNext(); + if (isEndElement()) + break; + + if (isStartElement()) + { + if (name() == "packet") + readPacket(); + else + readUnexpectedElement(); + } + } +} + +void PdmlReader::readPacket() +{ + Q_ASSERT(isStartElement() && name() == "packet"); + + packetCount_++; + qDebug("packetNum = %d", packetCount_); + + // XXX: For now, each packet is converted to a stream + currentStream_ = streams_->add_stream(); + currentStream_->mutable_stream_id()->set_id(packetCount_); + currentStream_->mutable_core()->set_is_enabled(true); + + while (!atEnd()) + { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + { + if (name() == "proto") + readProto(); + else if (name() == "field") + readField(NULL, NULL); // TODO: top level field!!!! + else + readUnexpectedElement(); + } + } + + if (currentStream_->core().name().size()) + { + OstProto::Protocol *proto = currentStream_->add_protocol(); + + proto->mutable_protocol_id()->set_id( + OstProto::Protocol::kHexDumpFieldNumber); + + OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump); + + hexDump->set_content(currentStream_->core().name()); + hexDump->set_pad_until_end(false); + currentStream_->mutable_core()->set_name(""); + } +} + + +void PdmlReader::readProto() +{ + PdmlDefaultProtocol *pdmlProto = NULL; + google::protobuf::Message *pbProto = NULL; + + Q_ASSERT(isStartElement() && name() == "proto"); + + QString protoName = attributes().value("name").toString(); + qDebug("proto: %s", protoName.toAscii().constData()); + +#if 0 + if (protoName.isEmpty() || (protoName == "expert")) + { + skipElement(); + return; + } +#endif + + pdmlProto = allocPdmlProtocol(protoName); + Q_ASSERT(pdmlProto != NULL); + + int protoId = pdmlProto->ostProtoId(); + + // Non PdmlDefaultProtocol + if (protoId > 0) + { + OstProto::Protocol *proto = currentStream_->add_protocol(); + + proto->mutable_protocol_id()->set_id(protoId); + + const google::protobuf::Reflection *msgRefl = proto->GetReflection(); + const google::protobuf::FieldDescriptor *fieldDesc = + msgRefl->FindKnownExtensionByNumber(protoId); + + // TODO: if !fDesc + // init default values of all fields in protocol + pbProto = msgRefl->MutableMessage(proto, fieldDesc); + + } + + pdmlProto->preProtocolHandler(protoName, attributes(), currentStream_); + + while (!atEnd()) + { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + { + if (name() == "proto") + { + int endPos = -1; + // an embedded proto + qDebug("embedded proto: %s\n", attributes().value("name") + .toString().toAscii().constData()); + if (isDontCareProto()) + { + skipElement(); + continue; + } + + if (!attributes().value("pos").isEmpty()) + endPos = attributes().value("pos").toString().toInt(); + + + // pdmlProto may be NULL for a sequence of embedded protos + if (pdmlProto) + { + pdmlProto->prematureEndHandler(endPos, currentStream_); + pdmlProto->postProtocolHandler(currentStream_); + } + readProto(); + pdmlProto = NULL; + pbProto = NULL; + } + else if (name() == "field") + { + if (pdmlProto == NULL) + { + pdmlProto = allocPdmlProtocol(protoName); + protoId = pdmlProto->ostProtoId(); + + // Non PdmlDefaultProtocol + if (protoId > 0) + { + OstProto::Protocol *proto = currentStream_->add_protocol(); + + proto->mutable_protocol_id()->set_id(protoId); + + const google::protobuf::Reflection *msgRefl = proto->GetReflection(); + const google::protobuf::FieldDescriptor *fieldDesc = + msgRefl->FindKnownExtensionByNumber(protoId); + + // TODO: if !fDesc + // init default values of all fields in protocol + pbProto = msgRefl->MutableMessage(proto, fieldDesc); + + } + pdmlProto->preProtocolHandler(protoName, attributes(), currentStream_); + } + readField(pdmlProto, pbProto); + } + else + readUnexpectedElement(); + } + } + + if (pdmlProto) + { + pdmlProto->postProtocolHandler(currentStream_); + freePdmlProtocol(pdmlProto); + } +} + +void PdmlReader::readField(PdmlDefaultProtocol *pdmlProto, + google::protobuf::Message *pbProto) +{ + Q_ASSERT(isStartElement() && name() == "field"); + + // fields with "hide='yes'" are informational and should be skipped + if (attributes().value("hide") == "yes") + { + skipElement(); + return; + } + + QString fieldName = attributes().value("name").toString(); + QString valueHexStr = attributes().value("value").toString(); + int pos = -1; + int size = -1; + + if (!attributes().value("pos").isEmpty()) + pos = attributes().value("pos").toString().toInt(); + if (!attributes().value("size").isEmpty()) + size = attributes().value("size").toString().toInt(); + + qDebug("\tfieldName:%s, pos:%d, size:%d value:%s", + fieldName.toAscii().constData(), + pos, + size, + valueHexStr.toAscii().constData()); + + if (pdmlProto->hasField(fieldName)) + { + int fieldId = pdmlProto->fieldId(fieldName); + const google::protobuf::Descriptor *msgDesc = + pbProto->GetDescriptor(); + const google::protobuf::FieldDescriptor *fieldDesc = + msgDesc->FindFieldByNumber(fieldId); + const google::protobuf::Reflection *msgRefl = + pbProto->GetReflection(); + + bool isOk; + + switch(fieldDesc->cpp_type()) + { + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: // TODO + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + msgRefl->SetUInt32(pbProto, fieldDesc, + valueHexStr.toUInt(&isOk, kBaseHex)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + msgRefl->SetUInt64(pbProto, fieldDesc, + valueHexStr.toULongLong(&isOk, kBaseHex)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + { + QByteArray hexVal = QByteArray::fromHex(valueHexStr.toUtf8()); + std::string str(hexVal.constData(), hexVal.size()); + msgRefl->SetString(pbProto, fieldDesc, str); + break; + } + default: + qDebug("%s: unhandled cpptype = %d", __FUNCTION__, + fieldDesc->cpp_type()); + } + } + else + { + pdmlProto->unknownFieldHandler(fieldName, pos, size, attributes(), + currentStream_); + } + + while (!atEnd()) + { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + { + if (name() == "proto") + { + if (isDontCareProto()) + { + skipElement(); + continue; + } + readProto(); + } + else if (name() == "field") + readField(pdmlProto, pbProto); + else + readUnexpectedElement(); + } + } +} // ---------------------------------------------------------- // @@ -336,22 +733,27 @@ bool PdmlParser::fatalError(const QXmlParseException &exception) PdmlUnknownProtocol::PdmlUnknownProtocol() { - pdmlProtoName_ = "OST:HexDump"; + pdmlProtoName_ = ""; ostProtoId_ = OstProto::Protocol::kHexDumpFieldNumber; endPos_ = expPos_ = -1; } +PdmlDefaultProtocol* PdmlUnknownProtocol::createInstance() +{ + return new PdmlUnknownProtocol(); +} + void PdmlUnknownProtocol::preProtocolHandler(QString name, - const QXmlAttributes &attributes, OstProto::Stream *stream) + const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { bool isOk; int size; - int pos = attributes.value("pos").toUInt(&isOk); + int pos = attributes.value("pos").toString().toUInt(&isOk); if (!isOk) goto _skip_pos_size_proc; - size = attributes.value("size").toUInt(&isOk); + size = attributes.value("size").toString().toUInt(&isOk); if (!isOk) goto _skip_pos_size_proc; @@ -364,6 +766,11 @@ _skip_pos_size_proc: hexDump->set_pad_until_end(false); } +void PdmlUnknownProtocol::prematureEndHandler(int pos, OstProto::Stream *stream) +{ + endPos_ = pos; +} + void PdmlUnknownProtocol::postProtocolHandler(OstProto::Stream *stream) { OstProto::HexDump *hexDump = stream->mutable_protocol( @@ -378,7 +785,7 @@ void PdmlUnknownProtocol::postProtocolHandler(OstProto::Stream *stream) expPos_ += hexVal.size(); } - qDebug("%s: expPos_ = %d, endPos_ = %d\n", __FUNCTION__, expPos_, endPos_); + qDebug(" hexdump: expPos_ = %d, endPos_ = %d\n", expPos_, endPos_); //Q_ASSERT(expPos_ == endPos_); hexDump->set_pad_until_end(false); @@ -386,13 +793,13 @@ void PdmlUnknownProtocol::postProtocolHandler(OstProto::Stream *stream) } void PdmlUnknownProtocol::unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream) + const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { OstProto::HexDump *hexDump = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::hexDump); - qDebug("%s: %s, pos = %d, expPos_ = %d, endPos_ = %d\n", - __PRETTY_FUNCTION__, name.toAscii().constData(), + qDebug(" hexdump: %s, pos = %d, expPos_ = %d, endPos_ = %d\n", + name.toAscii().constData(), pos, expPos_, endPos_); // Skipped field? Pad with zero! @@ -407,8 +814,8 @@ void PdmlUnknownProtocol::unknownFieldHandler(QString name, int pos, int size, if ((pos == expPos_) /*&& (pos < endPos_)*/) { QByteArray hexVal = attributes.value("unmaskedvalue").isEmpty() ? - QByteArray::fromHex(attributes.value("value").toUtf8()) : - QByteArray::fromHex(attributes.value("unmaskedvalue").toUtf8()); + QByteArray::fromHex(attributes.value("value").toString().toUtf8()) : + QByteArray::fromHex(attributes.value("unmaskedvalue").toString().toUtf8()); hexDump->mutable_content()->append(hexVal.constData(), hexVal.size()); expPos_ += hexVal.size(); @@ -425,8 +832,13 @@ PdmlGenInfoProtocol::PdmlGenInfoProtocol() pdmlProtoName_ = "geninfo"; } +PdmlDefaultProtocol* PdmlGenInfoProtocol::createInstance() +{ + return new PdmlGenInfoProtocol(); +} + void PdmlGenInfoProtocol::unknownFieldHandler(QString name, int pos, - int size, const QXmlAttributes &attributes, OstProto::Stream *stream) + int size, const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { stream->mutable_core()->set_frame_len(size+4); // TODO:check FCS } @@ -440,6 +852,11 @@ PdmlFrameProtocol::PdmlFrameProtocol() pdmlProtoName_ = "frame"; } +PdmlDefaultProtocol* PdmlFrameProtocol::createInstance() +{ + return new PdmlFrameProtocol(); +} + #if 1 // ---------------------------------------------------------- // // PdmlFakeFieldWrapperProtocol // @@ -453,8 +870,13 @@ PdmlFakeFieldWrapperProtocol::PdmlFakeFieldWrapperProtocol() expPos_ = -1; } +PdmlDefaultProtocol* PdmlFakeFieldWrapperProtocol::createInstance() +{ + return new PdmlFakeFieldWrapperProtocol(); +} + void PdmlFakeFieldWrapperProtocol::preProtocolHandler(QString name, - const QXmlAttributes &attributes, OstProto::Stream *stream) + const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { expPos_ = 0; OstProto::HexDump *hexDump = stream->mutable_protocol( @@ -474,7 +896,7 @@ void PdmlFakeFieldWrapperProtocol::postProtocolHandler(OstProto::Stream *stream) } void PdmlFakeFieldWrapperProtocol::unknownFieldHandler(QString name, int pos, - int size, const QXmlAttributes &attributes, OstProto::Stream *stream) + int size, const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { OstProto::HexDump *hexDump = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::hexDump); @@ -484,8 +906,8 @@ void PdmlFakeFieldWrapperProtocol::unknownFieldHandler(QString name, int pos, !attributes.value("value").isEmpty())) { QByteArray hexVal = attributes.value("unmaskedvalue").isEmpty() ? - QByteArray::fromHex(attributes.value("value").toUtf8()) : - QByteArray::fromHex(attributes.value("unmaskedvalue").toUtf8()); + QByteArray::fromHex(attributes.value("value").toString().toUtf8()) : + QByteArray::fromHex(attributes.value("unmaskedvalue").toString().toUtf8()); hexDump->mutable_content()->append(hexVal.constData(), hexVal.size()); expPos_ += hexVal.size(); @@ -506,8 +928,13 @@ PdmlEthProtocol::PdmlEthProtocol() fieldMap_.insert("eth.src", OstProto::Mac::kSrcMacFieldNumber); } +PdmlDefaultProtocol* PdmlEthProtocol::createInstance() +{ + return new PdmlEthProtocol(); +} + void PdmlEthProtocol::unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream) + const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { if (name == "eth.type") { @@ -519,7 +946,7 @@ void PdmlEthProtocol::unknownFieldHandler(QString name, int pos, int size, OstProto::Eth2 *eth2 = proto->MutableExtension(OstProto::eth2); bool isOk; - eth2->set_type(attributes.value("value").toUInt(&isOk, kBaseHex)); + eth2->set_type(attributes.value("value").toString().toUInt(&isOk, kBaseHex)); eth2->set_is_override_type(true); } } @@ -547,8 +974,13 @@ PdmlIp4Protocol::PdmlIp4Protocol() fieldMap_.insert("ip.dst", 18); } +PdmlDefaultProtocol* PdmlIp4Protocol::createInstance() +{ + return new PdmlIp4Protocol(); +} + void PdmlIp4Protocol::unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream) + const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { bool isOk; @@ -557,7 +989,7 @@ void PdmlIp4Protocol::unknownFieldHandler(QString name, int pos, int size, OstProto::Ip4 *ip4 = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::ip4); - ip4->set_flags(attributes.value("value").toUInt(&isOk, kBaseHex) >> 5); + ip4->set_flags(attributes.value("value").toString().toUInt(&isOk, kBaseHex) >> 5); } } @@ -592,8 +1024,13 @@ PdmlIp6Protocol::PdmlIp6Protocol() // ipv6.src and ipv6.dst handled as unknown fields } +PdmlDefaultProtocol* PdmlIp6Protocol::createInstance() +{ + return new PdmlIp6Protocol(); +} + void PdmlIp6Protocol::unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream) + const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { bool isOk; @@ -601,7 +1038,7 @@ void PdmlIp6Protocol::unknownFieldHandler(QString name, int pos, int size, { OstProto::Ip6 *ip6 = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::ip6); - QString addrHexStr = attributes.value("value"); + QString addrHexStr = attributes.value("value").toString(); ip6->set_src_addr_hi(addrHexStr.left(16).toULongLong(&isOk, kBaseHex)); ip6->set_src_addr_lo(addrHexStr.right(16).toULongLong(&isOk, kBaseHex)); @@ -610,7 +1047,7 @@ void PdmlIp6Protocol::unknownFieldHandler(QString name, int pos, int size, { OstProto::Ip6 *ip6 = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::ip6); - QString addrHexStr = attributes.value("value"); + QString addrHexStr = attributes.value("value").toString(); ip6->set_dst_addr_hi(addrHexStr.left(16).toULongLong(&isOk, kBaseHex)); ip6->set_dst_addr_lo(addrHexStr.right(16).toULongLong(&isOk, kBaseHex)); @@ -647,15 +1084,20 @@ PdmlTcpProtocol::PdmlTcpProtocol() fieldMap_.insert("tcp.urgent_pointer", OstProto::Tcp::kUrgPtrFieldNumber); } +PdmlDefaultProtocol* PdmlTcpProtocol::createInstance() +{ + return new PdmlTcpProtocol(); +} + void PdmlTcpProtocol::unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream) + const QXmlStreamAttributes &attributes, OstProto::Stream *stream) { if (name == "tcp.options") - options_ = QByteArray::fromHex(attributes.value("value").toUtf8()); + options_ = QByteArray::fromHex(attributes.value("value").toString().toUtf8()); else if (name == "" - && attributes.value("show").startsWith("TCP segment data")) + && attributes.value("show").toString().startsWith("TCP segment data")) { - segmentData_ = QByteArray::fromHex(attributes.value("value").toUtf8()); + segmentData_ = QByteArray::fromHex(attributes.value("value").toString().toUtf8()); stream->mutable_core()->mutable_name()->append(segmentData_.constData(), segmentData_.size()); } @@ -666,6 +1108,8 @@ void PdmlTcpProtocol::postProtocolHandler(OstProto::Stream *stream) OstProto::Tcp *tcp = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::tcp); + qDebug("Tcp: post\n"); + tcp->set_is_override_src_port(true); // FIXME tcp->set_is_override_dst_port(true); // FIXME tcp->set_is_override_hdrlen(true); // FIXME diff --git a/common/pdml_p.h b/common/pdml_p.h index e125dd6..174442c 100644 --- a/common/pdml_p.h +++ b/common/pdml_p.h @@ -26,6 +26,7 @@ along with this program. If not, see #include #include #include +#include // TODO: add const where possible @@ -35,19 +36,22 @@ class QXmlInputSource; class PdmlDefaultProtocol { public: - PdmlDefaultProtocol(); + PdmlDefaultProtocol(); // TODO: make private virtual ~PdmlDefaultProtocol(); + static PdmlDefaultProtocol* createInstance(); + QString pdmlProtoName() const; int ostProtoId() const; bool hasField(QString name) const; int fieldId(QString name) const; virtual void preProtocolHandler(QString name, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); + virtual void prematureEndHandler(int pos, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); protected: QString pdmlProtoName_; // TODO: needed? duplicated in protocolMap_ @@ -55,6 +59,7 @@ protected: QMap fieldMap_; }; +#if 0 class PdmlParser : public QXmlDefaultHandler { public: @@ -83,17 +88,53 @@ private: OstProto::Stream *currentStream_; google::protobuf::Message *currentProtocolMsg_; }; +#endif + +class PdmlReader : public QXmlStreamReader +{ +public: + PdmlReader(OstProto::StreamConfigList *streams); + ~PdmlReader(); + + bool read(QIODevice *device); + +private: + PdmlDefaultProtocol* allocPdmlProtocol(QString protoName); + void freePdmlProtocol(PdmlDefaultProtocol *proto); + + bool isDontCareProto(); + void readPdml(); + void skipElement(); + void readUnexpectedElement(); + void readPacket(); + void readProto(); + void readField(PdmlDefaultProtocol *pdmlProto, + google::protobuf::Message *pbProto); + + typedef PdmlDefaultProtocol* (*FactoryMethod)(); + QMap factory_; + + OstProto::StreamConfigList *streams_; + + int packetCount_; + OstProto::Stream *currentStream_; + //PdmlDefaultProtocol *currentPdmlProtocol_; + //google::protobuf::Message *currentProtocolMsg_; +}; class PdmlUnknownProtocol : public PdmlDefaultProtocol { public: PdmlUnknownProtocol(); + static PdmlDefaultProtocol* createInstance(); + virtual void preProtocolHandler(QString name, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); + virtual void prematureEndHandler(int pos, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); private: int endPos_; int expPos_; @@ -104,14 +145,18 @@ class PdmlGenInfoProtocol : public PdmlDefaultProtocol public: PdmlGenInfoProtocol(); + static PdmlDefaultProtocol* createInstance(); + virtual void unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); }; class PdmlFrameProtocol : public PdmlDefaultProtocol { public: PdmlFrameProtocol(); + + static PdmlDefaultProtocol* createInstance(); }; #if 1 @@ -120,11 +165,13 @@ class PdmlFakeFieldWrapperProtocol : public PdmlDefaultProtocol public: PdmlFakeFieldWrapperProtocol(); + static PdmlDefaultProtocol* createInstance(); + virtual void preProtocolHandler(QString name, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); private: int expPos_; }; @@ -135,16 +182,21 @@ class PdmlEthProtocol : public PdmlDefaultProtocol public: PdmlEthProtocol(); + static PdmlDefaultProtocol* createInstance(); + virtual void unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); }; class PdmlIp4Protocol : public PdmlDefaultProtocol { public: PdmlIp4Protocol(); + + static PdmlDefaultProtocol* createInstance(); + virtual void unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Stream *stream); }; @@ -152,8 +204,11 @@ class PdmlIp6Protocol : public PdmlDefaultProtocol { public: PdmlIp6Protocol(); + + static PdmlDefaultProtocol* createInstance(); + virtual void unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Stream *stream); }; @@ -161,8 +216,11 @@ class PdmlTcpProtocol : public PdmlDefaultProtocol { public: PdmlTcpProtocol(); + + static PdmlDefaultProtocol* createInstance(); + virtual void unknownFieldHandler(QString name, int pos, int size, - const QXmlAttributes &attributes, OstProto::Stream *stream); + const QXmlStreamAttributes &attributes, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Stream *stream); private: QByteArray options_; diff --git a/common/pdmlfileformat.cpp b/common/pdmlfileformat.cpp index 091924b..3f86084 100644 --- a/common/pdmlfileformat.cpp +++ b/common/pdmlfileformat.cpp @@ -30,6 +30,7 @@ PdmlFileFormat::~PdmlFileFormat() { } +#if 0 bool PdmlFileFormat::openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error) { @@ -61,6 +62,32 @@ _exit: return isOk; } +#else +bool PdmlFileFormat::openStreams(const QString fileName, + OstProto::StreamConfigList &streams, QString &error) +{ + bool isOk = false; + QFile file(fileName); + PdmlReader *reader = new PdmlReader(&streams); + + if (!file.open(QIODevice::ReadOnly)) + goto _open_fail; + + // TODO: fill in error string + + isOk = reader->read(&file); + + goto _exit; + +_open_fail: + isOk = false; + +_exit: + delete reader; + + return isOk; +} +#endif bool PdmlFileFormat::saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error)