From 9d487edfb3bfd139d839e33de059baa0e48ce836 Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Fri, 18 Jan 2008 19:09:09 -0700 Subject: [PATCH] Integrate GapString and a few tweaks --- __init__.py | 99 ++++++++++++++++++++++++++++++++++++----------------- crypto.py | 9 +++-- gapstr.py | 6 +++- ip.py | 48 ++++++++++++++------------ 4 files changed, 103 insertions(+), 59 deletions(-) diff --git a/__init__.py b/__init__.py index c57d2e9..85a67b5 100755 --- a/__init__.py +++ b/__init__.py @@ -10,47 +10,82 @@ def unpack(fmt, buf): """Unpack buf based on fmt, return the rest as a string.""" size = struct.calcsize(fmt) - vals = struct.unpack(fmt, buf[:size]) + vals = struct.unpack(fmt, str(buf[:size])) return vals + (buf[size:],) -def to_printable(c): - if c in printable: - return c - elif c == '\0': - return '␀' - elif c == '\r': - return '␍' - elif c == '\n': - return '␤' - else: - return '·' +class HexDumper: + def __init__(self, fd=sys.stdout): + self.fd = fd + self.offset = 0 + self.buf = [] + + def _to_printable(self, c): + if not c: + return '◆' + elif c in printable: + return c + elif c == '\0': + return '␀' + elif c == '\r': + return '␍' + elif c == '\n': + return '␤' + else: + return '·' + + + def _flush(self): + if not self.buf: + return + + o = [] + for c in self.buf: + if c: + o.append('%02x' % ord(c)) + else: + o.append('--') + o += ([' '] * (16 - len(self.buf))) + p = [self._to_printable(c) for c in self.buf] + + self.fd.write('%08x ' % self.offset) + + self.fd.write(' '.join(o[:8])) + self.fd.write(' ') + self.fd.write(' '.join(o[8:])) + + self.fd.write(' ║') + + self.fd.write(''.join(p)) + + self.fd.write('║\n') + + self.buf = [] + self.offset += 16 + + def dump_chr(self, c): + self.buf.append(c) + if len(self.buf) == 16: + self._flush() + + def dump_drop(self): + self.buf.append(None) + if len(self.buf) == 16: + self._flush() + + def finish(self): + self._flush() + self.fd.write('%08x\n' % self.offset) def hexdump(buf, f=sys.stdout): "Print a hex dump of buf" - offset = 0 + d = HexDumper() - while buf: - s = buf[:16] - o = [('%02x' % ord(c)) for c in s] + ([' '] * (16 - len(s))) - p = [to_printable(c) for c in s] - - f.write('%08x ' % offset) - - f.write(' '.join(o[:8])) - f.write(' ') - f.write(' '.join(o[8:])) - - f.write(' ║') - - f.write(''.join(p)) - - f.write('║\n') - - buf = buf[16:] - offset += 16 + for c in buf: + d.dump_chr(c) + d.finish() def cstring(buf): diff --git a/crypto.py b/crypto.py index 10df9c6..a2e2621 100644 --- a/crypto.py +++ b/crypto.py @@ -186,11 +186,10 @@ tabula_recta = caesars('ABCDEFGHIJKLMNOPQRSTUVWXYZ') def xor(n, txt): - out = '' - for c in txt: - o = ord(c) ^ n - out += chr(o) - return out + if n == 0: + return txt + out = [(chr(ord(c) ^ n)) for c in txt] + return ''.join(out) def xors(txt): ret = [] diff --git a/gapstr.py b/gapstr.py index 402e136..94fdd29 100755 --- a/gapstr.py +++ b/gapstr.py @@ -48,7 +48,7 @@ class GapString: else: for c in i: d.dump_chr(c) - d.flush() + d.finish() def extend(self, other): self.contents += other.contents @@ -56,10 +56,14 @@ class GapString: def __getslice__(self, start, end): end = min(self.length, end) + start = min(self.length, start) new = self.__class__(self.drop) new.contents = self.contents[:] new.length = end - start + if new.length == 0: + return new + l = self.length - new.length - start # Trim off the beginning diff --git a/ip.py b/ip.py index a8983cc..1dc85bb 100755 --- a/ip.py +++ b/ip.py @@ -5,6 +5,7 @@ import struct import socket import warnings import heapq +import gapstr def unpack(fmt, buf): @@ -110,18 +111,13 @@ class Frame: self.dst_addr, self.dport, len(self.payload)) + class Chunk: """Chunk of frames, possibly with gaps. - Currently, gaps show up as a string of 0x33, ascii '3'. - """ - def __init__(self, seq=None, drop='3'): - # chr(0x33) == '3'. If you see a bunch of 3s, in the ascii or - # the hex view, suspect a drop. - assert len(drop) == 1, "Don't yet support len(drop) > 1" - self.drop = drop + def __init__(self, seq=None): self.collection = {} self.length = 0 self.seq = seq @@ -130,8 +126,8 @@ class Chunk: def add(self, frame): if not self.first: self.first = frame - if self.seq is None: - self.seq = frame.seq + if self.seq is None: + self.seq = frame.seq assert frame.seq >= self.seq, (frame.seq, self.seq) self.collection[frame.seq] = frame end = frame.seq - self.seq + len(frame.payload) @@ -150,25 +146,35 @@ class Chunk: else: return '' - def __str__(self): - s = '' - while len(s) < self.length: - f = self.collection.get(self.seq + len(s)) + def gapstr(self, drop='?'): + """Return contents as a GapString""" + + ret = gapstr.GapString(drop) + while len(ret) < self.length: + f = self.collection.get(self.seq + len(ret)) if f: - s += f.payload + ret.append(f.payload) else: - # This is where to fix it for len(drop) > 1. - # This is also where to fix big inefficiency for dropped packets. - s += self.drop - return s + # This is where to fix big inefficiency for dropped packets. + l = 1 + while ((len(ret) + l < self.length) and + (not (self.seq + len(ret) + l) in self.collection)): + l += 1 + ret.append(l) + return ret + + def __str__(self): + return str(self.gapstr()) def extend(self, other): self.seq = min(self.seq or other.seq, other.seq) - for frame in other.collection.itervalues(): - self.add(frame) + self.length = self.length + other.length + if not self.first: + self.first = other.first + self.collection.update(other.collection) def __add__(self, next): - new = self.__class__(self.seq, self.drop) + new = self.__class__(self.seq) new.extend(self) new.extend(next) return new