What is wrong
pcapkit/foundation/engines/pcapng.py:218 rejects a Simple Packet Block in any section that does not have exactly one interface:
elif block.info.type == Enum_BlockType.Simple_Packet_Block:
if len(self._ctx.interfaces) != 1:
raise FormatError(f'PCAP-NG: [SPB] invalid section with {len(self._ctx.interfaces)} interfaces')
break
The format permits a multi-interface section to contain an SPB. § 4.4 of draft-ietf-opsawg-pcapng:
As a Simple Packet Block does not contain an Interface ID field, in a Section that has more than one interface, only packets received or transmitted on the interface described by the first Interface Description Block can be contained in a Simple Packet Block; packets received or transmitted on any other interface MUST be contained in an Enhanced Packet Block.
So a multi-interface section is legal; the SPB simply refers to the first IDB. The condition that is actually invalid is zero interfaces, and != 1 gets that case right only by accident of also rejecting everything else.
pcapkit already implements the "first IDB" rule elsewhere — PCAPNG._get_snaplen (pcapkit/foundation/engines/pcapng.py:297) returns self._ctx.interfaces[0].snaplen, and falls back to 0xFFFF_FFFF_FFFF_FFFF when there is no interface at all — so the parser is built for it and only this guard stands in the way.
Symptom
A spec-conformant capture is refused outright:
[CRITICAL] FormatError: PCAP-NG: [SPB] invalid section with 2 interfaces
pcapkit.utilities.exceptions.FormatError: PCAP-NG: [SPB] invalid section with 2 interfaces
And the case the check ought to catch is not caught: an SPB in a section with no IDB at all gets past the guard and dies further down, in _get_linktype:
File ".../pcapkit/protocols/misc/pcapng.py", line 1611, in _read_block_spb
File ".../pcapkit/protocols/misc/pcapng.py", line 1207, in _get_linktype
IndexError: list index out of range
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))
spb = lambda d: block(0x00000003, struct.pack('<I', len(d)) + pad4(d))
ETH = bytes.fromhex('ffffffffffff001122334455') + b'\x08\x06' + b'\x00' * 28
import pcapkit
cases = {
'two IDBs (legal per 4.4)': shb() + idb() + idb() + spb(ETH),
'one IDB (control)': shb() + idb() + spb(ETH),
'no IDB (truly invalid)': shb() + spb(ETH),
}
for name, blob in cases.items():
open('/tmp/spb.pcapng', 'wb').write(blob)
try:
ext = pcapkit.extract(fin='/tmp/spb.pcapng', store=True, nofile=True)
print(f'{name}: {len(ext.frame)} frame(s)')
except Exception as exc:
print(f'{name}: {type(exc).__name__}: {exc}')
two IDBs (legal per 4.4): FormatError: PCAP-NG: [SPB] invalid section with 2 interfaces
one IDB (control): 1 frame(s)
no IDB (truly invalid): IndexError: list index out of range
What a fix would need to touch
The condition at line 218 becomes a test for an empty interface list — if not self._ctx.interfaces: — with a message saying the section has no Interface Description Block. That both accepts the legal multi-interface case and turns the zero-interface IndexError into a proper FormatError.
How it was found
While building deterministic sample captures for the test suite. The generators' module docstrings record it: examples/samples/pcapng.py works around it by putting test.pcapng's Simple Packet Block in a single-interface second section, so the block type stays covered, and quotes § 4.4 as the reason it is a workaround rather than a fix.
Line numbers are from main at 72f950d.
What is wrong
pcapkit/foundation/engines/pcapng.py:218rejects a Simple Packet Block in any section that does not have exactly one interface:The format permits a multi-interface section to contain an SPB. § 4.4 of draft-ietf-opsawg-pcapng:
So a multi-interface section is legal; the SPB simply refers to the first IDB. The condition that is actually invalid is zero interfaces, and
!= 1gets that case right only by accident of also rejecting everything else.pcapkitalready implements the "first IDB" rule elsewhere —PCAPNG._get_snaplen(pcapkit/foundation/engines/pcapng.py:297) returnsself._ctx.interfaces[0].snaplen, and falls back to0xFFFF_FFFF_FFFF_FFFFwhen there is no interface at all — so the parser is built for it and only this guard stands in the way.Symptom
A spec-conformant capture is refused outright:
And the case the check ought to catch is not caught: an SPB in a section with no IDB at all gets past the guard and dies further down, in
_get_linktype:Reproduction
What a fix would need to touch
The condition at line 218 becomes a test for an empty interface list —
if not self._ctx.interfaces:— with a message saying the section has no Interface Description Block. That both accepts the legal multi-interface case and turns the zero-interfaceIndexErrorinto a properFormatError.How it was found
While building deterministic sample captures for the test suite. The generators' module docstrings record it:
examples/samples/pcapng.pyworks around it by puttingtest.pcapng's Simple Packet Block in a single-interface second section, so the block type stays covered, and quotes § 4.4 as the reason it is a workaround rather than a fix.Line numbers are from
mainat 72f950d.