Skip to content

fix(protocols): a later IPv6 fragment's data is raw, not an upper-layer header (#1545) - #1552

Merged
JarryShaw merged 1 commit into
mainfrom
fix/1545-ipv6-nonfirst-fragment
Oct 10, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
fix/1545-ipv6-nonfirst-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

Closes #1545.

After #1540 a Fragment header with a non-zero offset ends the extension-header walk, but IPv6._decode_next_layer still dispatched the rest on its Next Header. So ipv6.pcap frames 14–16 read as IPv6-Frag:UDP:Raw with garbage ports. Now no code is dispatched for a known non-zero offset, and the rest is a Raw leaf with no protocol alias. Frames 14–16 read Ethernet:IPv6:IPv6-Frag:Raw, which matches tshark (ipv6.fraghdr:data), and 'UDP' in frame is false.

  • protocol still names the first fragment's upper layer, and fragment/hdr_len/raw_len are unchanged. Reassembled datagrams over every capture under examples/captures/ are identical before and after (IPv6: one 4778-octet datagram from frames 13–16).
  • A Fragment header parsed with no offset (IPv6_Ext stand-in) still dispatches as before, since it is not known to be a later fragment.
  • Tests: the new test_ipv6_later_fragment_raw_unit.py covers UDP and TCP at four offsets, M set and clear, make→parse, and a first/atomic-fragment guard. test_ipv6_extension_runtime.py covers frames 14–16; its frame-16 chain pin had encoded the bug. Round trips stay byte-exact.
  • The dpkt and scapy engines already read these frames as raw (bytes and Raw). No Gap rows cite fix(protocols): a non-first IPv6 fragment's data is dissected as an upper-layer header #1545.

…er header (#1545)

A Fragment header with a non-zero offset ended the extension header walk
(#1539), but the octets after it were still dispatched on its Next Header,
so a slice from the middle of a UDP or TCP datagram read as a UDP or TCP
header. RFC 8200 section 4.5 puts that header in the first fragment only,
so a later fragment's data is now a Raw leaf with no protocol alias.
``protocol`` still names the first fragment's upper layer, and the split
that reassembly takes is 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

Copy link
Copy Markdown
Owner Author

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

  • Behaviour: ipv6.pcap frames 14–16 now chain Ethernet:IPv6:IPv6-Frag:Raw, which matches tshark (data). Frame 13 is unchanged. Across 1,590 frames in every capture, no other chain changes, and reassembly gives 1,571 datagrams hash-identical to main.
  • 24 hand-built cases:
    • A later fragment stays Raw behind HBH, Routing, Dest-Opts, AH and combinations of them, whatever its Next Header.
    • First and atomic fragments still dissect.
  • Round trips: all 16 ipv6.pcap frames are byte-exact through from_data(info), from_data(info.to_dict()) and re-parse.
  • Fail-before: the PR's tests give 21 failed on main's ipv6.py.
  • With fix(toolkit): the pypcapfile engine warns that it leaves TCP over IPv6 out (#1513) #1535: merged together, test_pypcapfile_unit.py gives 35 passed in 3.11.

One reviewer finding I refuted: the review asked for a test pinning the "offset unknown" guard (ipv6.py:625), saying an opaque = True mutant survives. I ran that mutant. It is killed by the existing test_ipv6_unit.py::test_ipv6_decode_next_layer_handles_extension_headers_and_fragments (None != <TransType.UDP: 17>). The review had not run that file, so no change is needed.

Not blocking:

@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
@github-actions

Copy link
Copy Markdown
Contributor

Coverage: 90.02% (unit tier, Python 3.14, 50cbc5f21, 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 2204 67 712 34 96.26%
pcapkit/dumpkit 258 2 90 2 98.85%
pcapkit/foundation 2797 132 986 48 94.18%
pcapkit/interface 108 7 36 5 91.67%
pcapkit/protocols 16994 229 4546 190 98.03%
pcapkit/toolkit 635 98 198 5 83.31%
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
JarryShaw merged commit b0bf4b9 into main Oct 10, 2026
41 checks passed
@JarryShaw
JarryShaw deleted the fix/1545-ipv6-nonfirst-fragment branch October 10, 2026 03:37
@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 added a commit that referenced this pull request Oct 10, 2026
…er header (#1553) (#1562)

A datagram with a non-zero Fragment Offset now passes no next-layer code to
_decode_next_layer, so its data is a Raw leaf with no protocol name, as
Wireshark shows it, instead of a bogus UDP/TCP header read from mid-datagram
octets. info.protocol, the lengths and packet.payload are unchanged, so
reassembly and every round trip are too. First fragments and unfragmented
datagrams are still dissected. Mirrors #1552's IPv6 fix for #1545.
@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): a non-first IPv6 fragment's data is dissected as an upper-layer header

1 participant