summaryrefslogtreecommitdiff
path: root/pcapspice.py
diff options
context:
space:
mode:
Diffstat (limited to 'pcapspice.py')
-rw-r--r--pcapspice.py178
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')))