summaryrefslogtreecommitdiffstats
path: root/tools/msnchat
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /tools/msnchat
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/msnchat')
-rwxr-xr-xtools/msnchat315
1 files changed, 315 insertions, 0 deletions
diff --git a/tools/msnchat b/tools/msnchat
new file mode 100755
index 0000000..c2fcaab
--- /dev/null
+++ b/tools/msnchat
@@ -0,0 +1,315 @@
+#!/usr/bin/env python
+"""
+Process packet capture files and produce a nice HTML
+report of MSN Chat sessions.
+
+Copyright (c) 2003 by Gilbert Ramirez <gram@alumni.rice.edu>
+
+SPDX-License-Identifier: GPL-2.0-or-later
+"""
+
+import os
+import re
+import sys
+import array
+import string
+import WiresharkXML
+import getopt
+
+# By default we output the HTML to stdout
+out_fh = sys.stdout
+
+class MSNMessage:
+ pass
+
+class MSN_MSG(MSNMessage):
+ def __init__(self, timestamp, user, message):
+ self.timestamp = timestamp
+ self.user = user
+ self.message = message
+
+
+class Conversation:
+ """Keeps track of a single MSN chat session"""
+
+ re_MSG_out = re.compile("MSG (?P<TrID>\d+) (?P<ACKTYPE>[UNA]) (?P<len>\d+)")
+ re_MSG_in = re.compile("MSG (?P<user>\S+)@(?P<domain>\S+) (?P<alias>\S+) (?P<len>\d+)")
+
+ USER_NOT_FOUND = -1
+ DEFAULT_USER = None
+
+
+ DEFAULT_USER_COLOR = "#0000ff"
+ USER_COLORS = [ "#ff0000", "#00ff00",
+ "#800000", "#008000", "#000080" ]
+
+ DEFAULT_USER_TEXT_COLOR = "#000000"
+ USER_TEXT_COLOR = "#000080"
+
+ def __init__(self):
+ self.packets = []
+ self.messages = []
+
+ def AddPacket(self, packet):
+ self.packets.append(packet)
+
+ def Summarize(self):
+ for packet in self.packets:
+ msg = self.CreateMSNMessage(packet)
+ if msg:
+ self.messages.append(msg)
+ else:
+ #XXX
+ pass
+
+
+ def CreateMSNMessage(self, packet):
+ msnms = packet.get_items("msnms")[0]
+
+ # Check the first line in the msnms transmission for the user
+ child = msnms.children[0]
+ user = self.USER_NOT_FOUND
+
+ m = self.re_MSG_out.search(child.show)
+ if m:
+ user = self.DEFAULT_USER
+
+ else:
+ m = self.re_MSG_in.search(child.show)
+ if m:
+ user = m.group("alias")
+
+ if user == self.USER_NOT_FOUND:
+ print >> sys.stderr, "No match for", child.show
+ sys.exit(1)
+ return None
+
+ msg = ""
+
+ i = 5
+ check_trailing = 0
+ if len(msnms.children) > 5:
+ check_trailing = 1
+
+ while i < len(msnms.children):
+ msg += msnms.children[i].show
+ if check_trailing:
+ j = msg.find("MSG ")
+ if j >= 0:
+ msg = msg[:j]
+ i += 5
+ else:
+ i += 6
+ else:
+ i += 6
+
+ timestamp = packet.get_items("frame.time")[0].get_show()
+ i = timestamp.rfind(".")
+ timestamp = timestamp[:i]
+
+ return MSN_MSG(timestamp, user, msg)
+
+ def MsgToHTML(self, text):
+ bytes = array.array("B")
+
+ new_string = text
+ i = new_string.find("\\")
+
+ while i > -1:
+ # At the end?
+ if i == len(new_string) - 1:
+ # Just let the default action
+ # copy everything to 'bytes'
+ break
+
+ if new_string[i+1] in string.digits:
+ left = new_string[:i]
+ bytes.fromstring(left)
+
+ right = new_string[i+4:]
+
+ oct_string = new_string[i+1:i+4]
+ char = int(oct_string, 8)
+ bytes.append(char)
+
+ new_string = right
+
+ # ignore \r and \n
+ elif new_string[i+1] in "rn":
+ copy_these = new_string[:i]
+ bytes.fromstring(copy_these)
+ new_string = new_string[i+2:]
+
+ else:
+ copy_these = new_string[:i+2]
+ bytes.fromstring(copy_these)
+ new_string = new_string[i+2:]
+
+ i = new_string.find("\\")
+
+
+ bytes.fromstring(new_string)
+
+ return bytes
+
+ def CreateHTML(self, default_user):
+ if not self.messages:
+ return
+
+ print >> out_fh, """
+<HR><BR><H3 Align=Center> ---- New Conversation @ %s ----</H3><BR>""" \
+ % (self.messages[0].timestamp)
+
+ user_color_assignments = {}
+
+ for msg in self.messages:
+ # Calculate 'user' and 'user_color' and 'user_text_color'
+ if msg.user == self.DEFAULT_USER:
+ user = default_user
+ user_color = self.DEFAULT_USER_COLOR
+ user_text_color = self.DEFAULT_USER_TEXT_COLOR
+ else:
+ user = msg.user
+ user_text_color = self.USER_TEXT_COLOR
+ if user_color_assignments.has_key(user):
+ user_color = user_color_assignments[user]
+ else:
+ num_assigned = len(user_color_assignments.keys())
+ user_color = self.USER_COLORS[num_assigned]
+ user_color_assignments[user] = user_color
+
+ # "Oct 6, 2003 21:45:25" --> "21:45:25"
+ timestamp = msg.timestamp.split()[-1]
+
+ htmlmsg = self.MsgToHTML(msg.message)
+
+ print >> out_fh, """
+<FONT COLOR="%s"><FONT SIZE="2">(%s) </FONT><B>%s:</B></FONT> <FONT COLOR="%s">""" \
+ % (user_color, timestamp, user, user_text_color)
+
+ htmlmsg.tofile(out_fh)
+
+ print >> out_fh, "</FONT><BR>"
+
+
+class CaptureFile:
+ """Parses a single a capture file and keeps track of
+ all chat sessions in the file."""
+
+ def __init__(self, capture_filename, tshark):
+ """Run tshark on the capture file and parse
+ the data."""
+ self.conversations = []
+ self.conversations_map = {}
+
+ pipe = os.popen(tshark + " -Tpdml -n -R "
+ "'msnms contains \"X-MMS-IM-Format\"' "
+ "-r " + capture_filename, "r")
+
+ WiresharkXML.parse_fh(pipe, self.collect_packets)
+
+ for conv in self.conversations:
+ conv.Summarize()
+
+ def collect_packets(self, packet):
+ """Collect the packets passed back from WiresharkXML.
+ Sort them by TCP/IP conversation, as there could be multiple
+ clients per machine."""
+ # Just in case we're looking at tunnelling protocols where
+ # more than one IP or TCP header exists, look at the last one,
+ # which would be the one inside the tunnel.
+ src_ip = packet.get_items("ip.src")[-1].get_show()
+ dst_ip = packet.get_items("ip.dst")[-1].get_show()
+ src_tcp = packet.get_items("tcp.srcport")[-1].get_show()
+ dst_tcp = packet.get_items("tcp.dstport")[-1].get_show()
+
+ key_params = [src_ip, dst_ip, src_tcp, dst_tcp]
+ key_params.sort()
+ key = '|'.join(key_params)
+
+ if not self.conversations_map.has_key(key):
+ conv = self.conversations_map[key] = Conversation()
+ self.conversations.append(conv)
+ else:
+ conv = self.conversations_map[key]
+
+ conv.AddPacket(packet)
+
+
+ def CreateHTML(self, default_user):
+ if not self.conversations:
+ return
+
+ for conv in self.conversations:
+ conv.CreateHTML(default_user)
+
+
+def run_filename(filename, default_user, tshark):
+ """Process one capture file."""
+
+ capture = CaptureFile(filename, tshark)
+ capture.CreateHTML(default_user)
+
+
+def run(filenames, default_user, tshark):
+ # HTML Header
+ print >> out_fh, """
+<HTML><TITLE>MSN Conversation</TITLE>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<BODY>
+"""
+ for filename in filenames:
+ run_filename(filename, default_user, tshark)
+
+ # HTML Footer
+ print >> out_fh, """
+<HR>
+</BODY>
+</HTML>
+"""
+
+
+def usage():
+ print >> sys.stderr, "msnchat [OPTIONS] CAPTURE_FILE [...]"
+ print >> sys.stderr, " -o FILE name of output file"
+ print >> sys.stderr, " -t TSHARK location of tshark binary"
+ print >> sys.stderr, " -u USER name for unknown user"
+ sys.exit(1)
+
+def main():
+ default_user = "Unknown"
+ tshark = "tshark"
+
+ optstring = "ho:t:u:"
+ longopts = ["help"]
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], optstring, longopts)
+ except getopt.GetoptError:
+ usage()
+
+ for opt, arg in opts:
+ if opt == "-h" or opt == "--help":
+ usage()
+
+ elif opt == "-o":
+ filename = arg
+ global out_fh
+ try:
+ out_fh = open(filename, "w")
+ except IOError:
+ sys.exit("Could not open %s for writing." % (filename,))
+
+ elif opt == "-u":
+ default_user = arg
+
+ elif opt == "-t":
+ tshark = arg
+
+ else:
+ sys.exit("Unhandled command-line option: " + opt)
+
+ run(args, default_user, tshark)
+
+if __name__ == '__main__':
+ main()