diff options
author | Gilbert Ramirez <gram@alumni.rice.edu> | 2003-12-06 06:09:13 +0000 |
---|---|---|
committer | Gilbert Ramirez <gram@alumni.rice.edu> | 2003-12-06 06:09:13 +0000 |
commit | 058ef64db8ce40909a18c91ab4805804362f80cb (patch) | |
tree | 767a7824daa712556971559e29e563658d643d51 /tools/EtherealXML.py | |
parent | 33b25ac15eac2e2cb4269377c41eada622c81fc1 (diff) |
Add the ability to print packet dissections in PDML (an XML-based format)
to tethereal. It could be added to Ethereal, but the GUI changes to
allow the user to select PDML as a print format have not been added.
Provide a python module (EtherealXML.py) to help parse PDML.
Provide a sample app (msnchat) which uses tethereal and EtherealXML.py
to reconstruct MSN Chat sessions from packet capture files. It produces
a nice HTML report of the chat sessions.
Document tethereal's PDML and EtherealXML.py usage in doc/README.xml-output
Update tethereal's manpage to reflect the new [-T pdml|ps|text] option
svn path=/trunk/; revision=9180
Diffstat (limited to 'tools/EtherealXML.py')
-rw-r--r-- | tools/EtherealXML.py | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/tools/EtherealXML.py b/tools/EtherealXML.py new file mode 100644 index 0000000000..d75464e84f --- /dev/null +++ b/tools/EtherealXML.py @@ -0,0 +1,275 @@ +""" +Baseclass for reading PDML produced from Tethereal. + +Copyright (c) 2003 by Gilbert Ramirez <gram@alumni.rice.edu> + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" + +import sys +from xml.sax import saxlib +from xml.sax import saxexts +from xml.sax import saxutils + +class CaptureFile: + pass + +class FoundItException(Exception): + pass + +class PacketList: + """Holds Packet objects, and has methods for finding + items within it.""" + + def __init__(self, children=None): + if children == None: + self.children = [] + else: + self.children = children + + def __getitem__(self, index): + """We act like a list.""" + return self.children[index] + + + def item_exists(self, name): + """Does an item with name 'name' exist in this + PacketList?""" + for child in self.children: + if child.name == name: + return 1 + + try: + for child in self.children: + child._item_exists(name) + + except FoundItException: + return 1 + + return 0 + + def _item_exists(self, name): + for child in self.children: + if child.name == name: + raise FoundItException + child._item_exists(name) + + + def get_items(self, name, items=None): + """Return all items that match the name 'name'. + They are returned in order of a depth-first-search.""" + if items == None: + top_level = 1 + items = [] + else: + top_level = 0 + + for child in self.children: + if child.name == name: + items.append(child) + child.get_items(name, items) + + if top_level: + return PacketList(items) + + + +class ProtoTreeItem(PacketList): + def __init__(self, xmlattrs): + PacketList.__init__(self) + + self.name = xmlattrs.get("name", "") + self.showname = xmlattrs.get("showname", "") + self.pos = xmlattrs.get("pos", "") + self.size = xmlattrs.get("size", "") + self.value = xmlattrs.get("value", "") + self.show = xmlattrs.get("show", "") + + def add_child(self, child): + self.children.append(child) + + def get_name(self): + return self.name + + def get_showname(self): + return self.showname + + def get_pos(self): + return self.pos + + def get_size(self): + return self.size + + def get_value(self): + return self.value + + def get_show(self): + return self.show + + def dump(self, fh): + if self.name: + print >> fh, " name=%s" % (saxutils.quoteattr(self.name),), + + if self.showname: + print >> fh, "showname=%s" % (saxutils.quoteattr(self.showname),), + + if self.pos: + print >> fh, "pos=%s" % (saxutils.quoteattr(self.pos),), + + if self.size: + print >> fh, "size=%s" % (saxutils.quoteattr(self.size),), + + if self.value: + print >> fh, "value=%s" % (saxutils.quoteattr(self.value),), + + if self.show: + print >> fh, "show=%s" % (saxutils.quoteattr(self.show),), + +class Packet(ProtoTreeItem, PacketList): + def dump(self, fh, indent=0): + print >> fh, " " * indent, "<packet>" + indent += 1 + for child in self.children: + child.dump(fh, indent) + print >> fh, " " * indent, "</packet>" + + +class Protocol(ProtoTreeItem): + + def dump(self, fh, indent=0): + print >> fh, "%s<proto " % (" " * indent,), + + ProtoTreeItem.dump(self, fh) + + print >> fh, '>' + + indent += 1 + for child in self.children: + child.dump(fh, indent) + print >> fh, " " * indent, "</proto>" + + +class Field(ProtoTreeItem): + + def dump(self, fh, indent=0): + print >> fh, "%s<field " % (" " * indent,), + + ProtoTreeItem.dump(self, fh) + + if self.label: + print >> fh, "label=%s" % (saxutils.quoteattr(self.label),), + + if self.children: + print >> fh, ">" + indent += 1 + for child in self.children: + child.dump(fh, indent) + print >> fh, " " * indent, "</field>" + + else: + print >> fh, "/>" + + +class ParseXML(saxlib.HandlerBase): + + ELEMENT_FILE = "pdml" + ELEMENT_FRAME = "packet" + ELEMENT_PROTOCOL = "proto" + ELEMENT_FIELD = "field" + + def __init__(self, cb): + self.cb = cb + self.chars = "" + self.element_stack = [] + + def startElement(self, name, xmlattrs): + self.chars = "" + + if name == self.ELEMENT_FILE: + # Eventually, we should check version number of pdml here + elem = CaptureFile() + + elif name == self.ELEMENT_FRAME: + elem = Packet(xmlattrs) + + elif name == self.ELEMENT_PROTOCOL: + elem = Protocol(xmlattrs) + + elif name == self.ELEMENT_FIELD: + elem = Field(xmlattrs) + + else: + sys.exit("Unknown element: %s" % (name,)) + + self.element_stack.append(elem) + + + def endElement(self, name): + elem = self.element_stack.pop() + +# if isinstance(elem, Field): +# if elem.get_name() == "frame.number": +# print >> sys.stderr, "Packet:", elem.get_show() + + # Add element as child to previous element as long + # as there is more than 1 element in the stack. Only + # one element in the stack means that the the element in + # the stack is the single CaptureFile element, and we don't + # want to add this element to that, as we only want one + # Packet element in memory at a time. + if len(self.element_stack) > 1: + parent_elem = self.element_stack[-1] + parent_elem.add_child(elem) + + self.chars = "" + + # If we just finished a Packet element, hand it to the + # user's callback. + if isinstance(elem, Packet): + self.cb(elem) + + def characters(self, chars, start, length): + self.chars = self.chars + chars[start:start+length] + + +def parse_fh(fh, cb): + + # Create a parser + parser = saxexts.make_parser() + + # Create the handler + ch = ParseXML(cb) + + # Tell the parser to use our handler + parser.setDocumentHandler(ch) + + # Parse the file + parser.parseFile(fh) + + # Close the parser + parser.close() + +def _test(): + import sys + + def test_cb(obj): + pass + + filename = sys.argv[1] + fh = open(filename, "r") + parse_fh(fh, test_cb) + +if __name__ == '__main__': + _test() |