Skip to content

ipv6_opts' SMFIdentificationBasedDPDOption has a stray test field HOPOPT lacks, so identical octets fail there #441

Description

@JarryShaw

SMFIdentificationBasedDPDOption in pcapkit/protocols/schema/internet/ipv6_opts.py declares a test ForwardMatchField that its HOPOPT twin does not. The two modules are otherwise line-for-line equivalents, and this one extra field makes the same octets parse under HOPOPT and fail under IPv6-Opts.

The difference

Enumerating the class body from origin/main (c28ffc287):

hopopt.py     SMFIdentificationBasedDPDOption fields = ['info', 'tid', 'id']
ipv6_opts.py  SMFIdentificationBasedDPDOption fields = ['test', 'info', 'tid', 'id']
                                                        ^^^^^^ line 434
# pcapkit/protocols/schema/internet/ipv6_opts.py:434
    test: 'SMFDPDTestFlag' = ForwardMatchField(BitField(length=1, namespace={
        'mode': (0, 1),
    }))

Normalising both modules for their protocol names leaves ten differing lines: a module docstring, a five-line explanatory comment, and these three.

Why it is a stray rather than intentional

  • The enclosing _SMFDPDOption already declares a test ForwardMatchField (length=3), in both modules.
  • Nothing reads the nested one. smf_dpd_data_selector reads pkt['test']['mode'] and pkt['test']['len'], and that pkt is the enclosing schema's.
  • It is the only field in the class carrying no #: comment, unlike info, tid and id around it.

It predates #432, which neither added nor removed it.

Effect

ForwardMatchField consumes nothing from the stream but still occupies a slot in __buffer__, so it counts toward len(schema). The nested schema therefore over-reports its length by one octet, and OptionField accumulates that over-report against the declared option area until the area check fails.

Same wire layout, same octets, different outcomes — built through HOPOPT as 1100080100010100, option area 080100010100:

                 len(schema)
hopopt                 3        <- correct
ipv6_opts              4        <- one too many

HOPOPT(built, 8, extension=True)     -> options=[SMF_DPD, PadN]
IPv6_Opts(built, 8, extension=True)  -> ProtocolError: IPv6-Opts: invalid format

The error is raised at pcapkit/protocols/internet/ipv6_opts.py:497, the option-area threshold check in _read_ipv6_opts, reached from read at :315 via options=self._read_ipv6_opts(schema.len * 8 + 6) and unpack → __post_init__ at protocols/protocol.py:678.

Byte-for-byte identical on Python 3.10.20 and 3.14.7, so unlike the PCAP-NG failures in #439 this is not interpreter-dependent.

Provenance

Surfaced by the option round-trip harness in #440, which records ipv6-opts-option/SMF_DPD as a PARSE gap. Two corrections happened on the way to it and are worth recording, since both were wrong in ways that looked right:

Not fixed in #440 deliberately: that PR keeps git diff origin/main -- pcapkit/ empty, which is what makes a 258-case harness reviewable.

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