Repository: secdev/scapy

Issue:
Pcap timestamp nanoseconds not equal to Wireshark
#### Brief description
The timestamp of Pcap or PcapNG files read using rdpcap() are interpreted differently to Wireshark.

#### Environment
Scapy Version: 2.4.3.dev170
Python: 3.7.5
OS: Kali 2019.4 (Linux kali 5.3.0-kali2-amd64 #1 SMP Debian 5.3.9-3kali1 (2019-11-20) x86_64 GNU/Linux)
Wireshark: 3.0.5-1on Linux
Cross-checked timestamp on Windows with Wireshark 3.0.6-0
ProfiShark Manager: 2.5.54

#### How to reproduce

Open a Pcap or PcapNG file of your choice with data in nanosecond resolution.
To reproduce the 10³ factor error you need a capture from ProfiTAP's ProfiShark.

Example view in Wireshark:

![image](https://user-images.githubusercontent.com/58110823/69479871-7abab000-0e02-11ea-957a-475db5ca9e9f.png)

Plain text timestamp: 2019-11-15 15:00:16.444223380

Code used in Scapy:

```python
pcap = rdpcap('c1.pcapng', 1)
for p in pcap:
    print(p.time)
```

#### Actual result

Output displayed:
```
1573830016444.2234
```

Adding some formatter:

```python
pcap = rdpcap('c1.pcapng', 1)
for p in pcap:
    print(p.time)
    print(p.time/1000)
    print('%.9f' % (p.time/1000))
```

Results:
```
1573830016444.2234
1573830016.4442234
1573830016.444223404
```

Actual problems:
* Timestamp is wrong by factor 10³ (only from ProfiShark files)
* Timestamp is wrong by 24 ns

#### Expected result

I expected to get exactly the same timestamp as seen in Wireshark.

#### Related information

Changing `read_packet` in `utils.py`
```python
p.time = float((tshigh << 32) + tslow) / tsresol
```
to
```python
p.time = Decimal((tshigh << 32) + tslow) / tsresol
```
seem to resolve the conversion problem.

Printing the `options = block[16:]` variable in `read_block_idb` looks like the following.

_Wireshark saved capture:_
```
b'\t\x00\x01\x00\t\x00\x00\x00\x0c\x00\x17\x00Linux 5.3.0-kali2-amd64\x00\x00\x00\x00\x00'
```

_ProfiShark saved capture:_
```
b'\x00\x00\x00\x00'
b'\x00\x00\x00\x00'
b'\x00\x00\x00\x00'
b'\x00\x00\x00\x00'
```

I think this leads to the default value of `tsresol = 1000000`.

I don't know if ProfiShark breaks the PcapNG format here or if it's a Scapy issue. Nevertheless, Wireshark does not have any problem to open the ProfiShark files.
Pcap timestamp nanoseconds not equal to Wireshark
#### Brief description
The timestamp of Pcap or PcapNG files read using rdpcap() are interpreted differently to Wireshark.

#### Environment
Scapy Version: 2.4.3.dev170
Python: 3.7.5
OS: Kali 2019.4 (Linux kali 5.3.0-kali2-amd64 #1 SMP Debian 5.3.9-3kali1 (2019-11-20) x86_64 GNU/Linux)
Wireshark: 3.0.5-1on Linux
Cross-checked timestamp on Windows with Wireshark 3.0.6-0
ProfiShark Manager: 2.5.54

#### How to reproduce

Open a Pcap or PcapNG file of your choice with data in nanosecond resolution.
To reproduce the 10³ factor error you need a capture from ProfiTAP's ProfiShark.

Example view in Wireshark:

![image](https://user-images.githubusercontent.com/58110823/69479871-7abab000-0e02-11ea-957a-475db5ca9e9f.png)

Plain text timestamp: 2019-11-15 15:00:16.444223380

Code used in Scapy:

```python
pcap = rdpcap('c1.pcapng', 1)
for p in pcap:
    print(p.time)
```

#### Actual result

Output displayed:
```
1573830016444.2234
```

Adding some formatter:

```python
pcap = rdpcap('c1.pcapng', 1)
for p in pcap:
    print(p.time)
    print(p.time/1000)
    print('%.9f' % (p.time/1000))
```

Results:
```
1573830016444.2234
1573830016.4442234
1573830016.444223404
```

Actual problems:
* Timestamp is wrong by factor 10³ (only from ProfiShark files)
* Timestamp is wrong by 24 ns

#### Expected result

I expected to get exactly the same timestamp as seen in Wireshark.

#### Related information

Changing `read_packet` in `utils.py`
```python
p.time = float((tshigh << 32) + tslow) / tsresol
```
to
```python
p.time = Decimal((tshigh << 32) + tslow) / tsresol
```
seem to resolve the conversion problem.

Printing the `options = block[16:]` variable in `read_block_idb` looks like the following.

_Wireshark saved capture:_
```
b'\t\x00\x01\x00\t\x00\x00\x00\x0c\x00\x17\x00Linux 5.3.0-kali2-amd64\x00\x00\x00\x00\x00'
```

_ProfiShark saved capture:_
```
b'\x00\x00\x00\x00'
b'\x00\x00\x00\x00'
b'\x00\x00\x00\x00'
b'\x00\x00\x00\x00'
```

I think this leads to the default value of `tsresol = 1000000`.

I don't know if ProfiShark breaks the PcapNG format here or if it's a Scapy issue. Nevertheless, Wireshark does not have any problem to open the ProfiShark files.


Discussion:

Resolving patch:
diff --git a/scapy/data.py b/scapy/data.py
--- a/scapy/data.py
+++ b/scapy/data.py
@@ -109,6 +109,7 @@
 DLT_BLUETOOTH_LE_LL = 251
 DLT_BLUETOOTH_LE_LL_WITH_PHDR = 256
 DLT_VSOCK = 271
+DLT_ETHERNET_MPACKET = 274
 
 # From net/ipv6.h on Linux (+ Additions)
 IPV6_ADDR_UNICAST = 0x01
diff --git a/scapy/layers/l2.py b/scapy/layers/l2.py
--- a/scapy/layers/l2.py
+++ b/scapy/layers/l2.py
@@ -21,14 +21,17 @@
 from scapy.config import conf
 from scapy import consts
 from scapy.data import ARPHDR_ETHER, ARPHDR_LOOPBACK, ARPHDR_METRICOM, \
-    DLT_LINUX_IRDA, DLT_LINUX_SLL, DLT_LOOP, DLT_NULL, ETHER_ANY, \
-    ETHER_BROADCAST, ETHER_TYPES, ETH_P_ARP, ETH_P_MACSEC
+    DLT_ETHERNET_MPACKET, DLT_LINUX_IRDA, DLT_LINUX_SLL, DLT_LOOP, \
+    DLT_NULL, ETHER_ANY, ETHER_BROADCAST, ETHER_TYPES, ETH_P_ARP, \
+    ETH_P_MACSEC
 from scapy.error import warning, ScapyNoDstMacException
 from scapy.fields import BCDFloatField, BitField, ByteField, \
-    ConditionalField, FieldLenField, IntEnumField, IntField, IP6Field, \
-    IPField, LenField, MACField, MultipleTypeField, ShortEnumField, \
-    ShortField, SourceIP6Field, SourceIPField, StrFixedLenField, StrLenField, \
-    X3BytesField, XByteField, XIntField, XShortEnumField, XShortField
+    ConditionalField, FieldLenField, FCSField, \
+    IntEnumField, IntField, IP6Field, IPField, \
+    LenField, MACField, MultipleTypeField, \
+    ShortEnumField, ShortField, SourceIP6Field, SourceIPField, \
+    StrFixedLenField, StrLenField, X3BytesField, XByteField, XIntField, \
+    XShortEnumField, XShortField
 from scapy.modules.six import viewitems
 from scapy.packet import bind_layers, Packet
 from scapy.plist import PacketList, SndRcvList
@@ -241,6 +244,13 @@ class CookedLinux(Packet):
                    XShortEnumField("proto", 0x800, ETHER_TYPES)]
 
 
+class MPacketPreamble(Packet):
+    # IEEE 802.3br Figure 99-3
+    name = "MPacket Preamble"
+    fields_desc = [StrFixedLenField("preamble", b"", length=8),
+                   FCSField("fcs", 0, fmt="!I")]
+
+
 class SNAP(Packet):
     name = "SNAP"
     fields_desc = [X3BytesField("OUI", 0x000000),
@@ -547,7 +557,7 @@ class Dot1AD(Dot1Q):
     name = '802_1AD'
 
 
-bind_layers(Dot3, LLC,)
+bind_layers(Dot3, LLC)
 bind_layers(Ether, LLC, type=122)
 bind_layers(Ether, LLC, type=34928)
 bind_layers(Ether, Dot1Q, type=33024)
@@ -563,6 +573,7 @@ class Dot1AD(Dot1Q):
 bind_layers(CookedLinux, Dot1AD, type=0x88a8)
 bind_layers(CookedLinux, Ether, proto=1)
 bind_layers(CookedLinux, ARP, proto=2054)
+bind_layers(MPacketPreamble, Ether)
 bind_layers(GRE, LLC, proto=122)
 bind_layers(GRE, Dot1Q, proto=33024)
 bind_layers(GRE, Dot1AD, type=0x88a8)
@@ -571,7 +582,7 @@ class Dot1AD(Dot1Q):
 bind_layers(GRE, ERSPAN, proto=0x88be, seqnum_present=1)
 bind_layers(GRE, GRErouting, {"routing_present": 1})
 bind_layers(GRErouting, conf.raw_layer, {"address_family": 0, "SRE_len": 0})
-bind_layers(GRErouting, GRErouting, {})
+bind_layers(GRErouting, GRErouting)
 bind_layers(LLC, STP, dsap=66, ssap=66, ctrl=3)
 bind_layers(LLC, SNAP, dsap=170, ssap=170, ctrl=3)
 bind_layers(SNAP, Dot1Q, code=33024)
@@ -585,6 +596,7 @@ class Dot1AD(Dot1Q):
 conf.l2types.register_num2layer(ARPHDR_LOOPBACK, Ether)
 conf.l2types.register_layer2num(ARPHDR_ETHER, Dot3)
 conf.l2types.register(DLT_LINUX_SLL, CookedLinux)
+conf.l2types.register(DLT_ETHERNET_MPACKET, MPacketPreamble)
 conf.l2types.register_num2layer(DLT_LINUX_IRDA, CookedLinux)
 conf.l2types.register(DLT_LOOP, Loopback)
 conf.l2types.register_num2layer(DLT_NULL, Loopback)
diff --git a/scapy/utils.py b/scapy/utils.py
--- a/scapy/utils.py
+++ b/scapy/utils.py
@@ -51,6 +51,43 @@ def issubtype(x, t):
     return isinstance(x, type) and issubclass(x, t)
 
 
+class EDecimal(Decimal):
+    """Extended Decimal
+
+    This implement comparison with float for backward compatibility
+    """
+
+    def __add__(self, other, **kwargs):
+        return EDecimal(Decimal.__add__(self, other, **kwargs))
+
+    def __sub__(self, other, **kwargs):
+        return EDecimal(Decimal.__sub__(self, other, **kwargs))
+
+    def __mul__(self, other, **kwargs):
+        return EDecimal(Decimal.__mul__(self, other, **kwargs))
+
+    def __truediv__(self, other, **kwargs):
+        return EDecimal(Decimal.__truediv__(self, other, **kwargs))
+
+    def __floordiv__(self, other, **kwargs):
+        return EDecimal(Decimal.__floordiv__(self, other, **kwargs))
+
+    def __div__(self, other, **kwargs):
+        return EDecimal(Decimal.__div__(self, other, **kwargs))
+
+    def __mod__(self, other, **kwargs):
+        return EDecimal(Decimal.__mod__(self, other, **kwargs))
+
+    def __divmod__(self, other, **kwargs):
+        return EDecimal(Decimal.__divmod__(self, other, **kwargs))
+
+    def __pow__(self, other, **kwargs):
+        return EDecimal(Decimal.__pow__(self, other, **kwargs))
+
+    def __eq__(self, other, **kwargs):
+        return super(EDecimal, self).__eq__(other) or float(self) == other
+
+
 def get_temp_file(keep=False, autoext="", fd=False):
     """Creates a temporary file.
 
@@ -1064,7 +1101,7 @@ def read_packet(self, size=MTU):
                 raise
             p = conf.raw_layer(s)
         power = Decimal(10) ** Decimal(-9 if self.nano else -6)
-        p.time = Decimal(pkt_info.sec + power * pkt_info.usec)
+        p.time = EDecimal(pkt_info.sec + power * pkt_info.usec)
         p.wirelen = pkt_info.wirelen
         return p
 
@@ -1078,8 +1115,8 @@ def recv(self, size=MTU):
 
 
 class RawPcapNgReader(RawPcapReader):
-    """A stateful pcapng reader. Each packet is returned as a
-    string.
+    """A stateful pcapng reader. Each packet is returned as
+    bytes.
 
     """
 
@@ -1094,6 +1131,9 @@ def __init__(self, filename, fdesc, magic):
         self.f = fdesc
         # A list of (linktype, snaplen, tsresol); will be populated by IDBs.
         self.interfaces = []
+        self.default_options = {
+            "tsresol": 1000000
+        }
         self.blocktypes = {
             1: self.read_block_idb,
             2: self.read_block_pkt,
@@ -1112,6 +1152,12 @@ def __init__(self, filename, fdesc, magic):
             self.endian = "<"
         else:
             raise Scapy_Exception("Not a pcapng capture file (bad magic)")
+        self.f.read(12)
+        blocklen = struct.unpack("!I", blocklen)[0]
+        # Read default options
+        self.default_options = self.read_options(
+            self.f.read(blocklen - 24)
+        )
         try:
             self.f.seek(0)
         except Exception:
@@ -1145,10 +1191,9 @@ def read_packet(self, size=MTU):
             if res is not None:
                 return res
 
-    def read_block_idb(self, block, _):
-        """Interface Description Block"""
-        options = block[16:]
-        tsresol = 1000000
+    def read_options(self, options):
+        """Section Header Block"""
+        opts = self.default_options.copy()
         while len(options) >= 4:
             code, length = struct.unpack(self.endian + "HH", options[:4])
             # PCAP Next Generation (pcapng) Capture File Format
@@ -1156,7 +1201,9 @@ def read_block_idb(self, block, _):
             # http://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.2
             if code == 9 and length == 1 and len(options) >= 5:
                 tsresol = orb(options[4])
-                tsresol = (2 if tsresol & 128 else 10) ** (tsresol & 127)
+                opts["tsresol"] = (2 if tsresol & 128 else 10) ** (
+                    tsresol & 127
+                )
             if code == 0:
                 if length != 0:
                     warning("PcapNg: invalid option length %d for end-of-option" % length)  # noqa: E501
@@ -1164,8 +1211,13 @@ def read_block_idb(self, block, _):
             if length % 4:
                 length += (4 - (length % 4))
             options = options[4 + length:]
+        return opts
+
+    def read_block_idb(self, block, _):
+        """Interface Description Block"""
+        options = self.read_options(block[16:])
         self.interfaces.append(struct.unpack(self.endian + "HxxI", block[:8]) +
-                               (tsresol,))
+                               (options["tsresol"],))
 
     def read_block_epb(self, block, size):
         """Enhanced Packet Block"""
@@ -1230,7 +1282,7 @@ def read_packet(self, size=MTU):
                 raise
             p = conf.raw_layer(s)
         if tshigh is not None:
-            p.time = float((tshigh << 32) + tslow) / tsresol
+            p.time = EDecimal((tshigh << 32) + tslow) / tsresol
         p.wirelen = wirelen
         return p
 


Test patch:
diff --git a/test/regression.uts b/test/regression.uts
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -6770,6 +6770,7 @@ pcapfile = BytesIO(b'\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x0
 pcapngfile = BytesIO(b'\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')
 pcapnanofile = BytesIO(b"M<\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00e\x00\x00\x00\xcf\xc5\xacV\xc9\xc1\xb5'(\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\x00\xcf\xc5\xacV-;\xc1'\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\xcf\xc5\xacV\x9aL\xcf'\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")
 pcapwirelenfile = BytesIO(b'\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x01\x00\x00\x00}\x87pZ.\xa2\x08\x00\x0f\x00\x00\x00\x10\x00\x00\x00\xff\xff\xff\xff\xff\xff GG\xee\xdd\xa8\x90\x00a')
+pcapngdefaults = BytesIO(base64_bytes(b'Cg0NChwAAABNPCsaAQAAAP//////////HAAAAAEAAAAgAAAAEgEAAP//AAAJAAEACUeZiQAAAAAgAAAAAQAAACAAAAASAQAA//8AAAkAAQAJAAAAAAAAACAAAAABAAAAIAAAABIBAAD//wAACQABAAkAAAAAAAAAIAAAAAEAAAAgAAAAEgEAAP//AAAJAAEACQAAAAAAAAAgAAAABgAAAIQBAAADAAAApO/bFdgJaeBiAQAAYgEAAFVVVVVVVVXV////////IMbr4D7PCABFAAFIlQkAAEAR5JwAAAAA/////wBEAEMBNJDsAQEGAFSpVwIACoAAAAAAAAAAAAAAAAAAAAAAACDG6+A+zwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABjglNjNQEB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsOs+bAAAhAEAAAYAAACAAQAAAwAAAKTv2xXIDYznYAEAAGABAABVVVVVVVVV1QEAXn//+iDG6+A+zwgARQABRgGPAAAEEal3qf5wqO////rhbgdsATJi0U5PVElGWSAqIEhUVFAvMS4xDQpIT1NUOiAyMzkuMjU1LjI1NS4yNTA6MTkwMA0KQ0FDSEUtQ09OVFJPTDogbWF4LWFnZT0xODAwDQpMT0NBVElPTjogaHR0cDovLzE2OS4yNTQuMTEyLjE2ODo1NTAwMC9ucmMvZGRkLnhtbA0KTlQ6IHV1aWQ6NEQ0NTQ5MzAtMDIwMC0xMDAwLTgwMDEtMjBDNkVCRTAzRUNGDQpOVFM6IHNzZHA6YWxpdmUNClNFUlZFUjogRnJlZUJTRC84LjAgVVBuUC8xLjAgUGFuYXNvbmljLU1JTC1ETE5BLVNWLzEuMA0KVVNOOiB1dWlkOjRENDU0OTMwLTAyMDAtMTAwMC04MDAxLTIwQzZFQkUwM0VDRg0KDQpcQcvWgAEAAAYAAAC4AQAAAwAAAKTv2xV4Ao3nlQEAAJUBAABVVVVVVVVV1QEAXn//+iDG6+A+zwgARQABewGQAAAEEalBqf5wqO////rhbgdsAWfu+k5PVElGWSAqIEhUVFAvMS4xDQpIT1NUOiAyMzkuMjU1LjI1NS4yNTA6MTkwMA0KQ0FDSEUtQ09OVFJPTDogbWF4LWFnZT0xODAwDQpMT0NBVElPTjogaHR0cDovLzE2OS4yNTQuMTEyLjE2ODo1NTAwMC9ucmMvZGRkLnhtbA0KTlQ6IHVybjpwYW5hc29uaWMtY29tOmRldmljZTpwMDBSZW1vdGVDb250cm9sbGVyOjENCk5UUzogc3NkcDphbGl2ZQ0KU0VSVkVSOiBGcmVlQlNELzguMCBVUG5QLzEuMCBQYW5hc29uaWMtTUlMLURMTkEtU1YvMS4wDQpVU046IHV1aWQ6NEQ0NTQ5MzAtMDIwMC0xMDAwLTgwMDEtMjBDNkVCRTAzRUNGOjp1cm46cGFuYXNvbmljLWNvbTpkZXZpY2U6cDAwUmVtb3RlQ29udHJvbGxlcjoxDQoNCrLVKmoAAAC4AQAABgAAAHgBAAADAAAApO/bFVjbjedXAQAAVwEAAFVVVVVVVVXVAQBef//6IMbr4D7PCABFAAE9AZEAAAQRqX6p/nCo7///+uFuB2wBKaZATk9USUZZICogSFRUUC8xLjENCkhPU1Q6IDIzOS4yNTUuMjU1LjI1MDoxOTAwDQpDQUNIRS1DT05UUk9MOiBtYXgtYWdlPTE4MDANCkxPQ0FUSU9OOiBodHRwOi8vMTY5LjI1NC4xMTIuMTY4OjU1MDAwL25yYy9kZGQueG1sDQpOVDogdXBucDpyb290ZGV2aWNlDQpOVFM6IHNzZHA6YWxpdmUNClNFUlZFUjogRnJlZUJTRC84LjAgVVBuUC8xLjAgUGFuYXNvbmljLU1JTC1ETE5BLVNWLzEuMA0KVVNOOiB1dWlkOjRENDU0OTMwLTAyMDAtMTAwMC04MDAxLTIwQzZFQkUwM0VDRjo6dXBucDpyb290ZGV2aWNlDQoNCjagXoUAeAEAAAYAAAC0AQAAAwAAAKTv2xXYw47nkwEAAJMBAABVVVVVVVVV1QEAXn//+iDG6+A+zwgARQABeQGSAAAEEalBqf5wqO////rhbgdsAWWV4E5PVElGWSAqIEhUVFAvMS4xDQpIT1NUOiAyMzkuMjU1LjI1NS4yNTA6MTkwMA0KQ0FDSEUtQ09OVFJPTDogbWF4LWFnZT0xODAwDQpMT0NBVElPTjogaHR0cDovLzE2OS4yNTQuMTEyLjE2ODo1NTAwMC9ucmMvZGRkLnhtbA0KTlQ6IHVybjpwYW5hc29uaWMtY29tOnNlcnZpY2U6cDAwTmV0d29ya0NvbnRyb2w6MQ0KTlRTOiBzc2RwOmFsaXZlDQpTRVJWRVI6IEZyZWVCU0QvOC4wIFVQblAvMS4wIFBhbmFzb25pYy1NSUwtRExOQS1TVi8xLjANClVTTjogdXVpZDo0RDQ1NDkzMC0wMjAwLTEwMDAtODAwMS0yMEM2RUJFMDNFQ0Y6OnVybjpwYW5hc29uaWMtY29tOnNlcnZpY2U6cDAwTmV0d29ya0NvbnRyb2w6MQ0KDQovXKFrALQBAAAGAAAAqAEAAAMAAACk79sVuJKP54cBAACHAQAAVVVVVVVVVdUBAF5///ogxuvgPs8IAEUAAW0BkwAABBGpTKn+cKjv///64W4HbAFZRNJOT1RJRlkgKiBIVFRQLzEuMQ0KSE9TVDogMjM5LjI1NS4yNTUuMjUwOjE5MDANCkNBQ0hFLUNPTlRST0w6IG1heC1hZ2U9MTgwMA0KTE9DQVRJT046IGh0dHA6Ly8xNjkuMjU0LjExMi4xNjg6NTUwMDAvbnJjL2RkZC54bWwNCk5UOiB1cm46ZGlhbC1tdWx0aXNjcmVlbi1vcmc6c2VydmljZTpkaWFsOjENCk5UUzogc3NkcDphbGl2ZQ0KU0VSVkVSOiBGcmVlQlNELzguMCBVUG5QLzEuMCBQYW5hc29uaWMtTUlMLURMTkEtU1YvMS4wDQpVU046IHV1aWQ6NEQ0NTQ5MzAtMDIwMC0xMDAwLTgwMDEtMjBDNkVCRTAzRUNGOjp1cm46ZGlhbC1tdWx0aXNjcmVlbi1vcmc6c2VydmljZTpkaWFsOjENCg0KLn5A6QCoAQAA'))
 
 = Read a pcap file
 pktpcap = rdpcap(pcapfile)
@@ -6780,7 +6781,12 @@ assert pktpcapng[0].time == 1454163407.666223
 
 = Read a pcap file with nanosecond precision
 pktpcapnano = rdpcap(pcapnanofile)
-assert pktpcapnano[0].time == Decimal('1454163407.666223049')
+assert pktpcapnano[0].time == 1454163407.666223049
+
+= Read a pcapng file with nanosecond precision and default tsresol
+pktpcapngdefaults = rdpcap(pcapngdefaults)
+assert pktpcapngdefaults[0].time == 1575115986.114775512
+assert Ether in pktpcapngdefaults[0]
 
 = Read a pcap file with wirelen != captured len
 pktpcapwirelen = rdpcap(pcapwirelenfile)