Skip to content

Commit 3ad5b80

Browse files
gpotter2guedou
authored andcommitted
Fix #2342 (#2352)
* Fix #2342 * Fix PcapNG read * Typos fixed
1 parent 993cc67 commit 3ad5b80

File tree

4 files changed

+90
-19
lines changed

4 files changed

+90
-19
lines changed

scapy/data.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
DLT_BLUETOOTH_LE_LL = 251
110110
DLT_BLUETOOTH_LE_LL_WITH_PHDR = 256
111111
DLT_VSOCK = 271
112+
DLT_ETHERNET_MPACKET = 274
112113

113114
# From net/ipv6.h on Linux (+ Additions)
114115
IPV6_ADDR_UNICAST = 0x01

scapy/layers/l2.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@
2121
from scapy.config import conf
2222
from scapy import consts
2323
from scapy.data import ARPHDR_ETHER, ARPHDR_LOOPBACK, ARPHDR_METRICOM, \
24-
DLT_LINUX_IRDA, DLT_LINUX_SLL, DLT_LOOP, DLT_NULL, ETHER_ANY, \
25-
ETHER_BROADCAST, ETHER_TYPES, ETH_P_ARP, ETH_P_MACSEC
24+
DLT_ETHERNET_MPACKET, DLT_LINUX_IRDA, DLT_LINUX_SLL, DLT_LOOP, \
25+
DLT_NULL, ETHER_ANY, ETHER_BROADCAST, ETHER_TYPES, ETH_P_ARP, \
26+
ETH_P_MACSEC
2627
from scapy.error import warning, ScapyNoDstMacException
2728
from scapy.fields import BCDFloatField, BitField, ByteField, \
28-
ConditionalField, FieldLenField, IntEnumField, IntField, IP6Field, \
29-
IPField, LenField, MACField, MultipleTypeField, ShortEnumField, \
30-
ShortField, SourceIP6Field, SourceIPField, StrFixedLenField, StrLenField, \
31-
X3BytesField, XByteField, XIntField, XShortEnumField, XShortField
29+
ConditionalField, FieldLenField, FCSField, \
30+
IntEnumField, IntField, IP6Field, IPField, \
31+
LenField, MACField, MultipleTypeField, \
32+
ShortEnumField, ShortField, SourceIP6Field, SourceIPField, \
33+
StrFixedLenField, StrLenField, X3BytesField, XByteField, XIntField, \
34+
XShortEnumField, XShortField
3235
from scapy.modules.six import viewitems
3336
from scapy.packet import bind_layers, Packet
3437
from scapy.plist import PacketList, SndRcvList
@@ -241,6 +244,13 @@ class CookedLinux(Packet):
241244
XShortEnumField("proto", 0x800, ETHER_TYPES)]
242245

243246

247+
class MPacketPreamble(Packet):
248+
# IEEE 802.3br Figure 99-3
249+
name = "MPacket Preamble"
250+
fields_desc = [StrFixedLenField("preamble", b"", length=8),
251+
FCSField("fcs", 0, fmt="!I")]
252+
253+
244254
class SNAP(Packet):
245255
name = "SNAP"
246256
fields_desc = [X3BytesField("OUI", 0x000000),
@@ -547,7 +557,7 @@ class Dot1AD(Dot1Q):
547557
name = '802_1AD'
548558

549559

550-
bind_layers(Dot3, LLC,)
560+
bind_layers(Dot3, LLC)
551561
bind_layers(Ether, LLC, type=122)
552562
bind_layers(Ether, LLC, type=34928)
553563
bind_layers(Ether, Dot1Q, type=33024)
@@ -563,6 +573,7 @@ class Dot1AD(Dot1Q):
563573
bind_layers(CookedLinux, Dot1AD, type=0x88a8)
564574
bind_layers(CookedLinux, Ether, proto=1)
565575
bind_layers(CookedLinux, ARP, proto=2054)
576+
bind_layers(MPacketPreamble, Ether)
566577
bind_layers(GRE, LLC, proto=122)
567578
bind_layers(GRE, Dot1Q, proto=33024)
568579
bind_layers(GRE, Dot1AD, type=0x88a8)
@@ -571,7 +582,7 @@ class Dot1AD(Dot1Q):
571582
bind_layers(GRE, ERSPAN, proto=0x88be, seqnum_present=1)
572583
bind_layers(GRE, GRErouting, {"routing_present": 1})
573584
bind_layers(GRErouting, conf.raw_layer, {"address_family": 0, "SRE_len": 0})
574-
bind_layers(GRErouting, GRErouting, {})
585+
bind_layers(GRErouting, GRErouting)
575586
bind_layers(LLC, STP, dsap=66, ssap=66, ctrl=3)
576587
bind_layers(LLC, SNAP, dsap=170, ssap=170, ctrl=3)
577588
bind_layers(SNAP, Dot1Q, code=33024)
@@ -585,6 +596,7 @@ class Dot1AD(Dot1Q):
585596
conf.l2types.register_num2layer(ARPHDR_LOOPBACK, Ether)
586597
conf.l2types.register_layer2num(ARPHDR_ETHER, Dot3)
587598
conf.l2types.register(DLT_LINUX_SLL, CookedLinux)
599+
conf.l2types.register(DLT_ETHERNET_MPACKET, MPacketPreamble)
588600
conf.l2types.register_num2layer(DLT_LINUX_IRDA, CookedLinux)
589601
conf.l2types.register(DLT_LOOP, Loopback)
590602
conf.l2types.register_num2layer(DLT_NULL, Loopback)

scapy/utils.py

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,43 @@ def issubtype(x, t):
5151
return isinstance(x, type) and issubclass(x, t)
5252

5353

54+
class EDecimal(Decimal):
55+
"""Extended Decimal
56+
57+
This implement comparison with float for backward compatibility
58+
"""
59+
60+
def __add__(self, other, **kwargs):
61+
return EDecimal(Decimal.__add__(self, other, **kwargs))
62+
63+
def __sub__(self, other, **kwargs):
64+
return EDecimal(Decimal.__sub__(self, other, **kwargs))
65+
66+
def __mul__(self, other, **kwargs):
67+
return EDecimal(Decimal.__mul__(self, other, **kwargs))
68+
69+
def __truediv__(self, other, **kwargs):
70+
return EDecimal(Decimal.__truediv__(self, other, **kwargs))
71+
72+
def __floordiv__(self, other, **kwargs):
73+
return EDecimal(Decimal.__floordiv__(self, other, **kwargs))
74+
75+
def __div__(self, other, **kwargs):
76+
return EDecimal(Decimal.__div__(self, other, **kwargs))
77+
78+
def __mod__(self, other, **kwargs):
79+
return EDecimal(Decimal.__mod__(self, other, **kwargs))
80+
81+
def __divmod__(self, other, **kwargs):
82+
return EDecimal(Decimal.__divmod__(self, other, **kwargs))
83+
84+
def __pow__(self, other, **kwargs):
85+
return EDecimal(Decimal.__pow__(self, other, **kwargs))
86+
87+
def __eq__(self, other, **kwargs):
88+
return super(EDecimal, self).__eq__(other) or float(self) == other
89+
90+
5491
def get_temp_file(keep=False, autoext="", fd=False):
5592
"""Creates a temporary file.
5693
@@ -1064,7 +1101,7 @@ def read_packet(self, size=MTU):
10641101
raise
10651102
p = conf.raw_layer(s)
10661103
power = Decimal(10) ** Decimal(-9 if self.nano else -6)
1067-
p.time = Decimal(pkt_info.sec + power * pkt_info.usec)
1104+
p.time = EDecimal(pkt_info.sec + power * pkt_info.usec)
10681105
p.wirelen = pkt_info.wirelen
10691106
return p
10701107

@@ -1078,8 +1115,8 @@ def recv(self, size=MTU):
10781115

10791116

10801117
class RawPcapNgReader(RawPcapReader):
1081-
"""A stateful pcapng reader. Each packet is returned as a
1082-
string.
1118+
"""A stateful pcapng reader. Each packet is returned as
1119+
bytes.
10831120
10841121
"""
10851122

@@ -1094,6 +1131,9 @@ def __init__(self, filename, fdesc, magic):
10941131
self.f = fdesc
10951132
# A list of (linktype, snaplen, tsresol); will be populated by IDBs.
10961133
self.interfaces = []
1134+
self.default_options = {
1135+
"tsresol": 1000000
1136+
}
10971137
self.blocktypes = {
10981138
1: self.read_block_idb,
10991139
2: self.read_block_pkt,
@@ -1112,6 +1152,12 @@ def __init__(self, filename, fdesc, magic):
11121152
self.endian = "<"
11131153
else:
11141154
raise Scapy_Exception("Not a pcapng capture file (bad magic)")
1155+
self.f.read(12)
1156+
blocklen = struct.unpack("!I", blocklen)[0]
1157+
# Read default options
1158+
self.default_options = self.read_options(
1159+
self.f.read(blocklen - 24)
1160+
)
11151161
try:
11161162
self.f.seek(0)
11171163
except Exception:
@@ -1145,27 +1191,33 @@ def read_packet(self, size=MTU):
11451191
if res is not None:
11461192
return res
11471193

1148-
def read_block_idb(self, block, _):
1149-
"""Interface Description Block"""
1150-
options = block[16:]
1151-
tsresol = 1000000
1194+
def read_options(self, options):
1195+
"""Section Header Block"""
1196+
opts = self.default_options.copy()
11521197
while len(options) >= 4:
11531198
code, length = struct.unpack(self.endian + "HH", options[:4])
11541199
# PCAP Next Generation (pcapng) Capture File Format
11551200
# 4.2. - Interface Description Block
11561201
# 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
11571202
if code == 9 and length == 1 and len(options) >= 5:
11581203
tsresol = orb(options[4])
1159-
tsresol = (2 if tsresol & 128 else 10) ** (tsresol & 127)
1204+
opts["tsresol"] = (2 if tsresol & 128 else 10) ** (
1205+
tsresol & 127
1206+
)
11601207
if code == 0:
11611208
if length != 0:
11621209
warning("PcapNg: invalid option length %d for end-of-option" % length) # noqa: E501
11631210
break
11641211
if length % 4:
11651212
length += (4 - (length % 4))
11661213
options = options[4 + length:]
1214+
return opts
1215+
1216+
def read_block_idb(self, block, _):
1217+
"""Interface Description Block"""
1218+
options = self.read_options(block[16:])
11671219
self.interfaces.append(struct.unpack(self.endian + "HxxI", block[:8]) +
1168-
(tsresol,))
1220+
(options["tsresol"],))
11691221

11701222
def read_block_epb(self, block, size):
11711223
"""Enhanced Packet Block"""
@@ -1230,7 +1282,7 @@ def read_packet(self, size=MTU):
12301282
raise
12311283
p = conf.raw_layer(s)
12321284
if tshigh is not None:
1233-
p.time = float((tshigh << 32) + tslow) / tsresol
1285+
p.time = EDecimal((tshigh << 32) + tslow) / tsresol
12341286
p.wirelen = wirelen
12351287
return p
12361288

test/regression.uts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6770,6 +6770,7 @@ pcapfile = BytesIO(b'\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x0
67706770
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')
67716771
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")
67726772
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')
6773+
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'))
67736774

67746775
= Read a pcap file
67756776
pktpcap = rdpcap(pcapfile)
@@ -6780,7 +6781,12 @@ assert pktpcapng[0].time == 1454163407.666223
67806781

67816782
= Read a pcap file with nanosecond precision
67826783
pktpcapnano = rdpcap(pcapnanofile)
6783-
assert pktpcapnano[0].time == Decimal('1454163407.666223049')
6784+
assert pktpcapnano[0].time == 1454163407.666223049
6785+
6786+
= Read a pcapng file with nanosecond precision and default tsresol
6787+
pktpcapngdefaults = rdpcap(pcapngdefaults)
6788+
assert pktpcapngdefaults[0].time == 1575115986.114775512
6789+
assert Ether in pktpcapngdefaults[0]
67846790

67856791
= Read a pcap file with wirelen != captured len
67866792
pktpcapwirelen = rdpcap(pcapwirelenfile)

0 commit comments

Comments
 (0)