Skip to content

feat(protocols): add the IP_Pseudo pseudo-protocol for the IP pseudo-header (#2471) - #2479

Merged
JarryShaw merged 6 commits into
mainfrom
feat/2471-ip-pseudo-header
Nov 1, 2026
Merged

JarryShaw merged 6 commits into
mainfrom
feat/2471-ip-pseudo-header

Conversation

@JarryShaw

@JarryShaw JarryShaw commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

What is the purpose of your pull request?

  • feat — adds a feature

Description of your pull request and other information

Closes #2471. IP_Pseudo builds the IPv4 (RFC 793) or IPv6 (RFC 8200 §8.1) pseudo-header from an IPv4/IPv6 layer, explicit values, or both.

  • Home Address (RFC 6275 §11.3.1) replaces the IPv6 source; a Routing header with segments left gives its final address as the destination.
  • Source route (LSR, SSR, RFC 791 §3.1): while addresses are left, the last one is the destination; once exhausted, the header's.
  • UDP: the Length field (RFC 768), read past the IPv6 fixed and extension headers; jumbograms use their Jumbo Payload Length (RFC 2675).
  • Fragments and unparsed headers raise ProtocolError: a non-zero offset or More Fragments, a truncated or malformed header. An atomic fragment is a whole packet.
  • Upper layers: a Mobility Header or HIP is the upper layer (RFC 6275 §6.1.1, RFC 7401 §5.1.1). An IPv4 Authentication Header is walked as IPv6's is (RFC 4302), except in a non-first fragment; ESP (RFC 4303) raises on both, even under an SA.
  • Explicit src, dst, protocol, upper_length, zero override those read from ip, and an explicit protocol skips the UDP Length read; out-of-range lengths raise FieldValueError.

Testing: test_ip_pseudo_2471_unit.py (captured frames, walk cases, mutants), test_fields_misc.py (switch table), test_rfc_constants_one_home_1739_unit.py; ip_pseudo.py at 100% line and branch.

@JarryShaw JarryShaw added feat Pull requests that add a new capability (feat: subject prefix) review: running A cross-review is in flight against the current head - no verdict yet labels Oct 30, 2026
@github-actions github-actions Bot added this to the PyPCAPKit v1.5 milestone Oct 30, 2026
@JarryShaw JarryShaw moved this to In review in PyPCAPKit Oct 30, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES (Sonnet, fa706cf7a). The layout matches RFC 768/793/8200 §8.1 byte for byte on 26 captured or scapy-built packets (Routing types 0, 2 and 3 included), and coverage is 100%.

  • Silent wrong values. Out-of-range lengths wrap: jumbogram → 0xfffffff8, IPv4 total length 0 (TSO) → 0xffec, upper_length=65536 → 0000. Range-check derived and explicit values.
  • Segment Routing (type 4) uses the IPv6 destination instead of Segment List[0]; Home Address options (RFC 6275 §11.3.1) and fragments aren't handled. Implement them, or document the limits.
  • Tests don't pin a multi-address Routing header, IPv4 options, zero truncation, or the unparsed-next-header guard. Four mutants survive.
  • pep.rst still says the class is undefined (two places); IP_Pseudo is missing from the mermaid hierarchy. The 0-octet input raises StreamEOFError, contrary to Raises:.

@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 30, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Verified (cad600653): length ranges are checked (FieldValueError); a Home Address option replaces the source; non-final fragments and SRH-with-segments-left raise unless upper_length/dst is given, instead of producing a wrong value; pep.rst and the mermaid diagram are updated. Sonnet review dispatched.

@JarryShaw JarryShaw added review: running A cross-review is in flight against the current head - no verdict yet and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Oct 30, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES (Sonnet, cad600653). The fixes hold: range edges raise, Home Address and jumbograms are exact, and 1,298 real frames are byte-exact. Coverage is 100%, and the docs warnings equal main's.

  • Two existing tests fail: test_rfc_constants_one_home_1739 (nine re-inlined constants, e.g. 0xFFFF for IP_MAX_LENGTH) and test_the_address_typed_switch_table_is_complete (src/dst missing from the table). The PR body's "make test passes" is therefore false.
  • Still silently wrong:
    • UDP uses the IP payload length, not its Length field.
    • IPv4 LSRR/SSRR gives the header destination, not the last route slot.
    • MH and HIP over IPv6 are walked as extension headers.
  • Mutants: three survive: an IPv6 last fragment, two or more extension headers, and duplicate header types.
  • Malformed Destination Options or Routing headers raise a bare AttributeError.

@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 31, 2026
@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Coverage: 94.52% (unit tier, Python 3.15, 6f0ee0c17, Unit Tests run success)

Package Statements Missed Branches Partial Cover
pcapkit (top level) 104 4 20 2 95.16%
pcapkit/const 19700 133 2632 120 98.85%
pcapkit/corekit 2605 74 818 37 96.52%
pcapkit/dumpkit 281 3 100 3 98.43%
pcapkit/foundation 3070 24 1072 26 98.79%
pcapkit/interface 138 4 52 3 96.32%
pcapkit/protocols 18557 200 4926 187 98.34%
pcapkit/toolkit 924 36 334 10 95.55%
pcapkit/utilities 502 7 144 5 98.14%
pcapkit/vendor 4474 1864 1024 168 55.11%

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

@JarryShaw JarryShaw added review: pending No verdict for the current head - never reviewed, or the head moved since the last one review: running A cross-review is in flight against the current head - no verdict yet and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Oct 31, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES (Sonnet, a6f81030c). Prior failing tests now pass; the MH/HIP deviation is stated honestly.

  • LSRR/SSRR exhausted route: _destination returns the last recorded hop; RFC 791 says routing is based on the destination field. Use remaining[-1] only when remaining is non-empty; fix test_source_route_final_destination.
  • UDP Length: _udp_length is fed hdr_len, which stops at a Fragment header. Use IPV6_HEADER_LEN + before. Measured: 706 mismatches in ~20k chains, all this class.
  • IPv4+AH returns proto 51, len 32; IPv6 returns 17, 8. IPv4+ESP returns 50 silently, though make() promises a raise.
  • PR body is 24 non-blank lines; limit 15. make() prose runs ~20 lines before Args:; limit 8.

@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 31, 2026
@JarryShaw
JarryShaw force-pushed the feat/2471-ip-pseudo-header branch from a6f8103 to 3ccb925 Compare October 31, 2026 01:59
@JarryShaw JarryShaw added review: running A cross-review is in flight against the current head - no verdict yet and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Oct 31, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES (Sonnet, 3ccb92523). Prior findings are fixed and the regression tests fail on the old head.

  • ip_pseudo.py _upper (IPv4 AH, ~L484): mypy [assignment], an int into a TransType-typed code. Use Enum_TransType.get(...). The body's "make mypy" tick is false until this is fixed.
  • _upper IPv6 branch: an ESP SA walks ESP and returns 17, len 0 instead of raising. Stop the walk at ESP.
  • _upper IPv4: AH on a non-first fragment with upper_length takes the protocol from payload bytes; IPv6 raises. Raise here too, and add an AH+TCP test (the UDP Length currently masks a wrong before).

@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 31, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Rebase Note

Old head: 68f9e0f2e8e957fb23c775fd6720e91201924da7
New head: a442d20ff2e1e0b84cd0e66e73fce6a3a0d957b2

Changes from merge with origin/main:

This branch was rebased onto the current origin/main to resolve test failures caused by PR #2480 ("fix(protocols)!: parse a malformed IPv6 extension header as Raw (#2477) (#2480)").

Impact from #2480:

  • PR fix(protocols)!: parse a malformed IPv6 extension header as Raw (#2477) #2480 changed IPv6 extension header parsing so that malformed headers (those whose parsers raise exceptions) are now parsed as Raw instead of using a fallback parser
  • This affected IP_Pseudo's logic for detecting unparsed extension headers
  • The pseudo-header protocol detection was raising a generic "upper layer not parsed" error instead of the specific error messages the tests expected

Fix Applied:

  • Updated IP_Pseudo._upper() to detect when an extension header failed to parse and raise specific error messages (e.g., "Destination Options of IPv6 not parsed; give src")
  • Updated IP_Pseudo._source() to check for malformed Destination Options headers and raise appropriate errors
  • Updated IP_Pseudo._destination() to check for malformed Routing headers and raise appropriate errors
  • Fixed import ordering with isort

Test Results:

  • ✅ tests/protocols/misc/checksum/: 42 passed
  • ✅ tests/project/: 2132 passed, 1 fixed (isort formatting)
  • ✅ Total: 2174 passed

The fix maintains backward compatibility by providing more specific error messages when extension headers fail to parse, while falling back to the generic message for other unparsed scenarios.

@JarryShaw JarryShaw added review: running A cross-review is in flight against the current head - no verdict yet review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment review: running A cross-review is in flight against the current head - no verdict yet labels Oct 31, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Cross-review (Sonnet) at a442d20ff: NEEDS CHANGES, two defects.

  1. isort failure: pcapkit/protocols/misc/checksum/ip_pseudo.py's import block needs reformatting (make isort / tests/project/test_isort_clean.py catches it -- the '2174 passed' figure didn't include this tests/project run, which has 1 failure).
  2. _upper's malformed-extension-header detection sits inside try: ... except ValueError: pass, but ProtocolError subclasses ValueError, so the specific raise is dead code whenever the malformed header isn't the FIRST next-header (e.g. a valid Hop-by-Hop followed by a malformed Destination Options falls through to the generic message instead of the specific one). No wrong behavior slips through -- it still raises ProtocolError either way -- but the fix's own point (a more informative message) silently doesn't apply in that case. Move the raises out of the try, or narrow the except to only the Enum_ExtensionHeader(code) lookup.

Detection heuristic itself confirmed sound otherwise (no false positives across 5 probed scenarios). Fixing both now.

Two defects found in cross-review:

- isort flagged the import block (make isort / test_isort_clean.py).
- _upper's malformed-extension-header detection sat inside
  try: ... except ValueError: pass, but ProtocolError subclasses
  ValueError, so the specific raise was dead code -- any path that
  hit it fell through silently to the generic error. Narrowed the
  except to wrap only the Enum_ExtensionHeader(code) lookup, moving
  the raises outside it.

Verified: tests/protocols/misc/checksum/, test_isort_clean.py and
test_fields_misc.py pass clean (53 tests, 115 subtests).

A deeper, separate issue surfaced while testing this: when a
malformed extension header follows a VALID one rather than being the
IPv6 layer's direct next header, IPv6 itself drops it as NoPayload
(not Raw), so IP_Pseudo has no signal to detect that case at all.
Left out of scope here -- it is a gap in IPv6's own extension-header
handling, not something this fix's detection logic can work around.
@JarryShaw

Copy link
Copy Markdown
Owner Author

Pushed 6f0ee0c17: fixed both defects from the last review -- isort on the import block, and the dead except ValueError branch that was silently swallowing ProtocolError (narrowed the except to wrap only the enum lookup, moved the raises outside it). Verified: tests/protocols/misc/checksum/, test_isort_clean.py, test_fields_misc.py clean (53 tests, 115 subtests; ran this narrow set rather than the full tests/project/ since this host has been hitting resource-contention-driven collection failures under heavy concurrent load this session, unrelated to this change).

One thing deliberately left out: while testing the except-clause fix, I found a genuinely separate, deeper gap -- a malformed extension header that follows a VALID one (rather than being IPv6's direct next header) gets dropped by IPv6 itself as NoPayload, not Raw, so IP_Pseudo has no signal to detect that case at all. That's a gap in IPv6's own extension-header handling, not something this fix's detection logic can work around -- flagging rather than silently reverting.

@JarryShaw JarryShaw added review: running A cross-review is in flight against the current head - no verdict yet and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Oct 31, 2026
@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 31, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Cross-review (Sonnet) at 6f0ee0c17: GOOD TO GO. Both fixes from the last round confirmed correct: isort matches the exact Makefile invocation; the narrowed except ValueError genuinely can no longer swallow ProtocolError (traced Enum_ExtensionHeader's only possible exception), and valid-code behavior is unchanged. Full suite: 2104 passed, 2 failed -- both confirmed pre-existing on main too (sandbox-network timeouts, unrelated to this PR). No conflict markers. (This verdict should have posted several ticks ago -- it landed bundled with the #2504 investigation and got dropped; apologies for the delay.) Ready for merge -- your call.

…eader

# Conflicts:
#	pcapkit/protocols/data/__init__.py
#	pcapkit/protocols/schema/__init__.py

Co-authored-by: JarryShaw <15666417+JarryShaw@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat Pull requests that add a new capability (feat: subject prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Pseudo-protocol class for the IP pseudo-header (checksum/integrity groundwork)

2 participants