/*
Copyright (C) 2011 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 "pdmlprotocols.h"
#include "arp.pb.h"
#include "eth2.pb.h"
#include "dot3.pb.h"
#include "gmp.pb.h"
#include "hexdump.pb.h"
#include "llc.pb.h"
#include "mac.pb.h"
#include "icmp.pb.h"
#include "igmp.pb.h"
#include "ip4.pb.h"
#include "ip6.pb.h"
#include "mld.pb.h"
#include "sample.pb.h"
#include "snap.pb.h"
#include "svlan.pb.h"
#include "tcp.pb.h"
#include "textproto.pb.h"
#include "udp.pb.h"
#include "vlan.pb.h"
#include
#include
const int kBaseHex = 16;
// ---------------------------------------------------------- //
// PdmlUnknownProtocol //
// ---------------------------------------------------------- //
PdmlUnknownProtocol::PdmlUnknownProtocol()
{
ostProtoId_ = OstProto::Protocol::kHexDumpFieldNumber;
endPos_ = expPos_ = -1;
}
PdmlProtocol* PdmlUnknownProtocol::createInstance()
{
return new PdmlUnknownProtocol();
}
void PdmlUnknownProtocol::preProtocolHandler(QString /*name*/,
const QXmlStreamAttributes &attributes, int expectedPos,
OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream)
{
bool isOk;
int size;
int pos = attributes.value("pos").toString().toUInt(&isOk);
if (!isOk)
{
if (expectedPos >= 0)
expPos_ = pos = expectedPos;
else
goto _skip_pos_size_proc;
}
size = attributes.value("size").toString().toUInt(&isOk);
if (!isOk)
goto _skip_pos_size_proc;
// If pos+size goes beyond the frame length, this is a "reassembled"
// protocol and should be skipped
if ((pos + size) > int(stream->core().frame_len()))
goto _skip_pos_size_proc;
expPos_ = pos;
endPos_ = expPos_ + size;
_skip_pos_size_proc:
OstProto::HexDump *hexDump = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::hexDump);
hexDump->set_pad_until_end(false);
}
void PdmlUnknownProtocol::prematureEndHandler(int pos,
OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/)
{
endPos_ = pos;
}
void PdmlUnknownProtocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream *stream)
{
OstProto::HexDump *hexDump = pbProto->MutableExtension(OstProto::hexDump);
// Skipped field(s) at end? Pad with zero!
if (endPos_ > expPos_)
{
QByteArray hexVal(endPos_ - expPos_, char(0));
hexDump->mutable_content()->append(hexVal.constData(), hexVal.size());
expPos_ += hexVal.size();
}
qDebug(" hexdump: expPos_ = %d, endPos_ = %d\n", expPos_, endPos_);
// If empty for some reason, remove the protocol
if (hexDump->content().size() == 0)
stream->mutable_protocol()->RemoveLast();
endPos_ = expPos_ = -1;
}
void PdmlUnknownProtocol::unknownFieldHandler(QString name, int pos,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
OstProto::HexDump *hexDump = pbProto->MutableExtension(OstProto::hexDump);
qDebug(" hexdump: %s, pos = %d, expPos_ = %d, endPos_ = %d\n",
name.toAscii().constData(),
pos, expPos_, endPos_);
// Skipped field? Pad with zero!
if ((pos > expPos_) && (expPos_ < endPos_))
{
QByteArray hexVal(pos - expPos_, char(0));
hexDump->mutable_content()->append(hexVal.constData(), hexVal.size());
expPos_ += hexVal.size();
}
if (pos == expPos_)
{
QByteArray hexVal = attributes.value("unmaskedvalue").isEmpty() ?
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();
}
}
// ---------------------------------------------------------- //
// PdmlGenInfoProtocol //
// ---------------------------------------------------------- //
PdmlGenInfoProtocol::PdmlGenInfoProtocol()
{
}
PdmlProtocol* PdmlGenInfoProtocol::createInstance()
{
return new PdmlGenInfoProtocol();
}
// ---------------------------------------------------------- //
// PdmlFrameProtocol //
// ---------------------------------------------------------- //
PdmlFrameProtocol::PdmlFrameProtocol()
{
}
PdmlProtocol* PdmlFrameProtocol::createInstance()
{
return new PdmlFrameProtocol();
}
void PdmlFrameProtocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream)
{
if (name == "frame.len")
{
int len = -1;
if (!attributes.value("show").isEmpty())
len = attributes.value("show").toString().toInt();
stream->mutable_core()->set_frame_len(len+4); // TODO:check FCS
}
else if (name == "frame.time_delta")
{
if (!attributes.value("show").isEmpty())
{
QString delta = attributes.value("show").toString();
int decimal = delta.indexOf('.');
if (decimal >= 0)
{
const uint kNsecsInSec = 1000000000;
uint sec = delta.left(decimal).toUInt();
uint nsec = delta.mid(decimal+1).toUInt();
uint ipg = sec*kNsecsInSec + nsec;
if (ipg)
{
stream->mutable_control()->set_packets_per_sec(
kNsecsInSec/ipg);
}
qDebug("sec.nsec = %u.%u, ipg = %u", sec, nsec, ipg);
}
}
}
}
// ---------------------------------------------------------- //
// PdmlSvlanProtocol //
// ---------------------------------------------------------- //
PdmlSvlanProtocol::PdmlSvlanProtocol()
{
ostProtoId_ = OstProto::Protocol::kSvlanFieldNumber;
}
PdmlProtocol* PdmlSvlanProtocol::createInstance()
{
return new PdmlSvlanProtocol();
}
void PdmlSvlanProtocol::preProtocolHandler(QString /*name*/,
const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/,
OstProto::Protocol *pbProto, OstProto::Stream *stream)
{
OstProto::Vlan *svlan = pbProto->MutableExtension(OstProto::svlan);
svlan->set_tpid(0x88a8);
svlan->set_is_override_tpid(true);
// If a eth2 protocol precedes svlan, we remove the eth2 protocol
// 'coz the eth2.etherType is actually the svlan.tpid
//
// We assume that the current protocol is the last in the stream
int index = stream->protocol_size() - 1;
if ((index > 1)
&& (stream->protocol(index).protocol_id().id()
== OstProto::Protocol::kSvlanFieldNumber)
&& (stream->protocol(index - 1).protocol_id().id()
== OstProto::Protocol::kEth2FieldNumber))
{
stream->mutable_protocol()->SwapElements(index, index - 1);
Q_ASSERT(stream->protocol(index).protocol_id().id()
== OstProto::Protocol::kEth2FieldNumber);
stream->mutable_protocol()->RemoveLast();
}
}
void PdmlSvlanProtocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream *stream)
{
if ((name == "ieee8021ad.id") || (name == "ieee8021ad.svid"))
{
bool isOk;
OstProto::Vlan *svlan = pbProto->MutableExtension(OstProto::svlan);
uint tag = attributes.value("unmaskedvalue").isEmpty() ?
attributes.value("value").toString().toUInt(&isOk, kBaseHex) :
attributes.value("unmaskedvalue").toString().toUInt(&isOk,kBaseHex);
svlan->set_vlan_tag(tag);
}
else if (name == "ieee8021ad.cvid")
{
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kSvlanFieldNumber);
OstProto::Vlan *svlan = proto->MutableExtension(OstProto::svlan);
svlan->set_tpid(0x88a8);
svlan->set_is_override_tpid(true);
bool isOk;
uint tag = attributes.value("unmaskedvalue").isEmpty() ?
attributes.value("value").toString().toUInt(&isOk, kBaseHex) :
attributes.value("unmaskedvalue").toString().toUInt(&isOk,kBaseHex);
svlan->set_vlan_tag(tag);
}
else if (name == "ieee8021ah.etype") // yes 'ah' not 'ad' - not a typo!
{
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kEth2FieldNumber);
bool isOk;
OstProto::Eth2 *eth2 = proto->MutableExtension(OstProto::eth2);
eth2->set_type(attributes.value("value")
.toString().toUInt(&isOk, kBaseHex));
eth2->set_is_override_type(true);
}
}
// ---------------------------------------------------------- //
// PdmlVlanProtocol //
// ---------------------------------------------------------- //
PdmlVlanProtocol::PdmlVlanProtocol()
{
ostProtoId_ = OstProto::Protocol::kVlanFieldNumber;
}
PdmlProtocol* PdmlVlanProtocol::createInstance()
{
return new PdmlVlanProtocol();
}
void PdmlVlanProtocol::preProtocolHandler(QString /*name*/,
const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/,
OstProto::Protocol *pbProto, OstProto::Stream *stream)
{
OstProto::Vlan *vlan = pbProto->MutableExtension(OstProto::vlan);
vlan->set_tpid(0x8100);
vlan->set_is_override_tpid(true);
// If a eth2 protocol precedes vlan, we remove the eth2 protocol
// 'coz the eth2.etherType is actually the vlan.tpid
//
// We assume that the current protocol is the last in the stream
int index = stream->protocol_size() - 1;
if ((index > 1)
&& (stream->protocol(index).protocol_id().id()
== OstProto::Protocol::kVlanFieldNumber)
&& (stream->protocol(index - 1).protocol_id().id()
== OstProto::Protocol::kEth2FieldNumber))
{
stream->mutable_protocol()->SwapElements(index, index - 1);
Q_ASSERT(stream->protocol(index).protocol_id().id()
== OstProto::Protocol::kEth2FieldNumber);
stream->mutable_protocol()->RemoveLast();
}
}
void PdmlVlanProtocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream *stream)
{
if (name == "vlan.id")
{
bool isOk;
OstProto::Vlan *vlan = pbProto->MutableExtension(OstProto::vlan);
uint tag = attributes.value("unmaskedvalue").isEmpty() ?
attributes.value("value").toString().toUInt(&isOk, kBaseHex) :
attributes.value("unmaskedvalue").toString().toUInt(&isOk,kBaseHex);
vlan->set_vlan_tag(tag);
}
else if (name == "vlan.etype")
{
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kEth2FieldNumber);
bool isOk;
OstProto::Eth2 *eth2 = proto->MutableExtension(OstProto::eth2);
eth2->set_type(attributes.value("value")
.toString().toUInt(&isOk, kBaseHex));
eth2->set_is_override_type(true);
}
}
// ---------------------------------------------------------- //
// PdmlEthProtocol //
// ---------------------------------------------------------- //
PdmlEthProtocol::PdmlEthProtocol()
{
ostProtoId_ = OstProto::Protocol::kMacFieldNumber;
fieldMap_.insert("eth.dst", OstProto::Mac::kDstMacFieldNumber);
fieldMap_.insert("eth.src", OstProto::Mac::kSrcMacFieldNumber);
}
PdmlProtocol* PdmlEthProtocol::createInstance()
{
return new PdmlEthProtocol();
}
void PdmlEthProtocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream)
{
if (name == "eth.vlan.tpid")
{
bool isOk;
uint tpid = attributes.value("value").toString()
.toUInt(&isOk, kBaseHex);
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kVlanFieldNumber);
OstProto::Vlan *vlan = proto->MutableExtension(OstProto::vlan);
vlan->set_tpid(tpid);
vlan->set_is_override_tpid(true);
}
else if (name == "eth.vlan.id")
{
bool isOk;
uint tag = attributes.value("unmaskedvalue").isEmpty() ?
attributes.value("value").toString().toUInt(&isOk, kBaseHex) :
attributes.value("unmaskedvalue").toString().toUInt(&isOk,kBaseHex);
OstProto::Vlan *vlan = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::vlan);
vlan->set_vlan_tag(tag);
}
else if (name == "eth.type")
{
bool isOk;
uint type = attributes.value("value").toString()
.toUInt(&isOk, kBaseHex);
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kEth2FieldNumber);
OstProto::Eth2 *eth2 = proto->MutableExtension(OstProto::eth2);
eth2->set_type(type);
eth2->set_is_override_type(true);
}
else if (name == "eth.len")
{
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kDot3FieldNumber);
OstProto::Dot3 *dot3 = proto->MutableExtension(OstProto::dot3);
bool isOk;
dot3->set_length(attributes.value("value").toString().toUInt(&isOk, kBaseHex));
dot3->set_is_override_length(true);
}
#if 0
else if (name == "eth.trailer")
{
QByteArray trailer = QByteArray::fromHex(
attributes.value("value").toString().toUtf8());
stream->mutable_core()->mutable_name()->append(trailer.constData(),
trailer.size());
}
else if ((name == "eth.fcs") ||
attributes.value("show").toString().startsWith("Frame check sequence"))
{
QByteArray trailer = QByteArray::fromHex(
attributes.value("value").toString().toUtf8());
stream->mutable_core()->mutable_name()->append(trailer.constData(),
trailer.size());
}
#endif
}
// ---------------------------------------------------------- //
// PdmlLlcProtocol //
// ---------------------------------------------------------- //
PdmlLlcProtocol::PdmlLlcProtocol()
{
ostProtoId_ = OstProto::Protocol::kLlcFieldNumber;
fieldMap_.insert("llc.dsap", OstProto::Llc::kDsapFieldNumber);
fieldMap_.insert("llc.ssap", OstProto::Llc::kSsapFieldNumber);
fieldMap_.insert("llc.control", OstProto::Llc::kCtlFieldNumber);
}
PdmlProtocol* PdmlLlcProtocol::createInstance()
{
return new PdmlLlcProtocol();
}
void PdmlLlcProtocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream)
{
if (name == "llc.oui")
{
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kSnapFieldNumber);
OstProto::Snap *snap = proto->MutableExtension(OstProto::snap);
bool isOk;
snap->set_oui(attributes.value("value").toString()
.toUInt(&isOk, kBaseHex));
snap->set_is_override_oui(true);
}
else if ((name == "llc.type") || (name.contains(QRegExp("llc\\..*pid"))))
{
OstProto::Snap *snap = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::snap);
bool isOk;
snap->set_type(attributes.value("value").toString()
.toUInt(&isOk, kBaseHex));
snap->set_is_override_type(true);
}
}
void PdmlLlcProtocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream* /*stream*/)
{
OstProto::Llc *llc = pbProto->MutableExtension(OstProto::llc);
llc->set_is_override_dsap(true);
llc->set_is_override_ssap(true);
llc->set_is_override_ctl(true);
}
// ---------------------------------------------------------- //
// PdmlArpProtocol //
// ---------------------------------------------------------- //
PdmlArpProtocol::PdmlArpProtocol()
{
ostProtoId_ = OstProto::Protocol::kArpFieldNumber;
fieldMap_.insert("arp.opcode", OstProto::Arp::kOpCodeFieldNumber);
fieldMap_.insert("arp.src.hw_mac", OstProto::Arp::kSenderHwAddrFieldNumber);
fieldMap_.insert("arp.src.proto_ipv4",
OstProto::Arp::kSenderProtoAddrFieldNumber);
fieldMap_.insert("arp.dst.hw_mac", OstProto::Arp::kTargetHwAddrFieldNumber);
fieldMap_.insert("arp.dst.proto_ipv4",
OstProto::Arp::kTargetProtoAddrFieldNumber);
}
PdmlProtocol* PdmlArpProtocol::createInstance()
{
return new PdmlArpProtocol();
}
// ---------------------------------------------------------- //
// PdmlIp4Protocol //
// ---------------------------------------------------------- //
PdmlIp4Protocol::PdmlIp4Protocol()
{
ostProtoId_ = OstProto::Protocol::kIp4FieldNumber;
fieldMap_.insert("ip.version", OstProto::Ip4::kVerHdrlenFieldNumber);
fieldMap_.insert("ip.dsfield", OstProto::Ip4::kTosFieldNumber);
fieldMap_.insert("ip.len", OstProto::Ip4::kTotlenFieldNumber);
fieldMap_.insert("ip.id", OstProto::Ip4::kIdFieldNumber);
//fieldMap_.insert("ip.flags", OstProto::Ip4::kFlagsFieldNumber);
fieldMap_.insert("ip.frag_offset", OstProto::Ip4::kFragOfsFieldNumber);
fieldMap_.insert("ip.ttl", OstProto::Ip4::kTtlFieldNumber);
fieldMap_.insert("ip.proto", OstProto::Ip4::kProtoFieldNumber);
fieldMap_.insert("ip.checksum", OstProto::Ip4::kCksumFieldNumber);
fieldMap_.insert("ip.src", OstProto::Ip4::kSrcIpFieldNumber);
fieldMap_.insert("ip.dst", OstProto::Ip4::kDstIpFieldNumber);
}
PdmlProtocol* PdmlIp4Protocol::createInstance()
{
return new PdmlIp4Protocol();
}
void PdmlIp4Protocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
bool isOk;
if ((name == "ip.options") ||
attributes.value("show").toString().startsWith("Options"))
{
options_ = QByteArray::fromHex(
attributes.value("value").toString().toUtf8());
}
else if (name == "ip.flags")
{
OstProto::Ip4 *ip4 = pbProto->MutableExtension(OstProto::ip4);
ip4->set_flags(attributes.value("value").toString().toUInt(&isOk, kBaseHex) >> 5);
}
}
void PdmlIp4Protocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream *stream)
{
OstProto::Ip4 *ip4 = pbProto->MutableExtension(OstProto::ip4);
ip4->set_is_override_ver(true);
ip4->set_is_override_hdrlen(true);
ip4->set_is_override_totlen(true);
ip4->set_is_override_proto(true);
ip4->set_is_override_cksum(true);
if (options_.size())
{
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kHexDumpFieldNumber);
OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump);
hexDump->mutable_content()->append(options_.constData(),
options_.size());
hexDump->set_pad_until_end(false);
options_.resize(0);
}
}
// ---------------------------------------------------------- //
// PdmlIp6Protocol //
// ---------------------------------------------------------- //
PdmlIp6Protocol::PdmlIp6Protocol()
{
ostProtoId_ = OstProto::Protocol::kIp6FieldNumber;
fieldMap_.insert("ipv6.version", OstProto::Ip6::kVersionFieldNumber);
fieldMap_.insert("ipv6.class", OstProto::Ip6::kTrafficClassFieldNumber);
fieldMap_.insert("ipv6.flow", OstProto::Ip6::kFlowLabelFieldNumber);
fieldMap_.insert("ipv6.plen", OstProto::Ip6::kPayloadLengthFieldNumber);
fieldMap_.insert("ipv6.nxt", OstProto::Ip6::kNextHeaderFieldNumber);
fieldMap_.insert("ipv6.hlim", OstProto::Ip6::kHopLimitFieldNumber);
// ipv6.src and ipv6.dst handled as unknown fields
}
PdmlProtocol* PdmlIp6Protocol::createInstance()
{
return new PdmlIp6Protocol();
}
void PdmlIp6Protocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
bool isOk;
if (name == "ipv6.src")
{
OstProto::Ip6 *ip6 = pbProto->MutableExtension(OstProto::ip6);
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));
}
else if (name == "ipv6.dst")
{
OstProto::Ip6 *ip6 = pbProto->MutableExtension(OstProto::ip6);
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));
}
}
void PdmlIp6Protocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream* /*stream*/)
{
OstProto::Ip6 *ip6 = pbProto->MutableExtension(OstProto::ip6);
ip6->set_is_override_version(true);
ip6->set_is_override_payload_length(true);
ip6->set_is_override_next_header(true);
}
// ---------------------------------------------------------- //
// PdmlIcmpProtocol //
// ---------------------------------------------------------- //
PdmlIcmpProtocol::PdmlIcmpProtocol()
{
ostProtoId_ = OstProto::Protocol::kIcmpFieldNumber;
fieldMap_.insert("icmp.type", OstProto::Icmp::kTypeFieldNumber);
fieldMap_.insert("icmp.code", OstProto::Icmp::kCodeFieldNumber);
fieldMap_.insert("icmp.checksum", OstProto::Icmp::kChecksumFieldNumber);
fieldMap_.insert("icmp.ident", OstProto::Icmp::kIdentifierFieldNumber);
fieldMap_.insert("icmp.seq", OstProto::Icmp::kSequenceFieldNumber);
fieldMap_.insert("icmpv6.type", OstProto::Icmp::kTypeFieldNumber);
fieldMap_.insert("icmpv6.code", OstProto::Icmp::kCodeFieldNumber);
fieldMap_.insert("icmpv6.checksum", OstProto::Icmp::kChecksumFieldNumber);
fieldMap_.insert("icmpv6.echo.identifier",
OstProto::Icmp::kIdentifierFieldNumber);
fieldMap_.insert("icmpv6.echo.sequence_number",
OstProto::Icmp::kSequenceFieldNumber);
}
PdmlProtocol* PdmlIcmpProtocol::createInstance()
{
return new PdmlIcmpProtocol();
}
void PdmlIcmpProtocol::preProtocolHandler(QString name,
const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
OstProto::Icmp *icmp = pbProto->MutableExtension(OstProto::icmp);
if (name == "icmp")
icmp->set_icmp_version(OstProto::Icmp::kIcmp4);
else if (name == "icmpv6")
icmp->set_icmp_version(OstProto::Icmp::kIcmp6);
icmp->set_is_override_checksum(true);
icmp->set_type(kIcmpInvalidType);
}
void PdmlIcmpProtocol::unknownFieldHandler(QString /*name*/, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
bool isOk;
OstProto::Icmp *icmp = pbProto->MutableExtension(OstProto::icmp);
if ((icmp->icmp_version() == OstProto::Icmp::kIcmp6)
&& (icmp->type() >= kIcmp6EchoRequest)
&& (icmp->type() <= kIcmp6EchoReply))
{
QString addrHexStr = attributes.value("value").toString();
// Wireshark 1.4.x does not have these as filterable fields
if (attributes.value("show").toString().startsWith("ID"))
icmp->set_identifier(addrHexStr.toUInt(&isOk, kBaseHex));
else if (attributes.value("show").toString().startsWith("Sequence"))
icmp->set_sequence(addrHexStr.toUInt(&isOk, kBaseHex));
}
}
void PdmlIcmpProtocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream *stream)
{
OstProto::Icmp *icmp = pbProto->MutableExtension(OstProto::icmp);
if (icmp->type() == kIcmpInvalidType)
stream->mutable_protocol()->RemoveLast();
}
// ---------------------------------------------------------- //
// PdmlIcmp6Protocol //
// ---------------------------------------------------------- //
PdmlIcmp6Protocol::PdmlIcmp6Protocol()
{
ostProtoId_ = OstProto::Protocol::kSampleFieldNumber;
proto_ = NULL;
}
PdmlProtocol* PdmlIcmp6Protocol::createInstance()
{
return new PdmlIcmp6Protocol();
}
void PdmlIcmp6Protocol::preProtocolHandler(QString name,
const QXmlStreamAttributes &attributes,
int expectedPos, OstProto::Protocol *pbProto,
OstProto::Stream *stream)
{
proto_ = NULL;
ostProtoId_ = OstProto::Protocol::kSampleFieldNumber;
icmp_.preProtocolHandler(name, attributes, expectedPos, pbProto, stream);
mld_.preProtocolHandler(name, attributes, expectedPos, pbProto, stream);
}
void PdmlIcmp6Protocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream *stream)
{
if (proto_)
proto_->postProtocolHandler(pbProto, stream);
else
stream->mutable_protocol()->RemoveLast();
proto_ = NULL;
ostProtoId_ = OstProto::Protocol::kSampleFieldNumber;
}
void PdmlIcmp6Protocol::unknownFieldHandler(QString name,
int pos, int size, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream *stream)
{
if (proto_)
{
proto_->unknownFieldHandler(name, pos, size, attributes, pbProto,
stream);
}
else if (name == "icmpv6.type")
{
bool isOk;
uint type = attributes.value("value").toString().toUInt(
&isOk, kBaseHex);
if (((type >= 130) && (type <= 132)) || (type == 143))
{
// MLD
proto_ = &mld_;
fieldMap_ = mld_.fieldMap_;
ostProtoId_ = OstProto::Protocol::kMldFieldNumber;
}
else
{
// ICMP
proto_ = &icmp_;
fieldMap_ = icmp_.fieldMap_;
ostProtoId_ = OstProto::Protocol::kIcmpFieldNumber;
}
pbProto->mutable_protocol_id()->set_id(ostProtoId_);
pbProto->MutableExtension(OstProto::sample)->Clear();
fieldHandler(name, attributes, pbProto, stream);
}
else
{
qDebug("unexpected field %s", name.toAscii().constData());
}
}
// ---------------------------------------------------------- //
// PdmlIgmpProtocol //
// ---------------------------------------------------------- //
PdmlIgmpProtocol::PdmlIgmpProtocol()
{
ostProtoId_ = OstProto::Protocol::kIgmpFieldNumber;
fieldMap_.insert("igmp.max_resp",
OstProto::Gmp::kMaxResponseTimeFieldNumber); // FIXME
fieldMap_.insert("igmp.checksum", OstProto::Gmp::kChecksumFieldNumber);
fieldMap_.insert("igmp.s", OstProto::Gmp::kSFlagFieldNumber);
fieldMap_.insert("igmp.qrv", OstProto::Gmp::kQrvFieldNumber);
fieldMap_.insert("igmp.qqic", OstProto::Gmp::kQqiFieldNumber); // FIXME
fieldMap_.insert("igmp.num_grp_recs",
OstProto::Gmp::kGroupRecordCountFieldNumber);
}
PdmlProtocol* PdmlIgmpProtocol::createInstance()
{
return new PdmlIgmpProtocol();
}
void PdmlIgmpProtocol::preProtocolHandler(QString /*name*/,
const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
OstProto::Gmp *igmp = pbProto->MutableExtension(OstProto::igmp);
igmp->set_is_override_rsvd_code(true);
igmp->set_is_override_checksum(true);
igmp->set_is_override_source_count(true);
igmp->set_is_override_group_record_count(true);
version_ = 0;
}
void PdmlIgmpProtocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
bool isOk;
OstProto::Gmp *igmp = pbProto->MutableExtension(OstProto::igmp);
QString valueHexStr = attributes.value("value").toString();
if (name == "igmp.version")
{
version_ = attributes.value("show").toString().toUInt(&isOk);
}
else if (name == "igmp.type")
{
uint type = valueHexStr.toUInt(&isOk, kBaseHex);
if (type == kIgmpQuery)
{
switch(version_)
{
case 1: type = kIgmpV1Query; break;
case 2: type = kIgmpV2Query; break;
case 3: type = kIgmpV3Query; break;
}
}
igmp->set_type(type);
}
else if (name == "igmp.record_type")
{
OstProto::Gmp::GroupRecord *rec = igmp->add_group_records();
rec->set_type(OstProto::Gmp::GroupRecord::RecordType(
valueHexStr.toUInt(&isOk, kBaseHex)));
rec->set_is_override_source_count(true);
rec->set_is_override_aux_data_length(true);
}
else if (name == "igmp.aux_data_len")
{
igmp->mutable_group_records(igmp->group_records_size() - 1)->
set_aux_data_length(valueHexStr.toUInt(&isOk, kBaseHex));
}
else if (name == "igmp.num_src")
{
if (igmp->group_record_count())
igmp->mutable_group_records(igmp->group_records_size() - 1)->
set_source_count(valueHexStr.toUInt(&isOk, kBaseHex));
else
igmp->set_source_count(valueHexStr.toUInt(&isOk, kBaseHex));
}
else if (name == "igmp.maddr")
{
if (igmp->group_record_count())
igmp->mutable_group_records(igmp->group_records_size() - 1)->
mutable_group_address()->set_v4(
valueHexStr.toUInt(&isOk, kBaseHex));
else
igmp->mutable_group_address()->set_v4(
valueHexStr.toUInt(&isOk, kBaseHex));
}
else if (name == "igmp.saddr")
{
if (igmp->group_record_count())
igmp->mutable_group_records(igmp->group_records_size() - 1)->
add_sources()->set_v4(valueHexStr.toUInt(&isOk, kBaseHex));
else
igmp->add_sources()->set_v4(valueHexStr.toUInt(&isOk, kBaseHex));
}
else if (name == "igmp.aux_data")
{
QByteArray ba = QByteArray::fromHex(
attributes.value("value").toString().toUtf8());
igmp->mutable_group_records(igmp->group_records_size() - 1)->
set_aux_data(ba.constData(), ba.size());
}
}
void PdmlIgmpProtocol::postProtocolHandler(OstProto::Protocol* /*pbProto*/,
OstProto::Stream *stream)
{
// version is 0 for IGMP like protocols such as RGMP which we don't
// support currently
if (version_ == 0)
stream->mutable_protocol()->RemoveLast();
}
// ---------------------------------------------------------- //
// PdmlMldProtocol //
// ---------------------------------------------------------- //
PdmlMldProtocol::PdmlMldProtocol()
{
ostProtoId_ = OstProto::Protocol::kMldFieldNumber;
fieldMap_.insert("icmpv6.code", OstProto::Gmp::kRsvdCodeFieldNumber);
fieldMap_.insert("icmpv6.checksum", OstProto::Gmp::kChecksumFieldNumber);
fieldMap_.insert("icmpv6.mld.maximum_response_delay",
OstProto::Gmp::kMaxResponseTimeFieldNumber); // FIXME
fieldMap_.insert("icmpv6.mld.flag.s", OstProto::Gmp::kSFlagFieldNumber);
fieldMap_.insert("icmpv6.mld.flag.qrv", OstProto::Gmp::kQrvFieldNumber);
fieldMap_.insert("icmpv6.mld.qqi", OstProto::Gmp::kQqiFieldNumber); // FIXME
fieldMap_.insert("icmpv6.mld.nb_sources",
OstProto::Gmp::kSourceCountFieldNumber);
fieldMap_.insert("icmpv6.mldr.nb_mcast_records",
OstProto::Gmp::kGroupRecordCountFieldNumber);
}
PdmlProtocol* PdmlMldProtocol::createInstance()
{
return new PdmlMldProtocol();
}
void PdmlMldProtocol::preProtocolHandler(QString /*name*/,
const QXmlStreamAttributes &attributes, int /*expectedPos*/,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
bool isOk;
OstProto::Gmp *mld = pbProto->MutableExtension(OstProto::mld);
mld->set_is_override_rsvd_code(true);
mld->set_is_override_checksum(true);
mld->set_is_override_source_count(true);
mld->set_is_override_group_record_count(true);
protoSize_ = attributes.value("size").toString().toUInt(&isOk);
}
void PdmlMldProtocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
bool isOk;
OstProto::Gmp *mld = pbProto->MutableExtension(OstProto::mld);
QString valueHexStr = attributes.value("value").toString();
if (name == "icmpv6.type")
{
uint type = valueHexStr.toUInt(&isOk, kBaseHex);
if ((type == kMldQuery) && (protoSize_ >= 28))
type = kMldV2Query;
mld->set_type(type);
}
else if (name == "icmpv6.mld.multicast_address")
{
mld->mutable_group_address()->set_v6_hi(
valueHexStr.left(16).toULongLong(&isOk, kBaseHex));
mld->mutable_group_address()->set_v6_lo(
valueHexStr.right(16).toULongLong(&isOk, kBaseHex));
}
else if (name == "icmpv6.mld.source_address")
{
OstProto::Gmp::IpAddress *ip = mld->add_sources();
ip->set_v6_hi(valueHexStr.left(16).toULongLong(&isOk, kBaseHex));
ip->set_v6_lo(valueHexStr.right(16).toULongLong(&isOk, kBaseHex));
}
else if (name == "icmpv6.mldr.mar.record_type")
{
OstProto::Gmp::GroupRecord *rec = mld->add_group_records();
rec->set_type(OstProto::Gmp::GroupRecord::RecordType(
valueHexStr.toUInt(&isOk, kBaseHex)));
rec->set_is_override_source_count(true);
rec->set_is_override_aux_data_length(true);
}
else if (name == "icmpv6.mldr.mar.aux_data_len")
{
mld->mutable_group_records(mld->group_records_size() - 1)->
set_aux_data_length(valueHexStr.toUInt(&isOk, kBaseHex));
}
else if (name == "icmpv6.mldr.mar.nb_sources")
{
mld->mutable_group_records(mld->group_records_size() - 1)->
set_source_count(valueHexStr.toUInt(&isOk, kBaseHex));
}
else if (name == "icmpv6.mldr.mar.multicast_address")
{
OstProto::Gmp::IpAddress *ip = mld->mutable_group_records(
mld->group_records_size() - 1)->mutable_group_address();
ip->set_v6_hi(valueHexStr.left(16).toULongLong(&isOk, kBaseHex));
ip->set_v6_lo(valueHexStr.right(16).toULongLong(&isOk, kBaseHex));
}
else if (name == "icmpv6.mldr.mar.source_address")
{
OstProto::Gmp::IpAddress *ip = mld->mutable_group_records(
mld->group_records_size() - 1)->add_sources();
ip->set_v6_hi(valueHexStr.left(16).toULongLong(&isOk, kBaseHex));
ip->set_v6_lo(valueHexStr.right(16).toULongLong(&isOk, kBaseHex));
}
else if (name == "icmpv6.mldr.mar.auxiliary_data")
{
QByteArray ba = QByteArray::fromHex(
attributes.value("value").toString().toUtf8());
mld->mutable_group_records(mld->group_records_size() - 1)->
set_aux_data(ba.constData(), ba.size());
}
}
// ---------------------------------------------------------- //
// PdmlTcpProtocol //
// ---------------------------------------------------------- //
PdmlTcpProtocol::PdmlTcpProtocol()
{
ostProtoId_ = OstProto::Protocol::kTcpFieldNumber;
fieldMap_.insert("tcp.srcport", OstProto::Tcp::kSrcPortFieldNumber);
fieldMap_.insert("tcp.dstport", OstProto::Tcp::kDstPortFieldNumber);
fieldMap_.insert("tcp.seq", OstProto::Tcp::kSeqNumFieldNumber);
fieldMap_.insert("tcp.ack", OstProto::Tcp::kAckNumFieldNumber);
fieldMap_.insert("tcp.hdr_len", OstProto::Tcp::kHdrlenRsvdFieldNumber);
fieldMap_.insert("tcp.flags", OstProto::Tcp::kFlagsFieldNumber);
fieldMap_.insert("tcp.window_size", OstProto::Tcp::kWindowFieldNumber);
fieldMap_.insert("tcp.checksum", OstProto::Tcp::kCksumFieldNumber);
fieldMap_.insert("tcp.urgent_pointer", OstProto::Tcp::kUrgPtrFieldNumber);
}
PdmlProtocol* PdmlTcpProtocol::createInstance()
{
return new PdmlTcpProtocol();
}
void PdmlTcpProtocol::unknownFieldHandler(QString name, int /*pos*/,
int /*size*/, const QXmlStreamAttributes &attributes,
OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/)
{
if (name == "tcp.options")
options_ = QByteArray::fromHex(attributes.value("value").toString().toUtf8());
else if (name == "")
{
if (attributes.value("show").toString().startsWith("Acknowledgement number"))
{
bool isOk;
OstProto::Tcp *tcp = pbProto->MutableExtension(OstProto::tcp);
tcp->set_ack_num(attributes.value("value").toString().toUInt(&isOk, kBaseHex));
}
#if 0
else if (attributes.value("show").toString().startsWith("TCP segment data"))
{
segmentData_ = QByteArray::fromHex(attributes.value("value").toString().toUtf8());
stream->mutable_core()->mutable_name()->insert(0,
segmentData_.constData(), segmentData_.size());
}
#endif
}
}
void PdmlTcpProtocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream *stream)
{
OstProto::Tcp *tcp = pbProto->MutableExtension(OstProto::tcp);
qDebug("Tcp: post\n");
tcp->set_is_override_src_port(true);
tcp->set_is_override_dst_port(true);
tcp->set_is_override_hdrlen(true);
tcp->set_is_override_cksum(true);
if (options_.size())
{
OstProto::Protocol *proto = stream->add_protocol();
proto->mutable_protocol_id()->set_id(
OstProto::Protocol::kHexDumpFieldNumber);
OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump);
hexDump->mutable_content()->append(options_.constData(),
options_.size());
hexDump->set_pad_until_end(false);
options_.resize(0);
}
}
// ---------------------------------------------------------- //
// PdmlUdpProtocol //
// ---------------------------------------------------------- //
PdmlUdpProtocol::PdmlUdpProtocol()
{
ostProtoId_ = OstProto::Protocol::kUdpFieldNumber;
fieldMap_.insert("udp.srcport", OstProto::Udp::kSrcPortFieldNumber);
fieldMap_.insert("udp.dstport", OstProto::Udp::kDstPortFieldNumber);
fieldMap_.insert("udp.length", OstProto::Udp::kTotlenFieldNumber);
fieldMap_.insert("udp.checksum_coverage",
OstProto::Udp::kTotlenFieldNumber);
fieldMap_.insert("udp.checksum", OstProto::Udp::kCksumFieldNumber);
}
PdmlProtocol* PdmlUdpProtocol::createInstance()
{
return new PdmlUdpProtocol();
}
void PdmlUdpProtocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream* /*stream*/)
{
OstProto::Udp *udp = pbProto->MutableExtension(OstProto::udp);
qDebug("Udp: post\n");
udp->set_is_override_src_port(true);
udp->set_is_override_dst_port(true);
udp->set_is_override_totlen(true);
udp->set_is_override_cksum(true);
}
// ---------------------------------------------------------- //
// PdmlTextProtocol //
// ---------------------------------------------------------- //
PdmlTextProtocol::PdmlTextProtocol()
{
ostProtoId_ = OstProto::Protocol::kTextProtocolFieldNumber;
}
PdmlProtocol* PdmlTextProtocol::createInstance()
{
return new PdmlTextProtocol();
}
void PdmlTextProtocol::preProtocolHandler(QString /*name*/,
const QXmlStreamAttributes &attributes, int expectedPos,
OstProto::Protocol *pbProto, OstProto::Stream *stream)
{
bool isOk;
int size;
int pos = attributes.value("pos").toString().toUInt(&isOk);
if (!isOk)
{
if (expectedPos >= 0)
expPos_ = pos = expectedPos;
else
goto _skip_pos_size_proc;
}
size = attributes.value("size").toString().toUInt(&isOk);
if (!isOk)
goto _skip_pos_size_proc;
// If pos+size goes beyond the frame length, this is a "reassembled"
// protocol and should be skipped
if ((pos + size) > int(stream->core().frame_len()))
goto _skip_pos_size_proc;
expPos_ = pos;
endPos_ = expPos_ + size;
_skip_pos_size_proc:
qDebug("expPos_ = %d, endPos_ = %d", expPos_, endPos_);
OstProto::TextProtocol *text = pbProto->MutableExtension(
OstProto::textProtocol);
text->set_port_num(0);
text->set_eol(OstProto::TextProtocol::kCrLf); // by default we assume CRLF
detectEol_ = true;
contentType_ = kUnknownContent;
}
void PdmlTextProtocol::unknownFieldHandler(QString name, int pos, int size,
const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto,
OstProto::Stream* /*stream*/)
{
_retry:
switch(contentType_)
{
case kUnknownContent:
if (name == "data")
contentType_ = kOtherContent;
else
contentType_ = kTextContent;
goto _retry;
break;
case kTextContent:
{
OstProto::TextProtocol *text = pbProto->MutableExtension(
OstProto::textProtocol);
if ((name == "data")
|| (attributes.value("show") == "HTTP chunked response"))
{
contentType_ = kOtherContent;
goto _retry;
}
if (pos < expPos_)
break;
if ((pos + size) > endPos_)
break;
if (pos > expPos_)
{
int gap = pos - expPos_;
QByteArray filler(gap, '\n');
if (text->eol() == OstProto::TextProtocol::kCrLf)
{
if (gap & 0x01) // Odd
{
filler.resize(gap/2 + 1);
filler[0]=int(' ');
}
else // Even
filler.resize(gap/2);
}
text->mutable_text()->append(filler.constData(), filler.size());
expPos_ += gap;
}
QByteArray line = QByteArray::fromHex(
attributes.value("value").toString().toUtf8());
if (detectEol_)
{
if (line.right(2) == "\r\n")
text->set_eol(OstProto::TextProtocol::kCrLf);
else if (line.right(1) == "\r")
text->set_eol(OstProto::TextProtocol::kCr);
else if (line.right(1) == "\n")
text->set_eol(OstProto::TextProtocol::kLf);
detectEol_ = false;
}
// Convert line endings to LF only - Qt reqmt that TextProto honours
line.replace("\r\n", "\n");
line.replace('\r', '\n');
text->mutable_text()->append(line.constData(), line.size());
expPos_ += size;
break;
}
case kOtherContent:
// Do nothing!
break;
default:
Q_ASSERT(false);
}
}
void PdmlTextProtocol::postProtocolHandler(OstProto::Protocol *pbProto,
OstProto::Stream *stream)
{
OstProto::TextProtocol *text = pbProto->MutableExtension(
OstProto::textProtocol);
// Empty Text Content - remove ourselves
if (text->text().length() == 0)
stream->mutable_protocol()->RemoveLast();
expPos_ = endPos_ = -1;
detectEol_ = true;
contentType_ = kUnknownContent;
}