What is wrong
pcapkit/protocols/schema/misc/pcapng.py:1335 sizes the Interface Statistics Block's option area as pkt['length'] - 20:
class InterfaceStatisticsBlock(BlockType, code=Enum_BlockType.Interface_Statistics_Block):
length: 'int' = UInt32Field(callback=byteorder_callback)
interface_id: 'int' = UInt32Field(callback=byteorder_callback)
timestamp_high: 'int' = UInt32Field(callback=byteorder_callback)
timestamp_low: 'int' = UInt32Field(callback=byteorder_callback)
options: 'list[Option]' = OptionField(
length=lambda pkt: pkt['length'] - 20, # <-- should be 24
...
)
padding: 'bytes' = PaddingField(length=lambda pkt: pkt['__option_padding__'])
length2: 'int' = UInt32Field(callback=byteorder_callback)
The ISB's fixed fields occupy 24 octets, not 20. Per § 4.6 of draft-ietf-opsawg-pcapng (Figure 14) the Options field begins at octet 20 — Block Type (4), Block Total Length (4), Interface ID (4), Timestamp (8) — and the block also ends with a second Block Total Length (4), which pkt['length'] includes. So the option area is length - 24, and as written the field is told it may read 4 octets more than exist.
That matters because Schema.unpack advances the file by each field's declared length (pcapkit/protocols/schema/schema.py:630, byte = data.read(field.length)), so the over-declaration consumes the trailing Block Total Length, and the leftover is then reported through __option_padding__ and consumed again by padding. The block ends up read 8 octets past its end. The error is unconditional — an explicit opt_endofopt does not save it, because the field still reads its declared width off the file.
Symptom
Any capture containing an ISB produces, per block:
[WARNING] packet length < 0: -8
[WARNING] PCAP-NG: [Block 5] block length mismatch: 40 != 0
The -8 is exact: the schema reads length(4) + interface_id(4) + timestamp_high(4) + timestamp_low(4) + options(20, should be 16) + padding(4, the leftover reported through __option_padding__) + length2(4) = 44 octets after the block type, i.e. 48 for a 40-octet block. The trailing length is therefore read from 8 octets beyond the block and comes back as 0.
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)
def opt(c, v): return struct.pack('<HH', c, len(v)) + pad4(v)
shb = lambda: block(0x0A0D0D0A, struct.pack('<IHHq', 0x1A2B3C4D, 1, 0, -1))
idb = lambda: block(0x00000001, struct.pack('<HHI', 1, 0, 0x40000))
epb = lambda d: block(0x00000006, struct.pack('<IIIII', 0, 0, 0, len(d), len(d)) + pad4(d))
ETH = bytes.fromhex('ffffffffffff001122334455') + b'\x08\x06' + b'\x00' * 28
# ISB with isb_starttime (option 2) and an explicit opt_endofopt
isb = block(0x00000005, struct.pack('<III', 0, 0, 0) + opt(2, struct.pack('<II', 0, 0)) + opt(0, b''))
open('/tmp/isb.pcapng', 'wb').write(shb() + idb() + epb(ETH) + isb)
import pcapkit
pcapkit.extract(fin='/tmp/isb.pcapng', store=True, nofile=True)
What a fix would need to touch
Changing the constant from 20 to 24 at line 1335 is sufficient: patching that callback at runtime and re-parsing the fixture above clears both warnings, with nothing else changed.
The generators' docstring also records this reproducing on Wireshark's own many_interfaces.pcapng (from test/captures in the Wireshark tree), as packet length < 0: -8 and [Block 5] block length mismatch. I did not have that capture to hand, so I am repeating that second-hand rather than reporting it as observed; the minimal fixture above is what I ran.
How it was found
While building deterministic sample captures for the test suite; the generators' module docstrings record it. examples/samples/pcapng.py exercises the ISB on purpose, because it warns rather than raising and a fixture covering the code path is what will catch a future crash there.
Line numbers are from main at 72f950d.
What is wrong
pcapkit/protocols/schema/misc/pcapng.py:1335sizes the Interface Statistics Block's option area aspkt['length'] - 20:The ISB's fixed fields occupy 24 octets, not 20. Per § 4.6 of draft-ietf-opsawg-pcapng (Figure 14) the Options field begins at octet 20 — Block Type (4), Block Total Length (4), Interface ID (4), Timestamp (8) — and the block also ends with a second Block Total Length (4), which
pkt['length']includes. So the option area islength - 24, and as written the field is told it may read 4 octets more than exist.That matters because
Schema.unpackadvances the file by each field's declared length (pcapkit/protocols/schema/schema.py:630,byte = data.read(field.length)), so the over-declaration consumes the trailing Block Total Length, and the leftover is then reported through__option_padding__and consumed again bypadding. The block ends up read 8 octets past its end. The error is unconditional — an explicitopt_endofoptdoes not save it, because the field still reads its declared width off the file.Symptom
Any capture containing an ISB produces, per block:
The
-8is exact: the schema readslength(4) +interface_id(4) +timestamp_high(4) +timestamp_low(4) +options(20, should be 16) +padding(4, the leftover reported through__option_padding__) +length2(4) = 44 octets after the block type, i.e. 48 for a 40-octet block. The trailing length is therefore read from 8 octets beyond the block and comes back as0.Reproduction
What a fix would need to touch
Changing the constant from 20 to 24 at line 1335 is sufficient: patching that callback at runtime and re-parsing the fixture above clears both warnings, with nothing else changed.
The generators' docstring also records this reproducing on Wireshark's own
many_interfaces.pcapng(fromtest/capturesin the Wireshark tree), aspacket length < 0: -8and[Block 5] block length mismatch. I did not have that capture to hand, so I am repeating that second-hand rather than reporting it as observed; the minimal fixture above is what I ran.How it was found
While building deterministic sample captures for the test suite; the generators' module docstrings record it.
examples/samples/pcapng.pyexercises the ISB on purpose, because it warns rather than raising and a fixture covering the code path is what will catch a future crash there.Line numbers are from
mainat 72f950d.