Skip to content

Simple Packet Block rejected in any multi-interface section #347

Description

@JarryShaw

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIssues reporting a defect (set by the bug report template; a default, not an assessment)

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions