mirror of https://github.com/dirtbags/netarch.git
Various fixes from carebears work
This commit is contained in:
parent
833edb4135
commit
b1469e059b
|
@ -42,7 +42,7 @@ decch = (u'␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏'
|
||||||
|
|
||||||
cgach = (u'␀☺☻♥♦♣♠•◘○◙♂♀♪♫☼'
|
cgach = (u'␀☺☻♥♦♣♠•◘○◙♂♀♪♫☼'
|
||||||
u'►◄↕‼¶§▬↨↑↓→←∟↔▲▼'
|
u'►◄↕‼¶§▬↨↑↓→←∟↔▲▼'
|
||||||
u'␣!"#$%&\'()*+,-./'
|
u' !"#$%&\'()*+,-./'
|
||||||
u'0123456789:;<=>?'
|
u'0123456789:;<=>?'
|
||||||
u'@ABCDEFGHIJKLMNO'
|
u'@ABCDEFGHIJKLMNO'
|
||||||
u'PQRSTUVWXYZ[\]^_'
|
u'PQRSTUVWXYZ[\]^_'
|
||||||
|
|
|
@ -16,12 +16,22 @@ class GapString:
|
||||||
self.contents = []
|
self.contents = []
|
||||||
self.length = 0
|
self.length = 0
|
||||||
self.drop = drop
|
self.drop = drop
|
||||||
|
|
||||||
if init:
|
if init:
|
||||||
self.append(init)
|
self.append(init)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return int(self.length)
|
return int(self.length)
|
||||||
|
|
||||||
|
def loss(self):
|
||||||
|
ret = 0
|
||||||
|
for i in self.contents:
|
||||||
|
try:
|
||||||
|
ret += i
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
return ret
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<GapString of length %d>' % self.length
|
return '<GapString of length %d>' % self.length
|
||||||
|
|
||||||
|
@ -33,6 +43,15 @@ class GapString:
|
||||||
self.length += i
|
self.length += i
|
||||||
self.contents.append(i)
|
self.contents.append(i)
|
||||||
|
|
||||||
|
def pop(self, idx=-1):
|
||||||
|
item = self.contents.pop(idx)
|
||||||
|
try:
|
||||||
|
self.length -= item
|
||||||
|
except TypeError:
|
||||||
|
self.length -= len(item)
|
||||||
|
return GapString(item)
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
ret = []
|
ret = []
|
||||||
for i in self.contents:
|
for i in self.contents:
|
||||||
|
@ -171,7 +190,6 @@ class GapString:
|
||||||
offset = (offset + 1) % masklen
|
offset = (offset + 1) % masklen
|
||||||
new.append(''.join(r))
|
new.append(''.join(r))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
print("type error!")
|
|
||||||
new.append(i)
|
new.append(i)
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
@ -188,9 +206,8 @@ class GapString:
|
||||||
|
|
||||||
def split(self, pivot=' ', times=None):
|
def split(self, pivot=' ', times=None):
|
||||||
ret = []
|
ret = []
|
||||||
n = 0
|
|
||||||
cur = self
|
cur = self
|
||||||
while (not times) or (n < times):
|
while (not times) or (len(ret) < times):
|
||||||
try:
|
try:
|
||||||
pos = cur.index(pivot)
|
pos = cur.index(pivot)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
|
@ -10,7 +10,10 @@ import warnings
|
||||||
import heapq
|
import heapq
|
||||||
import gapstr
|
import gapstr
|
||||||
import time
|
import time
|
||||||
|
try:
|
||||||
import pcap
|
import pcap
|
||||||
|
except ImportError:
|
||||||
|
import py_pcap as pcap
|
||||||
import os
|
import os
|
||||||
import cgi
|
import cgi
|
||||||
import urllib
|
import urllib
|
||||||
|
@ -21,6 +24,8 @@ def unpack_nybbles(byte):
|
||||||
return (byte >> 4, byte & 0x0F)
|
return (byte >> 4, byte & 0x0F)
|
||||||
|
|
||||||
|
|
||||||
|
transfers = os.environ.get('TRANSFERS', 'transfers')
|
||||||
|
|
||||||
IP = 0x0800
|
IP = 0x0800
|
||||||
ARP = 0x0806
|
ARP = 0x0806
|
||||||
VLAN = 0x8100
|
VLAN = 0x8100
|
||||||
|
@ -87,7 +92,6 @@ class Frame:
|
||||||
self.sum,
|
self.sum,
|
||||||
self.urp,
|
self.urp,
|
||||||
p) = unpack("!HHLLBBHHH", p)
|
p) = unpack("!HHLLBBHHH", p)
|
||||||
assert self.seq != self.ack
|
|
||||||
(self.off, th_x2) = unpack_nybbles(x2off)
|
(self.off, th_x2) = unpack_nybbles(x2off)
|
||||||
opt_length = self.off * 4
|
opt_length = self.off * 4
|
||||||
self.options, p = p[:opt_length - 20], p[opt_length - 20:]
|
self.options, p = p[:opt_length - 20], p[opt_length - 20:]
|
||||||
|
@ -154,15 +158,17 @@ class Frame:
|
||||||
self.dst_addr)
|
self.dst_addr)
|
||||||
|
|
||||||
class TCP_Recreate:
|
class TCP_Recreate:
|
||||||
def __init__(self, pcap, src, dst):
|
closed = True
|
||||||
|
|
||||||
|
def __init__(self, pcap, src, dst, timestamp):
|
||||||
self.pcap = pcap
|
self.pcap = pcap
|
||||||
self.src = (socket.inet_aton(src[0]), src[1])
|
self.src = (socket.inet_aton(src[0]), src[1])
|
||||||
self.dst = (socket.inet_aton(dst[0]), dst[1])
|
self.dst = (socket.inet_aton(dst[0]), dst[1])
|
||||||
self.sid = self.did = 0
|
self.sid = self.did = 0
|
||||||
self.sseq = self.dseq = 0
|
self.sseq = self.dseq = 1
|
||||||
self.closed = True
|
|
||||||
self.lastts = 0
|
self.lastts = 0
|
||||||
self.write_header()
|
self.write_header()
|
||||||
|
self.handshake(timestamp)
|
||||||
|
|
||||||
def write_header(self):
|
def write_header(self):
|
||||||
p = '\0\0\0\0\0\0\0\0\0\0\0\0\xfe\xed'
|
p = '\0\0\0\0\0\0\0\0\0\0\0\0\xfe\xed'
|
||||||
|
@ -189,6 +195,8 @@ class TCP_Recreate:
|
||||||
if flags & (SYN|FIN):
|
if flags & (SYN|FIN):
|
||||||
self.dseq += 1
|
self.dseq += 1
|
||||||
ack = self.sseq
|
ack = self.sseq
|
||||||
|
if not (flags & ACK):
|
||||||
|
ack = 0
|
||||||
ethhdr = struct.pack('!6s6sH',
|
ethhdr = struct.pack('!6s6sH',
|
||||||
'\x11\x11\x11\x11\x11\x11',
|
'\x11\x11\x11\x11\x11\x11',
|
||||||
'\x22\x22\x22\x22\x22\x22',
|
'\x22\x22\x22\x22\x22\x22',
|
||||||
|
@ -198,7 +206,6 @@ class TCP_Recreate:
|
||||||
0x45, # Version, Header length/32
|
0x45, # Version, Header length/32
|
||||||
0, # Differentiated services / ECN
|
0, # Differentiated services / ECN
|
||||||
40+len(payload), # total size
|
40+len(payload), # total size
|
||||||
#40,
|
|
||||||
id,
|
id,
|
||||||
0x4000, # Don't fragment, no fragment offset
|
0x4000, # Don't fragment, no fragment offset
|
||||||
6, # TTL
|
6, # TTL
|
||||||
|
@ -207,7 +214,8 @@ class TCP_Recreate:
|
||||||
sip,
|
sip,
|
||||||
dip)
|
dip)
|
||||||
shorts = struct.unpack('!hhhhhhhhhh', iphdr)
|
shorts = struct.unpack('!hhhhhhhhhh', iphdr)
|
||||||
ipsum = struct.pack('!h', ~(sum(shorts)) & 0xffff)
|
shsum = sum(shorts)
|
||||||
|
ipsum = struct.pack('!h', (~shsum & 0xffff) - 2) # -2? WTF?
|
||||||
iphdr = iphdr[:10] + ipsum + iphdr[12:]
|
iphdr = iphdr[:10] + ipsum + iphdr[12:]
|
||||||
|
|
||||||
tcphdr = struct.pack('!HHLLBBHHH',
|
tcphdr = struct.pack('!HHLLBBHHH',
|
||||||
|
@ -217,13 +225,13 @@ class TCP_Recreate:
|
||||||
ack, # Acknowledgement number
|
ack, # Acknowledgement number
|
||||||
0x50, # Data offset
|
0x50, # Data offset
|
||||||
flags, # Flags
|
flags, # Flags
|
||||||
0x1000, # Window size
|
0xff00, # Window size
|
||||||
0, # Checksum
|
0, # Checksum
|
||||||
0) # Urgent pointer
|
0) # Urgent pointer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return ethhdr + iphdr + tcphdr + payload
|
return ethhdr + iphdr + tcphdr + str(payload)
|
||||||
|
|
||||||
def write_pkt(self, timestamp, cli, payload, flags=0):
|
def write_pkt(self, timestamp, cli, payload, flags=0):
|
||||||
p = self.packet(cli, payload, flags)
|
p = self.packet(cli, payload, flags)
|
||||||
|
@ -232,7 +240,9 @@ class TCP_Recreate:
|
||||||
self.lastts = timestamp
|
self.lastts = timestamp
|
||||||
|
|
||||||
def write(self, timestamp, cli, data):
|
def write(self, timestamp, cli, data):
|
||||||
self.write_pkt(timestamp, cli, data, ACK)
|
while data:
|
||||||
|
d, data = data[:0xff00], data[0xff00:]
|
||||||
|
self.write_pkt(timestamp, cli, d, ACK)
|
||||||
|
|
||||||
def handshake(self, timestamp):
|
def handshake(self, timestamp):
|
||||||
self.write_pkt(timestamp, True, '', SYN)
|
self.write_pkt(timestamp, True, '', SYN)
|
||||||
|
@ -289,15 +299,75 @@ class TCP_Resequence:
|
||||||
self.handle = self.handle_handshake
|
self.handle = self.handle_handshake
|
||||||
|
|
||||||
|
|
||||||
|
def bundle_pending(self, xdi, pkt, seq):
|
||||||
|
"""Bundle up any pending packets.
|
||||||
|
|
||||||
|
Called when a packet comes from a new direction, this is the thing responsible for
|
||||||
|
replaying TCP as a back-and-forth conversation.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
pending = self.pending[xdi]
|
||||||
|
# Get a sorted list of sequence numbers
|
||||||
|
keys = pending.keys()
|
||||||
|
keys.sort()
|
||||||
|
|
||||||
|
# Build up return value
|
||||||
|
gs = gapstr.GapString()
|
||||||
|
if keys:
|
||||||
|
f = pending[keys[0]]
|
||||||
|
ret = (xdi, f, gs)
|
||||||
|
else:
|
||||||
|
ret = (xdi, None, gs)
|
||||||
|
|
||||||
|
# Fill in gs with our frames
|
||||||
|
for key in keys:
|
||||||
|
if key >= pkt.ack:
|
||||||
|
# In the future
|
||||||
|
break
|
||||||
|
frame = pending[key]
|
||||||
|
if key > seq:
|
||||||
|
# Dropped frame(s)
|
||||||
|
if key - seq > 6000:
|
||||||
|
print "Gosh, bob, %d dropped octets sure is a lot!" % (key - seq)
|
||||||
|
gs.append(key - seq)
|
||||||
|
seq = key
|
||||||
|
if key == seq:
|
||||||
|
# Default
|
||||||
|
gs.append(frame.payload)
|
||||||
|
seq += len(frame.payload)
|
||||||
|
del pending[key]
|
||||||
|
elif key < seq:
|
||||||
|
# Hopefully just a retransmit. Anyway we've already
|
||||||
|
# claimed to have data (or a drop) for this packet.
|
||||||
|
del pending[key]
|
||||||
|
if frame.flags & (FIN):
|
||||||
|
seq += 1
|
||||||
|
if frame.flags & (FIN | ACK) == FIN | ACK:
|
||||||
|
self.closed[xdi] = True
|
||||||
|
if self.closed == [True, True]:
|
||||||
|
self.handle = self.handle_drop
|
||||||
|
if seq != pkt.ack:
|
||||||
|
# Drop at the end
|
||||||
|
if pkt.ack - seq > 6000:
|
||||||
|
print 'Large drop at end of session!'
|
||||||
|
print ' %s' % ((pkt, pkt.time),)
|
||||||
|
print ' %x %x' % (pkt.ack, seq)
|
||||||
|
gs.append(pkt.ack - seq)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def handle(self, pkt):
|
def handle(self, pkt):
|
||||||
"""Stub.
|
"""Stub.
|
||||||
|
|
||||||
This function will never be called, it is immediately overridden
|
This function will never be called, it is immediately overridden
|
||||||
by __init__. The current value of this function is the state.
|
by __init__. The current value of self.handle is the state.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
def handle_handshake(self, pkt):
|
def handle_handshake(self, pkt):
|
||||||
if not self.first:
|
if not self.first:
|
||||||
self.first = pkt
|
self.first = pkt
|
||||||
|
@ -325,11 +395,19 @@ class TCP_Resequence:
|
||||||
self.handle = self.handle_packet
|
self.handle = self.handle_packet
|
||||||
self.handle(pkt)
|
self.handle(pkt)
|
||||||
|
|
||||||
|
|
||||||
def handle_packet(self, pkt):
|
def handle_packet(self, pkt):
|
||||||
# Which way is this going? 0 == from client
|
# Which way is this going? 0 == from client
|
||||||
idx = int(pkt.src == self.srv)
|
idx = int(pkt.src == self.srv)
|
||||||
xdi = 1 - idx
|
xdi = 1 - idx
|
||||||
|
|
||||||
|
if pkt.flags & RST:
|
||||||
|
# Handle RST before wonky sequence numbers screw up algorithm
|
||||||
|
self.closed = [True, True]
|
||||||
|
self.handle = self.handle_drop
|
||||||
|
|
||||||
|
return self.bundle_pending(xdi, pkt, self.lastack[idx])
|
||||||
|
else:
|
||||||
# Stick it into pending
|
# Stick it into pending
|
||||||
self.pending[idx][pkt.seq] = pkt
|
self.pending[idx][pkt.seq] = pkt
|
||||||
|
|
||||||
|
@ -337,52 +415,8 @@ class TCP_Resequence:
|
||||||
seq = self.lastack[idx]
|
seq = self.lastack[idx]
|
||||||
self.lastack[idx] = pkt.ack
|
self.lastack[idx] = pkt.ack
|
||||||
if pkt.ack > seq:
|
if pkt.ack > seq:
|
||||||
pending = self.pending[xdi]
|
return self.bundle_pending(xdi, pkt, seq)
|
||||||
# Get a sorted list of sequence numbers
|
|
||||||
keys = pending.keys()
|
|
||||||
keys.sort()
|
|
||||||
|
|
||||||
# Build up return value
|
|
||||||
gs = gapstr.GapString()
|
|
||||||
if keys:
|
|
||||||
f = pending[keys[0]]
|
|
||||||
ret = (xdi, f, gs)
|
|
||||||
else:
|
|
||||||
ret = (xdi, None, gs)
|
|
||||||
|
|
||||||
# Fill in gs with our frames
|
|
||||||
for key in keys:
|
|
||||||
if key >= pkt.ack:
|
|
||||||
# In the future
|
|
||||||
break
|
|
||||||
frame = pending[key]
|
|
||||||
if key > seq:
|
|
||||||
# Dropped frame(s)
|
|
||||||
gs.append(key - seq)
|
|
||||||
seq = key
|
|
||||||
if key == seq:
|
|
||||||
# Default
|
|
||||||
gs.append(frame.payload)
|
|
||||||
seq += len(frame.payload)
|
|
||||||
del pending[key]
|
|
||||||
elif key < seq:
|
|
||||||
# Hopefully just a retransmit. Anyway we've already
|
|
||||||
# claimed to have data (or a drop) for this packet.
|
|
||||||
del pending[key]
|
|
||||||
if frame.flags & (FIN | RST):
|
|
||||||
seq += 1
|
|
||||||
if frame.flags & (FIN | ACK) == FIN | ACK:
|
|
||||||
self.closed[xdi] = True
|
|
||||||
if self.closed == [True, True]:
|
|
||||||
self.handle = self.handle_drop
|
|
||||||
if seq != pkt.ack:
|
|
||||||
# Drop at the end
|
|
||||||
if pkt.ack - seq > 6000:
|
|
||||||
print(pkt, pkt.time)
|
|
||||||
print('%x %x' % (pkt.ack, seq))
|
|
||||||
gs.append(pkt.ack - seq)
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def handle_drop(self, pkt):
|
def handle_drop(self, pkt):
|
||||||
"""Warn about any unhandled packets"""
|
"""Warn about any unhandled packets"""
|
||||||
|
@ -591,8 +625,8 @@ class Session:
|
||||||
def __init__(self, frame):
|
def __init__(self, frame):
|
||||||
self.firstframe = frame
|
self.firstframe = frame
|
||||||
self.lastframe = [None, None]
|
self.lastframe = [None, None]
|
||||||
self.basename = 'transfers/%s' % (frame.src_addr,)
|
self.basename = os.path.join(transfers, frame.src_addr)
|
||||||
self.basename2 = 'transfers/%s' % (frame.dst_addr,)
|
self.basename2 = os.path.join(transfers, frame.dst_addr)
|
||||||
self.pending = {}
|
self.pending = {}
|
||||||
self.count = 0
|
self.count = 0
|
||||||
for d in (self.basename, self.basename2):
|
for d in (self.basename, self.basename2):
|
||||||
|
@ -639,7 +673,7 @@ class Session:
|
||||||
self.pending[saddr] = (f, data)
|
self.pending[saddr] = (f, data)
|
||||||
self.count += 1
|
self.count += 1
|
||||||
except:
|
except:
|
||||||
print 'Lastpos: %s:::%d' % lastpos
|
print ('Lastpos: %r' % (lastpos,))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def process(self, packet):
|
def process(self, packet):
|
||||||
|
@ -696,6 +730,7 @@ class HtmlSession(Session):
|
||||||
<head>
|
<head>
|
||||||
<title>%s</title>
|
<title>%s</title>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
.time { float: right; margin-left: 1em; font-size: 75%%; }
|
||||||
.server { background-color: white; color: black; }
|
.server { background-color: white; color: black; }
|
||||||
.client { background-color: #884; color: white; }
|
.client { background-color: #884; color: white; }
|
||||||
</style>
|
</style>
|
||||||
|
@ -720,6 +755,12 @@ class HtmlSession(Session):
|
||||||
cls = 'server'
|
cls = 'server'
|
||||||
else:
|
else:
|
||||||
cls = 'client'
|
cls = 'client'
|
||||||
|
|
||||||
|
if False:
|
||||||
self.sessfd.write('<span class="%s" title="%s(%s)">' % (cls, time.ctime(frame.time), frame.time))
|
self.sessfd.write('<span class="%s" title="%s(%s)">' % (cls, time.ctime(frame.time), frame.time))
|
||||||
|
else:
|
||||||
|
ts = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(frame.time))
|
||||||
|
self.sessfd.write('<span class="time %s">%s</span><span class="%s">' % (cls, ts, cls))
|
||||||
self.sessfd.write(p.replace('\r\n', '\n'))
|
self.sessfd.write(p.replace('\r\n', '\n'))
|
||||||
self.sessfd.write('</span>')
|
self.sessfd.write('</span>')
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
#! /usr/bin/python
|
||||||
|
|
||||||
|
import struct
|
||||||
|
|
||||||
|
_MAGIC = 0xA1B2C3D4
|
||||||
|
|
||||||
|
class pcap:
|
||||||
|
def __init__(self, stream, mode='rb', snaplen=65535, linktype=1):
|
||||||
|
try:
|
||||||
|
self.stream = file(stream, mode)
|
||||||
|
except TypeError:
|
||||||
|
self.stream = stream
|
||||||
|
try:
|
||||||
|
# Try reading
|
||||||
|
hdr = self.stream.read(24)
|
||||||
|
except IOError:
|
||||||
|
hdr = None
|
||||||
|
|
||||||
|
if hdr:
|
||||||
|
# We're in read mode
|
||||||
|
self._endian = None
|
||||||
|
for endian in '<>':
|
||||||
|
(self.magic,) = struct.unpack(endian + 'I', hdr[:4])
|
||||||
|
if self.magic == _MAGIC:
|
||||||
|
self._endian = endian
|
||||||
|
break
|
||||||
|
if not self._endian:
|
||||||
|
raise IOError('Not a pcap file')
|
||||||
|
(self.magic, version_major, version_minor,
|
||||||
|
self.thiszone, self.sigfigs,
|
||||||
|
self.snaplen, self.linktype) = struct.unpack(self._endian + 'IHHIIII', hdr)
|
||||||
|
if (version_major, version_minor) != (2, 4):
|
||||||
|
raise IOError('Cannot handle file version %d.%d' % (version_major,
|
||||||
|
version_minor))
|
||||||
|
else:
|
||||||
|
# We're in write mode
|
||||||
|
self._endian = '='
|
||||||
|
self.magic = _MAGIC
|
||||||
|
version_major = 2
|
||||||
|
version_minor = 4
|
||||||
|
self.thiszone = 0
|
||||||
|
self.sigfigs = 0
|
||||||
|
self.snaplen = snaplen
|
||||||
|
self.linktype = linktype
|
||||||
|
hdr = struct.pack(self._endian + 'IHHIIII',
|
||||||
|
self.magic, version_major, version_minor,
|
||||||
|
self.thiszone, self.sigfigs,
|
||||||
|
self.snaplen, self.linktype)
|
||||||
|
self.stream.write(hdr)
|
||||||
|
self.version = (version_major, version_minor)
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
hdr = self.stream.read(16)
|
||||||
|
if not hdr:
|
||||||
|
return
|
||||||
|
(tv_sec, tv_usec, caplen, length) = struct.unpack(self._endian + 'IIII', hdr)
|
||||||
|
datum = self.stream.read(caplen)
|
||||||
|
return ((tv_sec, tv_usec, length), datum)
|
||||||
|
|
||||||
|
def write(self, packet):
|
||||||
|
(header, datum) = packet
|
||||||
|
(tv_sec, tv_usec, length) = header
|
||||||
|
hdr = struct.pack(self._endian + 'IIII', tv_sec, tv_usec, length, len(datum))
|
||||||
|
self.stream.write(hdr)
|
||||||
|
self.stream.write(datum)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
while True:
|
||||||
|
r = self.read()
|
||||||
|
if not r:
|
||||||
|
break
|
||||||
|
yield r
|
||||||
|
|
||||||
|
|
||||||
|
open = pcap
|
||||||
|
open_offline = pcap
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
p = open('test.pcap', 'w') # Create a new file
|
||||||
|
p.write(((0, 0, 3), 'foo')) # Add a packet
|
||||||
|
p.write(((0, 0, 3), 'bar'))
|
||||||
|
del p
|
||||||
|
p = open(file('test.pcap')) # Also takes file objects
|
||||||
|
assert ((p.version, p.thiszone, p.sigfigs, p.snaplen, p.linktype) ==
|
||||||
|
((2, 4), 0, 0, 65535, 1))
|
||||||
|
assert ([i for i in p] == [((0, 0, 3), 'foo'), ((0, 0, 3), 'bar')])
|
Loading…
Reference in New Issue