Refactored demux and resequence into new class

This commit is contained in:
Neale Pickett 2008-07-21 22:24:36 -06:00
parent ef0b4ac1e3
commit 8c69a8933e
1 changed files with 78 additions and 53 deletions

131
ip.py
View File

@ -10,6 +10,7 @@ import warnings
import heapq import heapq
import gapstr import gapstr
import time import time
import pcap
import UserDict import UserDict
from __init__ import * from __init__ import *
@ -250,6 +251,7 @@ class TCP_Resequence:
self.pending = [{}, {}] self.pending = [{}, {}]
self.frames = 0 self.frames = 0
self.closed = 0 self.closed = 0
self.midstream = False
self.handle = self.handle_handshake self.handle = self.handle_handshake
@ -282,6 +284,8 @@ class TCP_Resequence:
self.handle = self.handle_packet self.handle = self.handle_packet
else: else:
# In the middle of a session, do the best we can # In the middle of a session, do the best we can
warnings.warn('Starting mid-stream')
self.midstream = True
self.cli, self.srv = pkt.src, pkt.dst self.cli, self.srv = pkt.src, pkt.dst
self.seq = [pkt.seq, pkt.ack] self.seq = [pkt.seq, pkt.ack]
self.handle = self.handle_packet self.handle = self.handle_packet
@ -332,50 +336,56 @@ class TCP_Resequence:
warnings.warn('Spurious frame after shutdown: %r %d' % (pkt, pkt.flags)) warnings.warn('Spurious frame after shutdown: %r %d' % (pkt, pkt.flags))
def resequence(pc): class Resequence:
"""Re-sequence from a pcap stream. def __init__(self, *filenames):
self.pcs = {}
>>> p = pcap.open('whatever.pcap') self.sessions = {}
>>> for chunk in resequence(p): self.tops = []
... print `chunk`
""" self.last = None
sessions = {} for fn in filenames:
for pkt in pc: self.open(fn)
f = Frame(pkt)
if f.protocol == TCP:
# compute TCP session hash
tcp_sess = sessions.get(f.hash)
if not tcp_sess:
tcp_sess = TCP_Resequence()
sessions[f.hash] = tcp_sess
chunk = tcp_sess.handle(f)
if chunk:
yield chunk
def demux(*pcs): def open(self, filename, literal=False):
"""Demultiplex pcap objects based on time. if not literal:
parts = filename.split(':::')
fn = parts[0]
fd = file(fn)
pc = pcap.open(fd)
if len(parts) > 1:
pos = int(parts[1])
fd.seek(pos)
self._read(pc, fn, fd)
else:
fd = file(filename)
pc = pcap.open(fd)
self._read(pc, filename, fd)
This is iterable just like a pcap object, so you could for instance do: def _read(self, pc, filename, fd):
pos = fd.tell()
>>> resequence(demux(pcap1, pcap2, pcap3)) pkt = pc.read()
if pkt:
""" heapq.heappush(self.tops, (pkt, pc, filename, fd, pos))
tops = []
for pc in pcs:
frame = pc.read()
if frame:
heapq.heappush(tops, (frame, pc))
while tops:
frame, pc = heapq.heappop(tops)
yield frame
frame = pc.read()
if frame:
heapq.heappush(tops, (frame, pc))
def __iter__(self):
while self.tops:
pkt, pc, filename, fd, pos = heapq.heappop(self.tops)
if not self.last:
self.last = (filename, pos)
frame = Frame(pkt)
if frame.protocol == TCP:
# compute TCP session hash
tcp_sess = self.sessions.get(frame.hash)
if not tcp_sess:
tcp_sess = TCP_Resequence()
self.sessions[frame.hash] = tcp_sess
chunk = tcp_sess.handle(frame)
if chunk:
yield chunk
self.last = None
self._read(pc, filename, fd)
## ##
@ -394,7 +404,8 @@ class Packet(UserDict.DictMixin):
opcodes = {} opcodes = {}
def __init__(self, firstframe=None): def __init__(self, session, firstframe=None):
self.session = session
self.firstframe = firstframe self.firstframe = firstframe
self.opcode = None self.opcode = None
self.opcode_desc = None self.opcode_desc = None
@ -513,28 +524,41 @@ class Session:
def __init__(self): def __init__(self):
self.pending = {} self.pending = {}
self.count = 0
self.setup()
def handle(self, chunk): def setup(self):
"""Set things up."""
pass
def handle(self, chunk, lastpos):
"""Handle a data burst. """Handle a data burst.
Pass in a chunk. Pass in a chunk.
""" """
saddr = chunk.first.saddr self.lastpos = lastpos
try: try:
(first, data) = self.pending.pop(saddr) saddr = chunk.first.saddr
except KeyError: try:
first = chunk.first (first, data) = self.pending.pop(saddr)
data = gapstr.GapString() except KeyError:
data.extend(chunk.gapstr()) first = chunk.first
try: data = gapstr.GapString()
while data: data.extend(chunk.gapstr())
p = self.Packet(first) try:
data = p.handle(data) while data:
self.process(p) p = self.Packet(self, first)
except NeedMoreData: data = p.handle(data)
self.pending[saddr] = (first, data) self.process(p)
except NeedMoreData:
self.pending[saddr] = (first, data)
self.count += 1
except:
print 'Lastpos: %s:::%d' % lastpos
raise
def process(self, packet): def process(self, packet):
"""Process a packet. """Process a packet.
@ -546,6 +570,7 @@ class Session:
""" """
print 'Lastpos: %s:::%d' % self.lastpos
packet.show() packet.show()
def done(self): def done(self):