What is wrong
In PacketBlock — the obsolete Packet Block, 0x00000002 — the declared field widths and the option-area arithmetic describe two different layouts, so neither a spec-conformant block nor a block matching the declared widths parses.
pcapkit/protocols/schema/misc/pcapng.py:1648:
length: 'int' = UInt32Field(callback=byteorder_callback)
interface_id: 'int' = UInt32Field(callback=byteorder_callback) # line 1657
drop_count: 'int' = UInt32Field(callback=byteorder_callback, default=0xFFFF) # line 1659
timestamp_high: 'int' = UInt32Field(callback=byteorder_callback)
timestamp_low: 'int' = UInt32Field(callback=byteorder_callback)
captured_length: 'int' = UInt32Field(callback=byteorder_callback)
original_length: 'int' = UInt32Field(callback=byteorder_callback)
packet_data: 'bytes' = PayloadField(length=lambda pkt: pkt['captured_length'])
padding_data: 'bytes' = BytesField(length=lambda pkt: (4 - pkt['captured_length'] % 4) % 4)
options: 'list[Option]' = OptionField(
length=lambda pkt: pkt['length'] - 32 - pkt['captured_length'] - len(pkt['padding_data']), # line 1674
...
)
Both fields are 16-bit in the format. Appendix A of draft-ietf-opsawg-pcapng (Figure 19) puts them in one 32-bit word:
8 | Interface ID | Drops Count |
with Packet Data starting at octet 28, so the fixed overhead including the trailing Block Total Length is 32 octets — which is precisely the constant line 1674 subtracts. With interface_id and drop_count declared as UInt32Field the overhead is 36, so the two disagree by four octets and every field from timestamp_high onward is read from the wrong offset.
drop_count's own default=0xFFFF is a further sign the 16-bit layout was intended: the spec reserves exactly that value ("The value xFFFF (in hexadecimal) is reserved for those systems in which this information is not available"), which is a 16-bit sentinel, not a 32-bit one.
Symptom
Both layouts fail, and confusingly — the warnings come first and the failure surfaces as an AttributeError from the protocol object rather than as a format error:
[WARNING] packet length < 0: -4
[WARNING] PCAP-NG: [Block 2] block length mismatch: 76 != 0
[WARNING] PCAP-NG: Packet Block has been obsolete! ...
AttributeError: 'PCAPNG' object has no attribute '_info'. Did you mean: 'info'?
(76 != 0 for the spec layout, 80 != 0 for the 32-bit layout; the AttributeError is identical.)
Reproduction
import struct
def pad4(b): return b + b'\x00' * ((4 - len(b) % 4) % 4)
def block(t, body):
body = pad4(body); n = 12 + len(body)
return struct.pack('<II', t, n) + body + struct.pack('<I', n)
shb = lambda: block(0x0A0D0D0A, struct.pack('<IHHq', 0x1A2B3C4D, 1, 0, -1))
idb = lambda: block(0x00000001, struct.pack('<HHI', 1, 0, 0x40000))
ETH = bytes.fromhex('ffffffffffff001122334455') + b'\x08\x06' + b'\x00' * 28
# Appendix A layout: 16-bit Interface ID and Drops Count
pb16 = block(0x00000002, struct.pack('<HHIIII', 0, 0, 0, 0, len(ETH), len(ETH)) + pad4(ETH))
# the layout the schema declares: 32-bit Interface ID and Drops Count
pb32 = block(0x00000002, struct.pack('<IIIIII', 0, 0, 0, 0, len(ETH), len(ETH)) + pad4(ETH))
import pcapkit
for name, pb in (('pb16', pb16), ('pb32', pb32)):
open(f'/tmp/{name}.pcapng', 'wb').write(shb() + idb() + pb)
try:
pcapkit.extract(fin=f'/tmp/{name}.pcapng', store=True, nofile=True)
except Exception as exc:
print(name, '->', type(exc).__name__, exc)
What a fix would need to touch
interface_id and drop_count at lines 1657 and 1659 become UInt16Field, which makes the existing - 32 at line 1674 correct. The corresponding _read_block_packet / _make_block_packet in pcapkit/protocols/misc/pcapng.py and the Data_PacketBlock model should be checked for the same assumption. The AttributeError: 'PCAPNG' object has no attribute '_info' is worth a look on its own — a malformed block ought to raise a format error rather than leaving a half-constructed protocol object (compare #289, which is the same symptom from a different cause).
The block is obsolete and MUST NOT appear in new files, so this is low-priority — but pcapkit claims to read it, and files containing it exist.
How it was found
While building deterministic sample captures for the test suite. The generators' module docstrings record it: examples/samples/pcapng.py lists the obsolete Packet Block among the block types deliberately left out of the fixtures, because neither layout parses.
Line numbers are from main at 72f950d.
What is wrong
In
PacketBlock— the obsolete Packet Block,0x00000002— the declared field widths and the option-area arithmetic describe two different layouts, so neither a spec-conformant block nor a block matching the declared widths parses.pcapkit/protocols/schema/misc/pcapng.py:1648:Both fields are 16-bit in the format. Appendix A of draft-ietf-opsawg-pcapng (Figure 19) puts them in one 32-bit word:
with Packet Data starting at octet 28, so the fixed overhead including the trailing Block Total Length is 32 octets — which is precisely the constant line 1674 subtracts. With
interface_idanddrop_countdeclared asUInt32Fieldthe overhead is 36, so the two disagree by four octets and every field fromtimestamp_highonward is read from the wrong offset.drop_count's owndefault=0xFFFFis a further sign the 16-bit layout was intended: the spec reserves exactly that value ("The value xFFFF (in hexadecimal) is reserved for those systems in which this information is not available"), which is a 16-bit sentinel, not a 32-bit one.Symptom
Both layouts fail, and confusingly — the warnings come first and the failure surfaces as an
AttributeErrorfrom the protocol object rather than as a format error:(
76 != 0for the spec layout,80 != 0for the 32-bit layout; theAttributeErroris identical.)Reproduction
What a fix would need to touch
interface_idanddrop_countat lines 1657 and 1659 becomeUInt16Field, which makes the existing- 32at line 1674 correct. The corresponding_read_block_packet/_make_block_packetinpcapkit/protocols/misc/pcapng.pyand theData_PacketBlockmodel should be checked for the same assumption. TheAttributeError: 'PCAPNG' object has no attribute '_info'is worth a look on its own — a malformed block ought to raise a format error rather than leaving a half-constructed protocol object (compare #289, which is the same symptom from a different cause).The block is obsolete and MUST NOT appear in new files, so this is low-priority — but
pcapkitclaims to read it, and files containing it exist.How it was found
While building deterministic sample captures for the test suite. The generators' module docstrings record it:
examples/samples/pcapng.pylists the obsolete Packet Block among the block types deliberately left out of the fixtures, because neither layout parses.Line numbers are from
mainat 72f950d.