diff options
Diffstat (limited to 'pcapspice.py')
-rw-r--r-- | pcapspice.py | 178 |
1 files changed, 45 insertions, 133 deletions
diff --git a/pcapspice.py b/pcapspice.py index b1c1e96..05a5bef 100644 --- a/pcapspice.py +++ b/pcapspice.py @@ -1,24 +1,27 @@ from itertools import chain, repeat -from pcaputil import (tcp_parse, is_tcp, is_tcp_data, is_tcp_syn, - conversations_iter, header_conversation_iter) -import client +import logging + +from pcaputil import header_conversation_iter +import client_proto from client import SpiceLinkHeader, SpiceLinkMess, SpiceLinkReply, SpiceDataHeader +logger = logging.getLogger('pcapspice') + def is_single_packet_data(payload): return len(payload) == SpiceDataHeader(payload).e.size + SpiceDataHeader.size num_spice_messages = sum(len(ch.client) + len(ch.server) for ch in - client.client_proto.channels.values()) + client_proto.channels.values()) valid_message_ids = set(sum([ch.client.keys() + ch.server.keys() for ch in - client.client_proto.channels.values()], [])) + client_proto.channels.values()], [])) -all_channels = client.client_proto.channels.keys() +all_channels = client_proto.channels.keys() def possible_channels(server_message, header): return set(c for c in all_channels if header.e.type in - (client.client_proto.channels[c].server.keys() if server_message - else client.client_proto.channels[c].client.keys())) + (client_proto.channels[c].server.keys() if server_message + else client_proto.channels[c].client.keys())) guesses = {} @@ -34,140 +37,49 @@ def guess_channel_iter(): seen_headers.append((src, dst, data_header)) optional_channels = optional_channels & possible_channels( src == min(src, dst), data_header) - print optional_channels + logger.debug(str(optional_channels)) if len(optional_channels) == 1: channel = list(optional_channels)[0] guesses[key] = channel if len(optional_channels) == 0: import pdb; pdb.set_trace() -spice_size_from_header = lambda header: header.e.size - -def channel_spice_start_iter(lower_port, higher_port): - server_port, client_port = lower_port, higher_port - ports = [server_port, client_port] - messages = dict([(port,None) for port in ports]) - payloads = dict([(port,[]) for port in ports]) - headers = dict([(port,None) for port in ports]) - discarded_len = {client_port:128, server_port:4} - message_ctors = {client_port:SpiceLinkMess, server_port:SpiceLinkReply} - if len(payload) > 0: - payloads[src].append(payload) - while not all(messages.values()): - src, dst, payload = yield None - if len(payload) == 0: continue - payloads[src].append(payload) - len_payload = sum(map(len,payloads[src])) - if headers[src] is None and len_payload >= SpiceLinkHeader.size: - headers[src] = SpiceLinkHeader(''.join(payloads[src])) - import pdb; pdb.set_trace() - expected_len = headers[src].e.size + SpiceLinkHeader.size + discarded_len[src] - if headers[src] is not None and expected_len <= len_payload: - if expected_len != len_payload: - print "extra bytes dumped!!! %d" % (len_payload - expected_len) - messages[src] = message_ctors[src](''.join(payloads[src])[ - SpiceLinkHeader.size:]) - channel = messages[client_port].e.channel_type - print "channel type %s created" % channel - result = None - src, dst, payload = yield None - data_iter = channel_spice_iter(src, dst, payload, channel=channel) - result = data_iter.next() - while True: - src, dst, payload = yield result - result = data_iter.send((src, dst, payload)) - -def channel_spice_iter(lower_port, higher_port, channel=None): - server_port, client_port = lower_port, higher_port - serial = {} - guesser = guess_channel_iter() - guesser.next() - - result = None - # yield spice data parsed results - while True: - src, dst, payload = yield result - data_header = SpiceDataHeader(payload) - # basic sanity check on the header - bad_header = False - if serial.has_key(src): - if data_header.e.serial != serial[src] + 1: - print "bad serial, replacing for %s->%s (%s!=%s+1)" % ( - src, dst, data_header.e.serial, serial[src]) - bad_header = True - serial[src] = data_header.e.serial - if data_header.e.type not in valid_message_ids: - print "bad message type %s in %s->%s" % (data_header.e.type, - src, dst) - if bad_header: continue - if channel is None: - channel = guesser.send((src, dst, data_header)) - if channel is not None: - # read as many messages as it takes to get - (msg_proto, (result_name, result_value), - left_over) = client.client_proto.parse( - channel_type=channel, - is_client=src == client_port, - header=data_header, - data=payload[SpiceDataHeader.size:]) - result = (data_header, msg_proto, result_name, result_value, - left_over) - -# for every tcp packet -# if it is a syn, read the link header, decide which channel we are -# if it is data -# if we know which channel we are, parse it -# else guess which channel. -# if we just figured out which channel we are, releaes all pending packets. - -def spice_iter1(packet_iter): - return conversations_iter( - packet_iter, - channel_spice_start_iter, - channel_spice_iter) - -def packet_header_iter_gen(hdr_ctor, pkt_ctor): - return repeat( - (hdr_ctor.size, - hdr_ctor, - lambda h: h.e.size, - pkt_ctor)) - def ident(x, **kw): return x def channel_spice_message_iter(src, dst, guesser): + """ coroutine, accepts (src,dst,header,data) packets + and yields maybe parsed spice results. + + maybe X - returns None or X + """ server_port, client_port = min(src, dst), max(src, dst) serial = {} channel = None result = None - # yield spice data parsed results while True: src, dst, (data_header, message) = yield result - # basic sanity check on the header + result = None bad_header = False if serial.has_key(src): if data_header.e.serial != serial[src] + 1: - print "bad serial, replacing for %s->%s (%s!=%s+1)" % ( - src, dst, data_header.e.serial, serial[src]) + logger.debug("bad serial, replacing for %s->%s (%s!=%s+1)" % ( + src, dst, data_header.e.serial, serial[src])) bad_header = True serial[src] = data_header.e.serial if data_header.e.type not in valid_message_ids: - print "bad message type %s in %s->%s" % (data_header.e.type, - src, dst) + logger.error("bad message type %s in %s->%s" % (data_header.e.type, + src, dst)) bad_header = True if bad_header: continue - if channel is None: - channel = guesser.send((src, dst, data_header)) + channel = guesser.send((src, dst, data_header)) if channel is not None: # read as many messages as it takes to get - (msg_proto, (result_name, result_value) - ) = client.client_proto.parse( - channel_type=channel, - is_client=src == client_port, - header=data_header, - data=message) - result = (msg_proto, result_name, result_value) + result = client_proto.parse( + channel_type=channel, + is_client=src == client_port, + header=data_header, + data=message) class ChannelGuesser(object): @@ -177,13 +89,15 @@ class ChannelGuesser(object): self.channel = None def send(self, (src, dst, payload)): - if self.channel: return self.channel - return self.iter.send((src, dst, payload)) + if self.channel: + return self.channel + self.channel = self.iter.send((src, dst, payload)) + return self.channel def on_client_link_message(self, p, **kw): self._client_message = SpiceLinkMess(p) self.channel = self._client_message.e.channel_type - print "STARTED channel %s" % self.channel + logger.info("STARTED channel %s" % self.channel) def on_server_link_message(self, p, **kw): self._server_message = SpiceLinkReply(p) @@ -194,37 +108,35 @@ def spice_iter(packet_iter): is_server = src < dst key = (min(src, dst), max(src, dst)) guesser = guessers[key] = guessers.get(key, ChannelGuesser()) - print guesser, is_server, "**** make_start_iter %s -> %s" % (src, dst) + logger.debug('%s %s **** make_start_iter %s -> %s' %( guesser, is_server, src, dst)) link_messages = [] yield (SpiceLinkHeader.size, SpiceLinkHeader.verify, lambda h: h.e.size, (guesser.on_server_link_message if is_server else guesser.on_client_link_message)) - print guesser, is_server, "2" - message_iter = channel_spice_message_iter(src, dst, guesser) - message_iter.next() - # TODO: way to say "src->dst 128, dst->src 4" + logger.debug('%s %s 2' % (guesser, is_server)) yield 128 if src > dst else 4, ident, lambda h: 0, ident - for i, data in enumerate(packet_header_iter_gen( - SpiceDataHeader, - lambda pkt, src, dst, header: - message_iter.send((src, dst, (header, pkt))))): - print guesser, is_server, "2+%s" % i + for i, data in enumerate(make_iter(src, dst)): + logger.debug('%s %s 2+%s' % (guesser, is_server, i)) yield data def make_iter(src, dst): key = (min(src, dst), max(src, dst)) guesser = guessers[key] = guessers.get(key, ChannelGuesser()) message_iter = channel_spice_message_iter(src, dst, guesser) message_iter.next() - return packet_header_iter_gen( - SpiceDataHeader, + return repeat( + (SpiceDataHeader.size, + SpiceDataHeader.verify, + lambda h: h.e.size, lambda pkt, src, dst, header: - message_iter.send((src, dst, (header, pkt)))) + message_iter.send((src, dst, (header, pkt))))) return header_conversation_iter( packet_iter, server_start=make_start_iter, client_start=make_start_iter, server=make_iter, - client=make_iter) + client=make_iter, + filter_result=lambda r: (r.msg is not None and r.msg.data != None + and hasattr(r.msg.data, 'result_name'))) |