220 lines
7.0 KiB
Python
220 lines
7.0 KiB
Python
#!/usr/bin/python
|
|
|
|
import sys, os
|
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..', '..', '..', '..')))
|
|
|
|
from optparse import OptionParser
|
|
import binascii
|
|
import re
|
|
import traceback
|
|
from pyogp.lib.base.message.udpdeserializer import UDPPacketDeserializer
|
|
from logging import getLogger, StreamHandler, Formatter, CRITICAL, ERROR, WARNING, INFO, DEBUG
|
|
|
|
logger = getLogger('parse_packet')
|
|
log = logger.log
|
|
|
|
class parsingStats(object):
|
|
|
|
#Todo: for this standalone script, move this class instance to global, move logging to the class itself
|
|
|
|
def __init__(self):
|
|
|
|
self.total = 0
|
|
self.success = 0
|
|
self.fail = 0
|
|
self.packets = {}
|
|
self.failed = []
|
|
|
|
def addSuccess(self, name):
|
|
self.success = self.success + 1
|
|
if self.packets.has_key(name):
|
|
self.packets[name] = self.packets[name] + 1
|
|
else:
|
|
self.packets[name] = 1
|
|
|
|
def addFail(self, data):
|
|
self.fail = self.fail + 1
|
|
self.failed.append(data)
|
|
|
|
def __repr__(self):
|
|
|
|
string = "\n\n-----------------------------\n"
|
|
string = string + " Parsing Summary\n"
|
|
string = string + "-----------------------------\n\n"
|
|
string = string + "Successes\n\n"
|
|
string = string + 'Parsed: %s\n\n' % (self.success)
|
|
for k in self.packets:
|
|
string = string + '%s: %s\n' %(k, self.packets[k])
|
|
string = string + "\n\nFailed to Parse\n\n"
|
|
string = string + 'Failed: %s\n\n' % (self.fail)
|
|
for item in self.failed:
|
|
string = string + '%s\n' %(item)
|
|
|
|
return string
|
|
|
|
|
|
def main():
|
|
|
|
(options) = parse_options()
|
|
|
|
if options.verbose: enable_logging()
|
|
|
|
if options.file:
|
|
stats = parsingStats()
|
|
process_file(options, stats)
|
|
print stats
|
|
else:
|
|
process_stream(options.data)
|
|
|
|
def process_file(options, stats):
|
|
|
|
if options.wireshark:
|
|
handle = open(options.file,"r")
|
|
# normal hex file, 1 packet of hex per line
|
|
lines = handle.readlines
|
|
handle.close()
|
|
isSLclientpacket = False
|
|
isSLsimpacket = False
|
|
packetSource = ''
|
|
|
|
if options.count > 0:
|
|
counter = 0.0
|
|
linecount = len(lines)
|
|
markers = [10,20,30,40,50,60,70,80,90,100]
|
|
|
|
log(INFO, 'Processing %s of up to %s packets' % (options.count, linecount))
|
|
|
|
percent = 0.0
|
|
for line in lines:
|
|
if percent == 100: break
|
|
if re.search('udp.srcport', line) and re.search('1300[0-9]', line):
|
|
isSLsimpacket = True
|
|
packetSource = 'Simulator'
|
|
continue
|
|
if re.search('udp.dstport', line) and re.search('1300[0-9]', line):
|
|
isSLclientpacket = True
|
|
packetSource = 'Client'
|
|
continue
|
|
if (isSLclientpacket == True or isSLsimpacket == True):
|
|
if re.search('field name="data"', line):
|
|
if options.count > 0:
|
|
percent = (counter/float(options.count)) * 100
|
|
#log(INFO, "%s percent complete... (%s of %s)" % (percent, counter, options.count))
|
|
if (percent) in markers:
|
|
log(INFO, "%s percent complete... (%s of %s)" % (int(percent), counter, options.count))
|
|
counter += 1
|
|
items = line.split()
|
|
process_stream(items[2][7:len(items[2])-3], packetSource, stats)
|
|
isSLclientpacket = False
|
|
isSLsimpacket = False
|
|
|
|
else:
|
|
handle = open(options.file,"r")
|
|
# normal hex file, 1 packet of hex per line
|
|
lines = handle.readlines()
|
|
for line in lines:
|
|
process_stream(line.strip())
|
|
|
|
def process_wiresharkpacket(packet):
|
|
|
|
print packet.__dict__
|
|
|
|
|
|
def process_stream(data, source=None, stats = None):
|
|
|
|
msg_buff = gen_message_buffer(data)
|
|
|
|
if msg_buff != None:
|
|
try:
|
|
deserializer = UDPPacketDeserializer(msg_buff)
|
|
packet = deserializer.deserialize()
|
|
display_packet(packet, data, source)
|
|
if stats != None:
|
|
stats.addSuccess(packet.name)
|
|
except Exception, e:
|
|
print 'Unable to parse data "%s" due to: %s' % (data, e)
|
|
traceback.print_exc()
|
|
if stats != None:
|
|
stats.addFail(data)
|
|
else:
|
|
print 'Skipping empty message buffer'
|
|
|
|
def parse_options():
|
|
|
|
parser = OptionParser()
|
|
|
|
#parser.add_option("-t", "--type", dest="datatype", default="hex", help="datatype to parse, default = hex")
|
|
parser.add_option("-d", "--data", dest="data", help="data to parse")
|
|
parser.add_option("-v", "--verbose", dest="verbose", default=True, action="store_false")
|
|
parser.add_option("-f", "--file", dest="file", help="parse data located in file")
|
|
parser.add_option("-w", "--wireshark", dest="wireshark", default=False, action="store_true", help="specifies file to parse is a wireshark pdml dump")
|
|
parser.add_option("-c", "--count", dest="count", default=0, help="how many packets to process from a file")
|
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
if options.wireshark and not options.file:
|
|
print "Cannot parse as wireshark and not pass a file in..."
|
|
sys.exit(-1)
|
|
|
|
return options
|
|
|
|
def gen_message_buffer(data, datatype='hex'):
|
|
|
|
if datatype == 'hex':
|
|
return message_buff_from_hex(data.strip())
|
|
|
|
return
|
|
|
|
def message_buff_from_hex(data):
|
|
|
|
try:
|
|
parsed = binascii.unhexlify(''.join(data.split()))
|
|
return parsed
|
|
except:
|
|
print 'Error parsing data: %s' % (data)
|
|
return None
|
|
|
|
def display_packet(packet, data, source=None):
|
|
|
|
sourcestring = ''
|
|
if source != None:
|
|
sourcestring = ' (from %s)' % (source)
|
|
|
|
print "~~~~~~~~~~~~~~~~~~~"
|
|
print "Source data%s:" % (sourcestring)
|
|
print data
|
|
print "~~~~~~~~~~~~~~~~~~~"
|
|
delim = " "
|
|
print 'Packet Name:%s%s' % (delim, packet.name)
|
|
|
|
for k in packet.__dict__:
|
|
|
|
if k == 'name': pass
|
|
if k == 'message_data':
|
|
print k
|
|
for ablock in packet.message_data.blocks:
|
|
print "%sBlock Name:%s%s" % (delim, delim, ablock)
|
|
for somevars in packet.message_data.blocks[ablock]:
|
|
|
|
for avar in somevars.var_list:
|
|
zvar = somevars.get_variable(avar)
|
|
print "%s%s%s:%s%s" % (delim, delim, zvar.name, delim, zvar)
|
|
|
|
print "~~~~~~~~~~~~~~~~~~~"
|
|
|
|
def enable_logging():
|
|
|
|
console = StreamHandler()
|
|
console.setLevel(DEBUG) # seems to be a no op, set it for the logger
|
|
formatter = Formatter('%(name)-30s: %(levelname)-8s %(message)s')
|
|
console.setFormatter(formatter)
|
|
getLogger('').addHandler(console)
|
|
|
|
# setting the level for the handler above seems to be a no-op
|
|
# it needs to be set for the logger, here the root logger
|
|
# otherwise it is NOTSET(=0) which means to log nothing.
|
|
getLogger('').setLevel(DEBUG)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|