Skip to content

IPv4 SEC option: the writer emits an option its own reader rejects, and IndexErrors on a single authority of value 0 #537

Description

@JarryShaw

IPv4._make_opt_sec writes a SEC option that IPv4._read_opt_sec rejects, and raises IndexError on a single low-numbered authority.

Found while verifying #536's fixture evidence, not by reading the code looking for trouble: the project's own generated capture examples/captures/options-ipv4.pcap emits a warning on main today.

ProtocolWarning: IPv4: [OptNo 130] invalid format: field termination indicator not set

That capture is produced by examples/generators/options.py, which builds the option through IPv4.make. So the library's writer produces a SEC option its own reader flags as malformed.

Three distinct defects, all in pcapkit/protocols/internet/ipv4.py, all measured on 733000f65 (equivalent to origin/main c8fd97bcd).

1. The writer never sets the field termination indicator

RFC 1108 §2.2 gives bit 0 of each protection-authority octet as the field termination indicator: 0 means another octet follows, 1 means this is the last. The reader enforces it at ipv4.py:752-753:

if schema.data[-1] & 0x01 == 0:
    warn(f'{self.alias}: [OptNo {schema.type}] invalid format: field termination indicator not set', ProtocolWarning)

_make_opt_sec at ipv4.py:1387-1393 builds data purely from the authority bit positions and never sets that bit:

>>> ip._make_opt_sec(OptionNumber.SEC, authorities=[ProtectionAuthority.GENSER,
...                                                 ProtectionAuthority.NSA]).data
b'\x90'          # 0x90 & 0x01 == 0  ->  own reader warns

Every SEC option the library writes with at least one authority is therefore malformed on the wire, unless the caller happens to pick authority 7 (see defect 3).

2. IndexError escapes on a single authority whose value is 0

int_len = math.ceil(max_auth / 8) at ipv4.py:1389 is off by one: it sizes the bitmap from the highest bit index rather than from the bit count. With the only authority being GENSER (value 0), int_len is 0, data_list is empty, and data_list[0] = b'1' raises:

>>> ip._make_opt_sec(OptionNumber.SEC, authorities=[ProtectionAuthority.GENSER])
IndexError: list assignment index out of range

Two consequences. It is a bare IndexError out of a _make_opt_* helper rather than an in-library exception from pcapkit.utilities.exceptions. And examples/generators/options.py:469-472 already documents a workaround for it in a comment rather than the library being fixed:

A single authority whose value is 0 makes _make_opt_sec compute a zero-octet bitmap and then index into it; two keeps it non-empty.

The off-by-one is also latent for max_auth == 8, which would need two octets and computes one. No enum member has value 8 today, so that half is not currently reachable.

3. Authority index 7 collides with the terminator bit, and the reader can never read it back

Enum_ProtectionAuthority member 7 is named Field_Termination_Indicator — it is not an authority at all, yet it is a member of the enum the writer accepts as one. Passing it produces an option that reads as validly terminated while carrying no authority:

>>> ip._make_opt_sec(OptionNumber.SEC, authorities=[ProtectionAuthority.Field_Termination_Indicator]).data
b'\x01'          # terminator set, zero authorities encoded

Symmetrically, the reader's loop at ipv4.py:741 is for bit in range(7), deliberately excluding bit 7. So a real authority written at index 7 is silently dropped on read. Writer and reader disagree about whether index 7 is data.

Suggested shape of the fix

  • Size the bitmap from the bit count, math.ceil((max_auth + 1) / 8), and raise an in-library exception instead of letting IndexError escape.
  • Set bit 0 of the final octet after building the bitmap, so the writer's output satisfies the reader.
  • Reject Field_Termination_Indicator as an authority argument rather than encoding it, since the enum names it as a structural bit.
  • Once the writer is correct, the warning should disappear from examples/captures/options-ipv4.pcap, which makes the fixture a regression test for free.

Coverage note

A test asserting that IPv4.make output round-trips through IPv4 without a ProtocolWarning would have caught defect 1 from the start; the existing option round-trip suite tolerates warnings.

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