Skip to content

fix(transport): rebuild an SCTP packet cut short of its envelope's length (#2673) - #2679

Merged
JarryShaw merged 1 commit into
mainfrom
fix/2673-sctp-cut-rebuild
Nov 2, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
fix/2673-sctp-cut-rebuild

Conversation

@JarryShaw

Copy link
Copy Markdown
Owner

What is the purpose of your pull request?

  • fix — corrects a defect

Description of your pull request and other information

A capture cut short leaves the IPv4 Total Length or IPv6 Payload Length past the SCTP octets present. Schema_SCTP sized its chunk area by that length, so Schema.unpack recorded the cut on chunks while ChunkListField handed the octets after the last whole chunk to trailer. from_data(info) then dropped them, and bytes(schema) counted them again. SCTP parsed on its own was unaffected.

Schema_SCTP.unpack now reads no further than the octets present, since SCTP has no length field. A cut inside the last chunk's padding still records the short read on chunks. ChunkListField, ListField and make() are unchanged.

Tests cut packets of several chunks at every offset through IPv4, IPv6 and a declared length, with whole packets, own-length cuts and a cut inside the last chunk's padding as controls (padding cuts were already exact); each other cut test fails on main. All shipped captures parse identically to main.

Closes #2673

…ngth (#2673)

A capture cut short leaves the IPv4 Total Length or IPv6 Payload Length past
the SCTP octets present. The SCTP schema sized its chunk area by that length,
so Schema.unpack recorded the cut on chunks while ChunkListField handed the
octets after the last whole chunk to trailer: from_data(info) dropped them,
and bytes(schema) counted them again. Parsing SCTP on its own was unaffected.

- SCTP.unpack in the schema module reads no further than the octets present,
  as SCTP has no length field. ChunkListField and ListField are unchanged.
- With no octet after the last whole chunk, as for a cut inside its padding,
  the short read stays on chunks, where Schema.unpack records it.
- SCTP.make takes no new keyword: SCTP has no length to pass through.
- Tests: cuts at every offset through IPv4, IPv6 and a declared length, of
  packets of several chunks with parameters and causes; the schema on bytes
  and on a stream; whole packets and own-length cuts as controls; and an
  IPv4-carried case in the short-read sweep.

SCTP, maker-range, schema, sweep, option, doc-claim, member-order and RFC
modules pass; captures parse identically to main.
@JarryShaw JarryShaw added this to the PyPCAPKit v1.6 milestone Nov 2, 2026
@JarryShaw JarryShaw added bug Issues reporting a defect (set by the bug report template; a default, not an assessment) review: good-to-go Cross-review at the current head says ready; CI state is separate labels Nov 2, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO at 62819e86f. A Sonnet cross-review reproduced the cut-rebuild failure on main through IPv4, IPv6 and standalone bytes and stream input. On the commit it found every cut exact, and every shipped capture's parse byte-identical to main. It confirmed the schema override is the only layer that sees the octets present, and that the type: ignore comments are needed. Eight mutants of the override were all killed. Its two wording nits are folded in; the code is unchanged from e725be1cc.

@JarryShaw
JarryShaw merged commit fc407c3 into main Nov 2, 2026
25 checks passed
@JarryShaw
JarryShaw deleted the fix/2673-sctp-cut-rebuild branch November 2, 2026 19:27
@github-project-automation github-project-automation Bot moved this to Done in PyPCAPKit Nov 2, 2026
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Nov 2, 2026
JarryShaw added a commit that referenced this pull request Nov 2, 2026
…TTP/2 and SCTP rebuilds into 1.6.0 (#2449)

- Breaking: the IPv4, HOPOPT, IPv6-Opts, IPv6-Route, MH and HIP makers
  (#2677) raise on a value a field cannot hold, where 1.5.x wrote it
  masked; a PDM scale past one octet raises where it warned, and
  MH._decode_signed is removed. The entry gives the old and new values.
- Fixed: an SCTP packet cut short of its declared length rebuilds as
  captured (#2679).
- Folded into unreleased entries: a cut HTTP/2 frame after the connection
  preface rebuilds, into the cut-SETTINGS entry (#2675); IPv4's Quick-Start
  function and not-used octet refusals, into the Quick-Start entry (#2677).
- No entry for the test-only 42a6133.
- CHANGELOG.md regenerated; util/changelog_md.py --check passes.
JarryShaw added a commit that referenced this pull request Nov 2, 2026
…ta ends (#2680)

Schema.unpack gave back a cut OptionField area's remainder by its declared
width, keeping and rewinding octets never read, and charged the cut to the
field before it parsed; #2679's SCTP.unpack override worked round that for
SCTP alone and could not read a stream that does not seek. padding_length
capped SCTP padding at the octets left, so a chunk cut inside it packed at
full width: 34 octets in, 36 out.

- Schema.unpack gives back no more of the remainder than it read, and charges
  the cut to the option field only when none is given back.
- ChunkListField reports its remainder in declared terms; the override is gone.
- padding_length returns the padding the Length calls for. OptionField.unpack
  asks _accepts_short_read before refusing a short option (#1325), and
  refuses by default, since a general padding rule accepts the PadN overruns
  #1325 refuses; PaddedOptionField accepts SCTP's, which the Length leaves out.
- Tests: SCTP items cut at every padding offset, alone, nested and bundled, on
  bytes, streams and envelopes; a TCP option area cut at every offset; SCTP on
  a stream that cannot seek. #2679's tests pass unchanged.

Every unittest leg passes; captures parse identically to main.

Closes #2680
Closes #2685
JarryShaw added a commit that referenced this pull request Nov 3, 2026
…ta ends (#2680)

Schema.unpack gave back a cut OptionField area's remainder by its declared
width, keeping and rewinding octets never read, and charged the cut to the
field before it parsed; #2679's SCTP.unpack override worked round that for
SCTP alone and could not read a stream that does not seek. padding_length
capped SCTP padding at the octets left, so a chunk cut inside it packed at
full width: 34 octets in, 36 out.

- Schema.unpack gives back no more of the remainder than it read, and charges
  the cut to the option field only when none is given back.
- ChunkListField reports its remainder in declared terms; the override is gone.
- padding_length returns the padding the Length calls for. OptionField.unpack
  asks _accepts_short_read before refusing a short option (#1325), and
  refuses by default, since a general padding rule accepts the PadN overruns
  #1325 refuses; PaddedOptionField accepts SCTP's, which the Length leaves out.
- Tests: SCTP items cut at every padding offset, alone, nested and bundled, on
  bytes, streams and envelopes; a TCP option area cut at every offset; SCTP on
  a stream that cannot seek; an SCTP item overrunning its chunk, still refused;
  an option reporting more than it read. #2679's tests pass unchanged.

Every unittest leg passes; captures parse identically to main.

Closes #2680
Closes #2685
JarryShaw added a commit that referenced this pull request Nov 3, 2026
…ta ends (#2680) (#2682)

Schema.unpack gave back a cut OptionField area's remainder by its declared
width, keeping and rewinding octets never read, and charged the cut to the
field before it parsed; #2679's SCTP.unpack override worked round that for
SCTP alone and could not read a stream that does not seek. padding_length
capped SCTP padding at the octets left, so a chunk cut inside it packed at
full width: 34 octets in, 36 out.

- Schema.unpack gives back no more of the remainder than it read, and charges
  the cut to the option field only when none is given back.
- ChunkListField reports its remainder in declared terms; the override is gone.
- padding_length returns the padding the Length calls for. OptionField.unpack
  asks _accepts_short_read before refusing a short option (#1325), and
  refuses by default, since a general padding rule accepts the PadN overruns
  #1325 refuses; PaddedOptionField accepts SCTP's, which the Length leaves out.
- Tests: SCTP items cut at every padding offset, alone, nested and bundled, on
  bytes, streams and envelopes; a TCP option area cut at every offset; SCTP on
  a stream that cannot seek; an SCTP item overrunning its chunk, still refused;
  an option reporting more than it read. #2679's tests pass unchanged.

Every unittest leg passes; captures parse identically to main.

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

Labels

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

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

fix(transport): an SCTP packet cut short by the capture does not rebuild as captured

1 participant