diff --git a/scapy/utils.py b/scapy/utils.py index 40ce9a4b47a1b78247f8eab23ba6281e683a46e8..c3febf59e2bb97d9f1d61172b8e900cab20c17c8 100644 --- a/scapy/utils.py +++ b/scapy/utils.py @@ -548,49 +548,77 @@ def rdpcap(filename, count=-1): count: read only <count> packets """ - try: - return _rdpcap(filename, count=count) - except Scapy_Exception: - pass - try: - return _rdpcapng(filename, count=count) - except Scapy_Exception: - raise Scapy_Exception("Not a valid pcap or pcapng file") - + with PcapReader(filename) as fdesc: + return fdesc.read_all(count=count) -def _rdpcap(filename, count=-1): - """Read a pcap file and return a packet list -count: read only <count> packets +class PcapReader_metaclass(type): + """Metaclass for (Raw)Pcap(Ng)Readers""" - """ - with PcapReader(filename) as fdesc: - return fdesc.read_all(count=count) + def __new__(cls, name, bases, dct): + """The `alternative` class attribute is declared in the PcapNg + variant, and set here to the Pcap variant. -def _rdpcapng(filename, count=-1): - """Read a pcapng file and return a packet list + """ + newcls = super(PcapReader_metaclass, cls).__new__(cls, name, bases, dct) + if 'alternative' in dct: + dct['alternative'].alternative = newcls + return newcls -count: read only <count> packets + def __call__(cls, filename): + """Creates a cls instance, use the `alternative` if that + fails. - """ - with PcapNgReader(filename) as fdesc: - return fdesc.read_all(count=count) + """ + i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__) + filename, fdesc, magic = cls.open(filename) + try: + i.__init__(filename, fdesc, magic) + except Scapy_Exception: + if "alternative" in cls.__dict__: + cls = cls.__dict__["alternative"] + i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__) + try: + i.__init__(filename, fdesc, magic) + except Scapy_Exception: + try: + self.f.seek(-4, 1) + except: + pass + raise Scapy_Exception("Not a supported capture file") + + return i + + @staticmethod + def open(filename): + """Open (if necessary) filename, and read the magic.""" + if isinstance(filename, basestring): + try: + fdesc = gzip.open(filename,"rb") + magic = fdesc.read(4) + except IOError: + fdesc = open(filename,"rb") + magic = fdesc.read(4) + else: + fdesc = filename + filename = (fdesc.name + if hasattr(fdesc, "name") else + "No name") + magic = fdesc.read(4) + return filename, fdesc, magic class RawPcapReader: """A stateful pcap reader. Each packet is returned as a string""" - - def __init__(self, filename): - magic = self.open(filename) + __metaclass__ = PcapReader_metaclass + def __init__(self, filename, fdesc, magic): + self.filename = filename + self.f = fdesc if magic == "\xa1\xb2\xc3\xd4": #big endian self.endian = ">" elif magic == "\xd4\xc3\xb2\xa1": #little endian self.endian = "<" else: - try: - self.f.seek(-4, 1) - except: - pass raise Scapy_Exception( "Not a pcap capture file (bad magic: %r)" % magic ) @@ -602,23 +630,6 @@ class RawPcapReader: ) self.linktype = linktype - def open(self, filename): - """Open (if necessary) filename""" - if isinstance(filename, basestring): - self.filename = filename - try: - self.f = gzip.open(filename,"rb") - return self.f.read(4) - except IOError: - self.f = open(filename,"rb") - return self.f.read(4) - else: - self.f = filename - self.filename = (filename.name - if hasattr(filename, "name") else - "No name") - return self.f.read(4) - def __iter__(self): return self @@ -684,8 +695,8 @@ class RawPcapReader: class PcapReader(RawPcapReader): - def __init__(self, filename): - RawPcapReader.__init__(self, filename) + def __init__(self, filename, fdesc, magic): + RawPcapReader.__init__(self, filename, fdesc, magic) try: self.LLcls = conf.l2types[self.linktype] except KeyError: @@ -721,19 +732,18 @@ class RawPcapNgReader(RawPcapReader): """ - def __init__(self, filename): + alternative = RawPcapReader + + def __init__(self, filename, fdesc, magic): + self.filename = filename + self.f = fdesc # A list of (linktype, snaplen); will be populated by IDBs. self.interfaces = [] self.blocktypes = { 1: self.read_block_idb, 6: self.read_block_epb, } - magic = self.open(filename) if magic != "\x0a\x0d\x0d\x0a": # PcapNg: - try: - self.f.seek(-4, 1) - except: - pass raise Scapy_Exception( "Not a pcapng capture file (bad magic: %r)" % magic ) @@ -786,8 +796,12 @@ class RawPcapNgReader(RawPcapReader): class PcapNgReader(RawPcapNgReader): - def __init__(self, filename): - RawPcapNgReader.__init__(self, filename) + + alternative = PcapReader + + def __init__(self, filename, fdesc, magic): + RawPcapNgReader.__init__(self, filename, fdesc, magic) + def read_packet(self, size=MTU): rp = RawPcapNgReader.read_packet(self, size=size) if rp is None: diff --git a/test/regression.uts b/test/regression.uts index 3cf4b298e4a57fda22d9f9297ac961509f19bedf..fd2569158aab4b6d7e6c2843baba25e2d3457cb2 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -4300,10 +4300,10 @@ pcapfile = cStringIO.StringIO('\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\x00\ pcapngfile = cStringIO.StringIO('\n\r\r\n\\\x00\x00\x00M<+\x1a\x01\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00,\x00File created by merging: \nFile1: test.pcap \n\x04\x00\x08\x00mergecap\x00\x00\x00\x00\\\x00\x00\x00\x01\x00\x00\x00\\\x00\x00\x00e\x00\x00\x00\xff\xff\x00\x00\x02\x006\x00Unknown/not available in original file format(libpcap)\x00\x00\t\x00\x01\x00\x06\x00\x00\x00\x00\x00\x00\x00\\\x00\x00\x00\x06\x00\x00\x00H\x00\x00\x00\x00\x00\x00\x00\x8d*\x05\x00/\xfc[\xcd(\x00\x00\x00(\x00\x00\x00E\x00\x00(\x00\x01\x00\x00@\x06|\xcd\x7f\x00\x00\x01\x7f\x00\x00\x01\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\x91|\x00\x00H\x00\x00\x00\x06\x00\x00\x00<\x00\x00\x00\x00\x00\x00\x00\x8d*\x05\x00\x1f\xff[\xcd\x1c\x00\x00\x00\x1c\x00\x00\x00E\x00\x00\x1c\x00\x01\x00\x00@\x11|\xce\x7f\x00\x00\x01\x7f\x00\x00\x01\x005\x005\x00\x08\x01r<\x00\x00\x00\x06\x00\x00\x00<\x00\x00\x00\x00\x00\x00\x00\x8d*\x05\x00\xb9\x02\\\xcd\x1c\x00\x00\x00\x1c\x00\x00\x00E\x00\x00\x1c\x00\x01\x00\x00@\x01|\xde\x7f\x00\x00\x01\x7f\x00\x00\x01\x08\x00\xf7\xff\x00\x00\x00\x00<\x00\x00\x00') = Read a pcap file -pktpcap = utils._rdpcap(pcapfile) +pktpcap = rdpcap(pcapfile) = Read a pcapng file -pktpcapng = utils._rdpcapng(pcapngfile) +pktpcapng = rdpcap(pcapngfile) = Check both packet lists are the same assert list(pktpcap) == list(pktpcapng)