Skip to content

fix(protocols): dissect an IPv6 extension header behind a first fragment as without it (#1539) - #1540

Merged
JarryShaw merged 1 commit into
mainfrom
fix/1539-ipv6-ext-after-fragment
Oct 10, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
fix/1539-ipv6-ext-after-fragment

Conversation

@JarryShaw

Copy link
Copy Markdown
Owner

Please follow the guide below

What is the purpose of your pull request?

Tick the commit type your subject line carries.

  • fix — corrects a defect
  • feat — adds a feature
  • perf — changes performance, not behaviour
  • refactor — changes neither behaviour nor performance
  • test — tests only
  • docs — documentation only
  • ci — workflows or build tooling
  • release — bumps the version or rolls up a distribution
  • chore — anything else

Description of your pull request and other information

IPv6._decode_next_layer stopped its extension-header walk at every Fragment header. Whatever came next went to the upper-layer dispatch, which passes neither extension=True nor version=6. Shim6 is registered (to IPv6_Ext), but it failed IPv6_Ext's version gate. A zero-filled HIP header, or a Routing header of type 3, raised in its own parser, and nothing stood in for it. Each one became a Raw leaf, so the TCP behind it was never reached.

  • RFC 8200 §4.5 requires the first fragment (offset 0) to carry every header up to and including the upper-layer one. So the walk now continues past that Fragment header, exactly as it would without one. In a later fragment, the bytes after the Fragment header are a slice of the Fragmentable Part and start with no header, so the walk still stops there.
  • fragment, hdr_len and raw_len keep the split at the first Fragment header, because toolkit/pcap.py:116 reassembles from it.
  • _lookup_exthdr applies the same rule when it rebuilds from to_dict(), and skips the fragment key. Without that, the rebuild drops the header that follows the Fragment header.

The new tests/protocols/internet/test_ipv6_ext_after_fragment_unit.py gets 8 failures on main. to_dict() digests of all 247 IPv6 frames in examples/captures/ are unchanged. These selections all pass, run one at a time: tests/protocols/internet, each tests/protocols/test_*roundtrip*, tests/project, tests/test_docstring_contract.py and tests/test_tier_guard.py.

Closes #1539

…ent as without it (#1539)

- IPv6._decode_next_layer ended its extension header walk at every Fragment
  header, so a header behind it went to the upper-layer dispatch, without
  extension=True or version=6: Shim6 failed IPv6_Ext's version gate, and a
  zero-filled HIP or a Routing type 3 header raised with no IPv6_Ext to stand
  in, leaving a Raw leaf and no TCP. The walk now goes on past a first
  fragment (offset 0), as RFC 8200 section 4.5 puts every header through the
  upper-layer one there; a later fragment still ends it.
- fragment, hdr_len and raw_len keep the split at the first Fragment header,
  which IPv6 reassembly takes.
- IPv6._lookup_exthdr follows the same rule when rebuilding from to_dict, and
  passes over the fragment key.

tests/protocols/internet: 455 passed; IPv6 frames in examples/captures: 247,
to_dict digests unchanged.
@JarryShaw JarryShaw added fix Pull requests that fix a defect (fix: subject prefix) review: running A cross-review is in flight against the current head - no verdict yet labels Oct 10, 2026
@JarryShaw JarryShaw moved this to In review in PyPCAPKit Oct 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage: 90.09% (unit tier, Python 3.14, d294bca19, Unit Tests run success)

Package Statements Missed Branches Partial Cover
pcapkit (top level) 104 4 20 4 93.55%
pcapkit/const 18795 842 2356 756 92.09%
pcapkit/corekit 2186 67 710 34 96.24%
pcapkit/dumpkit 258 2 90 2 98.85%
pcapkit/foundation 2665 98 934 42 95.00%
pcapkit/interface 112 7 40 5 92.11%
pcapkit/protocols 17016 229 4578 190 98.03%
pcapkit/toolkit 539 74 168 3 84.58%
pcapkit/utilities 431 4 124 4 98.56%
pcapkit/vendor 4409 2342 1006 157 43.25%

Per-file detail: the coverage-html artifact of this run.

@JarryShaw

Copy link
Copy Markdown
Owner Author

Verdict: GOOD TO GO at d294bca19. Cross-reviewed on Sonnet; the author ran Opus.

  • Fixed. Frag(0) followed by Shim6, zero-filled HIP, or Routing type 3, then TCP now dissects as the direct form does (…IPv6-Frag:IPv6-Ext:TCP:Raw). A Fragment with offset > 0 still stops the walk.
  • Byte-identical. All 247 sample IPv6 frames match main on protochain, to_dict(), and both rebuild paths.
  • Fuzzed 3,000 random chains.
    • Nothing raised.
    • The Frag(0) form agrees with the same bytes with the Fragment header spliced out in 1,975 of 1,975 cases, against 725 on main.
    • Non-fragmented records are identical.
  • Reassembly unchanged. hdr_len, raw_len, fragment and the toolkit reassembly record are identical across all fuzz cases and 12 synthetic two-fragment datagrams.
  • Tests. Fail-before is 8. 5 of 8 mutations are killed.
  • Merges cleanly into current main. The internet and round-trip suites pass on the merged tree.

Non-blocking:

  • The visible change is a little wider than the PR body says. After a Frag(0)+header, info.protocol becomes the upper layer, which the Data_IPv6 docstring already promised. ip.payload changes type, and Frag(0)+ESP loses its Raw leaf, matching direct ESP.
  • 3 mutation survivors are untested edge branches (a second Fragment header, a missing offset).

Non-first fragments being dissected on main is filed separately.

@JarryShaw JarryShaw added review: good-to-go Cross-review at the current head says ready; CI state is separate and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 10, 2026
@JarryShaw
JarryShaw merged commit f4243bc into main Oct 10, 2026
41 checks passed
@JarryShaw
JarryShaw deleted the fix/1539-ipv6-ext-after-fragment branch October 10, 2026 01:57
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Oct 10, 2026
@JarryShaw JarryShaw added this to the PyPCAPKit v1.5 milestone Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Pull requests that fix a defect (fix: subject prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

fix(protocols): an IPv6 extension header behind a Fragment header stops TCP dissection

1 participant