diff --git a/scapy/utils.py b/scapy/utils.py
index 0699c955e56b3b8a6dff99a3f36f609921b7c83e..0a50399974539647087ece98b95f111f8ade0c45 100644
--- a/scapy/utils.py
+++ b/scapy/utils.py
@@ -532,6 +532,17 @@ count: read only <count> packets"""
     with PcapReader(filename) as fdesc:
         return fdesc.read_all(count=count)
 
+def rdpcapng(filename, count=-1):
+    """Read a pcap file and return a packet list
+count: read only <count> packets"""
+    ## Does not work with Python <= 2.5. Use this implementation as
+    ## soon as we drop support for Python 2.5.
+    # with PcapNgReader(filename) as fdesc:
+    #     return fdesc.read_all(count=count)
+    fdesc = PcapNgReader(filename)
+    result = fdesc.read_all(count=count)
+    fdesc.close()
+    return result
 
 
 class RawPcapReader:
@@ -547,19 +558,20 @@ class RawPcapReader:
             magic = self.f.read(4)
         if magic == "\xa1\xb2\xc3\xd4": #big endian
             self.endian = ">"
-        elif  magic == "\xd4\xc3\xb2\xa1": #little endian
+        elif magic == "\xd4\xc3\xb2\xa1": #little endian
             self.endian = "<"
         else:
-            raise Scapy_Exception("Not a pcap capture file (bad magic)")
+            raise Scapy_Exception(
+                "Not a pcap capture file (bad magic: %r)" % magic
+            )
         hdr = self.f.read(20)
         if len(hdr)<20:
             raise Scapy_Exception("Invalid pcap file (too short)")
-        vermaj,vermin,tz,sig,snaplen,linktype = struct.unpack(self.endian+"HHIIII",hdr)
-
+        vermaj, vermin, tz, sig, snaplen, linktype = struct.unpack(
+            self.endian + "HHIIII", hdr
+        )
         self.linktype = linktype
 
-
-
     def __iter__(self):
         return self
 
@@ -654,7 +666,104 @@ class PcapReader(RawPcapReader):
         return plist.PacketList(res,name = os.path.basename(self.filename))
     def recv(self, size=MTU):
         return self.read_packet(size=size)
-        
+
+
+class RawPcapNgReader(RawPcapReader):
+    """A stateful pcapng reader. Each packet is returned as a
+    string.
+
+    """
+
+    def __init__(self, filename):
+        self.filename = filename
+        # A list of (linktype, snaplen); will be populated by IDBs.
+        self.interfaces = []
+        self.blocktypes = {
+            1: self.read_block_idb,
+            6: self.read_block_epb,
+        }
+        try:
+            self.f = gzip.open(filename,"rb")
+            magic = self.f.read(4)
+        except IOError:
+            self.f = open(filename,"rb")
+            magic = self.f.read(4)
+        if magic != "\n\r\r\n": # PcapNg:
+            raise Scapy_Exception(
+                "Not a pcapng capture file (bad magic: %r)" % magic
+            )
+        # see https://github.com/pcapng/pcapng
+        blocklen, magic = self.f.read(4), self.f.read(4)
+        if magic == "\x1a\x2b\x3c\x4d":
+            self.endian = ">"
+        elif magic == "\x4d\x3c\x2b\x1a":
+            self.endian = "<"
+        else:
+            raise Scapy_Exception("Not a pcapng capture file (bad magic)")
+        self.f.seek(0)
+
+    def read_packet(self, size=MTU):
+        """Read blocks until it reaches either EOF or a packet, and
+        returns None or (packet, (linktype, sec, usec, wirelen)),
+        where packet is a string.
+
+        """
+        while True:
+            try:
+                blocktype, blocklen = struct.unpack(self.endian + "2I",
+                                                    self.f.read(8))
+            except struct.error:
+                return None
+            block = self.f.read(blocklen - 12)
+            try:
+                if (blocklen,) != struct.unpack(self.endian + 'I',
+                                                self.f.read(4)):
+                    raise Scapy_Exception(
+                        "Invalid pcapng block (bad blocklen)"
+                    )
+            except struct.error:
+                return None
+            res = self.blocktypes.get(blocktype,
+                                      lambda block, size: None)(block, size)
+            if res is not None:
+                return res
+
+    def read_block_idb(self, block, _):
+        """Interface Description Block"""
+        self.interfaces.append(struct.unpack(self.endian + "HxxI", block[:8]))
+
+    def read_block_epb(self, block, size):
+        """Enhanced Packet Block"""
+        intid, sec, usec, caplen, wirelen = struct.unpack(self.endian + "5I",
+                                                          block[:20])
+        return (block[20:20 + caplen][:size],
+                (self.interfaces[intid][0], sec, usec, wirelen))
+
+
+class PcapNgReader(RawPcapNgReader):
+    def __init__(self, filename):
+        RawPcapNgReader.__init__(self, filename)
+    def read_packet(self, size=MTU):
+        rp = RawPcapNgReader.read_packet(self, size=size)
+        if rp is None:
+            return None
+        s, (linktype, sec, usec, wirelen) = rp
+        try:
+            p = conf.l2types[linktype](s)
+        except KeyboardInterrupt:
+            raise
+        except:
+            if conf.debug_dissector:
+                raise
+            p = conf.raw_layer(s)
+        p.time = sec+0.000001*usec
+        return p
+    def read_all(self,count=-1):
+        res = RawPcapNgReader.read_all(self, count)
+        import plist
+        return plist.PacketList(res, name=os.path.basename(self.filename))
+    def recv(self, size=MTU):
+        return self.read_packet()
 
 
 class RawPcapWriter: