From af8542ad7c344768fe76e07a134f5823812c5ee9 Mon Sep 17 00:00:00 2001 From: Phil <phil@secdev.org> Date: Tue, 26 Feb 2008 21:19:39 +0100 Subject: [PATCH] Improved PcapWriter Added .close() and .flush() method Added ability to append packets to a pcap file with the append parameter Added ability to make synchronous writes withe the sync parameter --- scapy.py | 78 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/scapy.py b/scapy.py index 205c664a..ab8563bc 100755 --- a/scapy.py +++ b/scapy.py @@ -10853,39 +10853,63 @@ class PcapReader: class PcapWriter: - """A pcap writer with more control than wrpcap() - - This routine is based entirely on scapy.wrpcap(), but adds capability - of writing one packet at a time in a streaming manner. - """ - def __init__(self, filename, linktype=None, gz=0, endianness=""): + """A stream PCAP writer with more control than wrpcap()""" + def __init__(self, filename, linktype=None, gz=False, endianness="", append=False, sync=False): + """ + linktype: force linktype to a given value. If None, linktype is taken + from the first writter packet + gz: compress the capture on the fly + endianness: force an endianness (little:"<", big:">"). Default is native + append: append packets to the capture file instead of truncating it + sync: do not bufferize writes to the capture file + """ + self.linktype = linktype - self.header_done = 0 - if gz: - self.f = gzip.open(filename,"wb") - else: - self.f = open(filename,"wb") + self.header_present = 0 + self.append=append + self.gz = gz self.endian = endianness + self.filename=filename + self.sync=sync + bufsz=4096 + if sync: + bufsz=0 + + self.f = [open,gzip.open][gz](filename,append and "ab" or "wb", gz and 9 or bufsz) + + def fileno(self): return self.f.fileno() + def _write_header(self, pkt): + self.header_present=1 + + if self.linktype == None: + if type(pkt) is list or type(pkt) is tuple: + pkt = pkt[0] + self.linktype = LLNumTypes.get(pkt.__class__,1) + + if self.append: + # Even if prone to race conditions, this seems to be + # safest way to tell whether the header is already present + # because we have to handle compressed streams that + # are not as flexible as basic files + g = [open,gzip.open][self.gz](self.filename,"rb") + if g.read(16): + return + + self.f.write(struct.pack(self.endian+"IHHIIII", 0xa1b2c3d4L, + 2, 4, 0, 0, MTU, self.linktype)) + self.f.flush() + + def write(self, pkt): """accepts a either a single packet or a list of packets to be written to the dumpfile """ - - if self.header_done == 0: - if self.linktype == None: - if isinstance(pkt,Packet): - self.linktype = LLNumTypes.get(pkt.__class__,1) - else: - self.linktype = LLNumTypes.get(pkt[0].__class__,1) - - self.f.write(struct.pack(self.endian+"IHHIIII", 0xa1b2c3d4L, - 2, 4, 0, 0, MTU, self.linktype)) - self.header_done = 1 - + if not self.header_present: + self._write_header(pkt) for p in pkt: self._write_packet(p) @@ -10898,6 +10922,14 @@ class PcapWriter: usec = int((packet.time-sec)*1000000) self.f.write(struct.pack(self.endian+"IIII", sec, usec, l, l)) self.f.write(s) + if self.gz and self.sync: + self.f.flush() + + def flush(self): + return self.f.flush() + def close(self): + return self.f.close() + re_extract_hexcap = re.compile("^(0x[0-9a-fA-F]{2,}[ :\t]|(0x)?[0-9a-fA-F]{2,}:|(0x)?[0-9a-fA-F]{3,}[: \t]|) *(([0-9a-fA-F]{2} {,2}){,16})") -- GitLab