diff --git a/common/pdml_p.cpp b/common/pdml_p.cpp index 3dac8e0..843d42f 100644 --- a/common/pdml_p.cpp +++ b/common/pdml_p.cpp @@ -95,6 +95,72 @@ void PdmlDefaultProtocol::postProtocolHandler(OstProto::Stream *stream) return; // do nothing! } +void PdmlDefaultProtocol::fieldHandler(QString name, + const QXmlStreamAttributes &attributes, + google::protobuf::Message *pbProto, OstProto::Stream *stream) +{ + if (hasField(name)) + { + QString valueHexStr = attributes.value("value").toString(); + + qDebug("\t(KNOWN) fieldName:%s, value:%s", + name.toAscii().constData(), + valueHexStr.toAscii().constData()); + + knownFieldHandler(name, valueHexStr, pbProto); + } + else + { + 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("\t(UNKNOWN) fieldName:%s, pos:%d, size:%d", + name.toAscii().constData(), pos, size); + + unknownFieldHandler(name, pos, size, attributes, stream); + } +} + +void PdmlDefaultProtocol::knownFieldHandler(QString name, QString valueHexStr, + google::protobuf::Message *pbProto) +{ + int fid = fieldId(name); + const google::protobuf::Descriptor *msgDesc = pbProto->GetDescriptor(); + const google::protobuf::FieldDescriptor *fieldDesc = + msgDesc->FindFieldByNumber(fid); + 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()); + } +} + void PdmlDefaultProtocol::unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Stream *stream) @@ -120,10 +186,10 @@ PdmlReader::PdmlReader(OstProto::StreamConfigList *streams) factory_.insert("hexdump", PdmlUnknownProtocol::createInstance); factory_.insert("geninfo", PdmlGenInfoProtocol::createInstance); factory_.insert("frame", PdmlFrameProtocol::createInstance); - factory_.insert("eth",PdmlEthProtocol::createInstance); - factory_.insert("ip",PdmlIp4Protocol::createInstance); - factory_.insert("ipv6",PdmlIp6Protocol::createInstance); - factory_.insert("tcp",PdmlTcpProtocol::createInstance); + factory_.insert("eth", PdmlEthProtocol::createInstance); + factory_.insert("ip", PdmlIp4Protocol::createInstance); + factory_.insert("ipv6", PdmlIp6Protocol::createInstance); + factory_.insert("tcp", PdmlTcpProtocol::createInstance); } PdmlReader::~PdmlReader() @@ -134,9 +200,8 @@ bool PdmlReader::read(QIODevice *device, PcapFileFormat *pcap, bool *stop) { setDevice(device); pcap_ = pcap; - packetCount_ = 0; - stop_ = stop; + while (!atEnd()) { readNext(); @@ -153,7 +218,7 @@ bool PdmlReader::read(QIODevice *device, PcapFileFormat *pcap, bool *stop) { qDebug("Line %lld", lineNumber()); qDebug("Col %lld", columnNumber()); - qDebug("%s", errorString().toAscii().constData()); // FIXME + qDebug("%s", errorString().toAscii().constData()); return false; } return true; @@ -162,6 +227,7 @@ bool PdmlReader::read(QIODevice *device, PcapFileFormat *pcap, bool *stop) // TODO: use a temp pool to avoid a lot of new/delete PdmlDefaultProtocol* PdmlReader::allocPdmlProtocol(QString protoName) { + // If protoName is not known, we use a hexdump if (!factory_.contains(protoName)) protoName = "hexdump"; @@ -177,42 +243,24 @@ bool PdmlReader::isDontCareProto() { Q_ASSERT(isStartElement() && name() == "proto"); - QString protoName = attributes().value("name").toString(); + QStringRef protoName = attributes().value("name"); 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(); - } + return false; } void PdmlReader::skipElement() { Q_ASSERT(isStartElement()); - // XXX: add to 'log' qDebug("skipping element - <%s>", name().toString().toAscii().constData()); while (!atEnd()) { readNext(); + if (isEndElement()) break; @@ -230,6 +278,7 @@ void PdmlReader::readPdml() while (!atEnd()) { readNext(); + if (isEndElement()) break; @@ -238,7 +287,7 @@ void PdmlReader::readPdml() if (name() == "packet") readPacket(); else - readUnexpectedElement(); + skipElement(); } } } @@ -259,7 +308,7 @@ void PdmlReader::readPacket() currentStream_->mutable_stream_id()->set_id(packetCount_); currentStream_->mutable_core()->set_is_enabled(true); - // Set to a high number; will get reset to correct during parse + // Set to a high number; will get reset to correct value during parse currentStream_->mutable_core()->set_frame_len(16384); // FIXME: Hard coding! expPos_ = 0; @@ -283,32 +332,11 @@ void PdmlReader::readPacket() else if (name() == "field") readField(NULL, NULL); // TODO: top level field!!!! else - readUnexpectedElement(); + skipElement(); } } - // BAD Hack for TCP Segments - if (currentStream_->core().name().size()) -#if 0 - { - OstProto::Protocol *proto = currentStream_->add_protocol(); - proto->mutable_protocol_id()->set_id( - OstProto::Protocol::kHexDumpFieldNumber); - - OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump); - - qDebug("Adding TCP Segment Data/FCS etc of size %d", - currentStream_->core().name().size()); - - hexDump->set_content(currentStream_->core().name()); - hexDump->set_pad_until_end(false); - currentStream_->mutable_core()->set_name(""); - - expPos_ += hexDump->content().size(); - } -#else - currentStream_->mutable_core()->set_name(""); -#endif + currentStream_->mutable_core()->set_name(""); // FIXME // If trailing bytes are missing, add those from the pcap if ((expPos_ < pktBuf_.size()) && pcap_) @@ -328,7 +356,7 @@ void PdmlReader::readPacket() } packetCount_++; - emit progress(int(characterOffset()*100/device()->size())); + emit progress(int(characterOffset()*100/device()->size())); // in % if (prevStream_) prevStream_->mutable_control()->CopyFrom(currentStream_->control()); if (stop_ && *stop_) @@ -342,10 +370,12 @@ void PdmlReader::readProto() Q_ASSERT(isStartElement() && name() == "proto"); - QString protoName = attributes().value("name").toString(); + QString protoName; int pos = -1; int size = -1; + if (!attributes().value("name").isEmpty()) + protoName = attributes().value("name").toString(); if (!attributes().value("pos").isEmpty()) pos = attributes().value("pos").toString().toInt(); if (!attributes().value("size").isEmpty()) @@ -356,44 +386,27 @@ void PdmlReader::readProto() // This is a heuristic to skip protocols which are not part of // this frame, but of a reassembled segment spanning several frames - // 1. Proto starting pos is 0, but we already seen some protocols + // 1. Proto starting pos is 0, but we've already seen some protocols // 2. Protocol Size exceeds frame length if (((pos == 0) && (currentStream_->protocol_size() > 0)) || ((pos + size) > int(currentStream_->core().frame_len()))) { - qDebug("(skipped)"); skipElement(); return; } -#if 1 - if (protoName.isEmpty() || (protoName == "expert")) + if (isDontCareProto()) { skipElement(); return; } -#endif - // detect overlaps or gaps between subsequent protocols and "fill-in" + // if we detect a gap between subsequent protocols, we "fill-in" // with a "hexdump" from the pcap - if (pos >=0 && pcap_) + if (pos > expPos_ && pcap_) { - if (pos > expPos_) - { - OstProto::Protocol *proto = currentStream_->add_protocol(); - OstProto::HexDump *hexDump = proto->MutableExtension( - OstProto::hexDump); - - proto->mutable_protocol_id()->set_id( - OstProto::Protocol::kHexDumpFieldNumber); - - qDebug("filling in gap of %d bytes starting from %d", - pos - expPos_, expPos_); - hexDump->set_content(pktBuf_.constData() + expPos_, pos - expPos_); - hexDump->set_pad_until_end(false); - - expPos_ = pos; - } + appendHexDumpProto(expPos_, pos - expPos_); + expPos_ = pos; } // for unknown protocol, read a hexdump from the pcap @@ -404,7 +417,6 @@ void PdmlReader::readProto() if (!attributes().value("size").isEmpty()) size = attributes().value("size").toString().toInt(); - // Check if this proto is a subset of previous proto - if so, do nothing if ((pos >= 0) && (size > 0) && ((pos + size) <= expPos_)) { @@ -416,47 +428,18 @@ void PdmlReader::readProto() if (pos >= 0 && size > 0 && ((pos + size) <= pktBuf_.size())) { - OstProto::Protocol *proto = currentStream_->add_protocol(); - OstProto::HexDump *hexDump = proto->MutableExtension( - OstProto::hexDump); - - proto->mutable_protocol_id()->set_id( - OstProto::Protocol::kHexDumpFieldNumber); - - qDebug("missing bytes - filling in %d bytes staring from %d", - size, pos); - hexDump->set_content(pktBuf_.constData() + pos, size); - hexDump->set_pad_until_end(false); + appendHexDumpProto(pos, size); + expPos_ += size; skipElement(); - - expPos_ += size; return; } } - 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 = appendPdmlProto(protoName, &pbProto); + qDebug("%s: preProtocolHandler(expPos = %d)", + protoName.toAscii().constData(), expPos_); pdmlProto->preProtocolHandler(protoName, attributes(), expPos_, currentStream_); @@ -471,23 +454,28 @@ void PdmlReader::readProto() { 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 we are in the midst of processing a protocol, we + // end it prematurely before we start processing the + // embedded protocol + // + // XXX: pdmlProto may be NULL for a sequence of embedded protos if (pdmlProto) { + int endPos = -1; + + if (!attributes().value("pos").isEmpty()) + endPos = attributes().value("pos").toString().toInt(); + pdmlProto->prematureEndHandler(endPos, currentStream_); pdmlProto->postProtocolHandler(currentStream_); @@ -495,7 +483,9 @@ void PdmlReader::readProto() s.protoDataCopyFrom(*currentStream_); expPos_ = s.frameProtocolLength(0); } + readProto(); + pdmlProto = NULL; pbProto = NULL; } @@ -511,38 +501,24 @@ void PdmlReader::readProto() continue; } - if (pdmlProto == NULL) { - pdmlProto = allocPdmlProtocol(protoName); - protoId = pdmlProto->ostProtoId(); + pdmlProto = appendPdmlProto(protoName, &pbProto); - // 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); - - } + qDebug("%s: preProtocolHandler(expPos = %d)", + protoName.toAscii().constData(), expPos_); pdmlProto->preProtocolHandler(protoName, attributes(), expPos_, currentStream_); } + readField(pdmlProto, pbProto); } else - readUnexpectedElement(); + skipElement(); } } + // Close-off current protocol if (pdmlProto) { pdmlProto->postProtocolHandler(currentStream_); @@ -567,61 +543,10 @@ void PdmlReader::readField(PdmlDefaultProtocol *pdmlProto, } 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(" fieldName:%s", fieldName.toAscii().constData()); - 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_); - } + pdmlProto->fieldHandler(fieldName, attributes(), pbProto, currentStream_); while (!atEnd()) { @@ -633,22 +558,56 @@ void PdmlReader::readField(PdmlDefaultProtocol *pdmlProto, if (isStartElement()) { if (name() == "proto") - { - if (isDontCareProto()) - { - skipElement(); - continue; - } readProto(); - } else if (name() == "field") readField(pdmlProto, pbProto); else - readUnexpectedElement(); + skipElement(); } } } +void PdmlReader::appendHexDumpProto(int offset, int size) +{ + OstProto::Protocol *proto = currentStream_->add_protocol(); + OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump); + + proto->mutable_protocol_id()->set_id( + OstProto::Protocol::kHexDumpFieldNumber); + + qDebug("filling in gap of %d bytes starting from %d", size, offset); + hexDump->set_content(pktBuf_.constData() + offset, size); + hexDump->set_pad_until_end(false); +} + +PdmlDefaultProtocol* PdmlReader::appendPdmlProto(const QString &protoName, + google::protobuf::Message **pbProto) +{ + PdmlDefaultProtocol* pdmlProto = allocPdmlProtocol(protoName); + Q_ASSERT(pdmlProto != NULL); + + int protoId = pdmlProto->ostProtoId(); + + if (protoId > 0) // Non-Base Class + { + 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); + } + else + *pbProto = NULL; + + return pdmlProto; +} + // ---------------------------------------------------------- // // PdmlUnknownProtocol // @@ -720,9 +679,6 @@ void PdmlUnknownProtocol::postProtocolHandler(OstProto::Stream *stream) } qDebug(" hexdump: expPos_ = %d, endPos_ = %d\n", expPos_, endPos_); - //Q_ASSERT(expPos_ == endPos_); - - hexDump->set_pad_until_end(false); // If empty for some reason, remove the protocol if (hexDump->content().size() == 0) @@ -750,7 +706,7 @@ void PdmlUnknownProtocol::unknownFieldHandler(QString name, int pos, int size, expPos_ += hexVal.size(); } - if ((pos == expPos_) /*&& (pos < endPos_)*/) + if (pos == expPos_) { QByteArray hexVal = attributes.value("unmaskedvalue").isEmpty() ? QByteArray::fromHex(attributes.value("value").toString().toUtf8()) : diff --git a/common/pdml_p.h b/common/pdml_p.h index af7c4f6..614a4cc 100644 --- a/common/pdml_p.h +++ b/common/pdml_p.h @@ -23,16 +23,12 @@ along with this program. If not, see #include #include -#include #include #include #include // TODO: add const where possible -class QXmlSimpleReader; -class QXmlInputSource; - class PdmlDefaultProtocol { public: @@ -51,6 +47,11 @@ public: int expectedPos, OstProto::Stream *stream); virtual void prematureEndHandler(int pos, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Stream *stream); + + void fieldHandler(QString name, const QXmlStreamAttributes &attributes, + google::protobuf::Message *pbProto, OstProto::Stream *stream); + void knownFieldHandler(QString name, QString valueHexStr, + google::protobuf::Message *pbProto); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Stream *stream); @@ -65,7 +66,7 @@ class PcapFileFormat; class PdmlReader : public QObject, public QXmlStreamReader { Q_OBJECT - friend class PdmlUnknownProtocol; + //friend class PdmlUnknownProtocol; public: PdmlReader(OstProto::StreamConfigList *streams); ~PdmlReader(); @@ -80,34 +81,32 @@ private: void freePdmlProtocol(PdmlDefaultProtocol *proto); bool isDontCareProto(); - void readPdml(); void skipElement(); - void readUnexpectedElement(); - - void readPacketPass1(); - void readProtoPass1(); - void readFieldPass1(); + void readPdml(); void readPacket(); void readProto(); void readField(PdmlDefaultProtocol *pdmlProto, google::protobuf::Message *pbProto); + void appendHexDumpProto(int offset, int size); + PdmlDefaultProtocol* appendPdmlProto(const QString &protoName, + google::protobuf::Message **pbProto); + typedef PdmlDefaultProtocol* (*FactoryMethod)(); QMap factory_; + bool *stop_; OstProto::StreamConfigList *streams_; PcapFileFormat *pcap_; + QByteArray pktBuf_; int packetCount_; int expPos_; bool skipUntilEnd_; OstProto::Stream *prevStream_; OstProto::Stream *currentStream_; - - QByteArray pktBuf_; - bool *stop_; }; class PdmlUnknownProtocol : public PdmlDefaultProtocol @@ -135,7 +134,6 @@ public: PdmlGenInfoProtocol(); static PdmlDefaultProtocol* createInstance(); - }; class PdmlFrameProtocol : public PdmlDefaultProtocol