You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(toolkit): dpkt ends the extraction with ProtocolError on 802.1Q then 802.1ad, two 802.1ad, or three VLAN tags #1646
Describe the bug
With engine='dpkt' and TCP or IPv4 reassembly on, three tag stackings make extract() raise ProtocolError: 802.1Q then 802.1ad, 802.1ad twice, or three tags. The rest of the capture is never read. The error is TCP header not found at offset 38 of the 66-octet record; the frame cannot be sliced without re-serialising it, or, from IPv4 reassembly, IP header not found at offset 18 .... Tracing alone is unaffected. The default engine, scapy and pypcapfile read the same frames and carry on.
dpkt 1.9.8 decodes the IP packet but loses tags. Ethernet._unpack_data (dpkt/ethernet.py:90) reads two tags per pass, and __init__ runs a second pass over the leftover octets that resets vlan_tags. Only the last tag survives: 1 of 2, or 1 of 3. dpkt's re-serialisation is then 4 octets short for each lost tag. _layer2bytes (pcapkit/toolkit/dpkt.py:362, raised at :403) slices the record by that length, misses the header, and raises. tcp_reassembly (:975) and ipv4_reassembly (:781) both call it.
Reproduction on main (b375656e1): Python 3.14.8 and 3.11.15, dpkt 1.9.8, and pypcapfile 0.12.0 on 3.11 only. Each case is a two-frame capture extracted with reassembly=True, tcp=True, trace=True. The first frame is Ethernet, then the tags, then IPv4 and a TCP segment carrying 4 octets of data. The first TPID is the Ethernet type, each tag's next type is the following TPID, and the VLAN ids run 100, 101, and so on. The second frame is plain IPv4/TCP. Each cell is the first frame's TCP reassembly payload length / whether it is traced:
tags, then IPv4/TCP
default
dpkt
scapy
pypcapfile
802.1Q (control)
4 / yes
4 / yes
4 / yes
4 / yes
802.1ad, 802.1Q (control)
4 / yes
4 / yes
4 / yes
4 / yes
802.1Q, 802.1ad
4 / yes
ProtocolError
4 / yes
4 / yes
802.1ad, 802.1ad
4 / yes
ProtocolError
4 / yes
4 / yes
802.1Q, 802.1Q, 802.1Q
4 / yes
ProtocolError
4 / yes
4 / yes
802.1ad, 802.1Q, 802.1Q
4 / yes
ProtocolError
4 / yes
4 / yes
pyshark does no reassembly, so it is not compared.
Expected behavior
For each frame, dpkt hands over the same TCP, trace and IP reassembly inputs as the default engine, and the extraction continues.
Being fixed together with #1637 and #1638. Their fix makes this same _layer2bytes error reachable from IPv6 reassembly of a 6in4 fragment as well, so the root cause is fixed in that PR rather than disclosed.
Activity
JarryShaw commentedon Oct 13, 2026
Being fixed together with #1637 and #1638. Their fix makes this same
_layer2byteserror reachable from IPv6 reassembly of a 6in4 fragment as well, so the root cause is fixed in that PR rather than disclosed.refactor(toolkit): revert dpkt's agreement-only code (#1708)
refactor(toolkit): revert dpkt's agreement-only code (#1708) (#1727)