Repository navigation
feat(foundation): reassemble fragmented DTLS handshake messages - #2451
Conversation
59937ed to
cbc6e7f
Compare
|
Rebased onto #2441's current tip (your branch had diverged since #2441 was rebased twice after you forked from it) — old head |
cbc6e7f to
158be85
Compare
|
Fixed and verified directly (new head |
|
Cross-review (different model, adversarial), round 3, came back NEEDS CHANGES. All 6 round-2 items are confirmed fixed for well-formed input, but the new conditional branches left gaps: Blocking:
Should-fix: Dispatching a fix now. |
158be85 to
679aa41
Compare
|
Fixed and verified directly (new head |
|
Round 4 review: NEEDS CHANGES. The 3 round-3 blockers are genuinely fixed. New issues: (1) no test for round 4's own idle-deadline change, (2) a new wrong §4.2.2 claim introduced this round (message_seq doesn't reset per-epoch mid-flight, no code impact since encrypted records never reach the engine, but the doc claim is false), (3) a stale Buffer.timestamp docstring. Should-fix: round 3's same-length-splice item was silently dropped without a mention either way; #2468's repro numbers need correcting (16MiB not 320MiB for the literal repro, though a length cap fixes the real variant too). Fixing now. |
1. Add test for idle-deadline extension: three fragments at t=0, t=100, t=200s complete with 120s timeout, verifying max(buf.timestamp, TS) logic extends deadline on each arrival. Fails if reverted back to buf.timestamp. 2. Remove incorrect claim about epoch changes and message_seq numbering. RFC 6347 §4.2.2 says message_seq restarts per handshake, not per epoch/flight. Epoch changes begin a fresh buffer (for replay protection), not a new flight. Updated in both dtls.py (lines 49-54) and data/dtls.py (lines 24-32). 3. Fix stale docstring for Buffer.timestamp: was claiming "first fragment, doesn't extend deadline", now correctly states "most recent fragment with idle deadline". Reflects round 4's max(buf.timestamp, TS) behavior. 4. Address same-length-splice known limitation: soften overclaim that guard against different length/type prevents all splicing. Explicitly document that same-length/type fragments from displaced messages can still splice into newer buffers -- a known gap resolved by #2451 tracking. 5. Fix test docstring nit in test_epoch_change_opens_a_fresh_buffer: was incorrectly stating "sequence numbers and fragment offsets reset" (old, fixed behavior), now correctly describes epoch change buffer isolation. 6. Item 6 (__protocol_name__ comment) already addressed in current codebase.
|
Fixed round 5's items (new head |
|
GOOD TO GO (Sonnet, |
|
Red required check on |
|
Rebase note: the red check was the toctree test. This branch predated the convention doc, so the one-line fix was not enough: 9 convention tests failed. Fix: merged origin/main into the branch (a merge commit, not a rebase, so the push is a fast-forward). Merged head runs 71 passed in the convention and DTLS reassembly files. Patch-id of the PR's own commit is unchanged. Owner can merge once the review passes. |
|
GOOD TO GO (Sonnet, |
- add foundation.reassembly.dtls.DTLS, keyed by UDP 4-tuple and DTLS epoch - DTLS.read decodes the fragment completing a handshake message into ClientHello/ServerHello - overlapping fragments are accepted (RFC 6347 4.2.3) - opt-in only; Extractor-level wiring left as a follow-up - isort-clean reassembly and DTLS modules - DTLS.read reassembles only the datagram's first record (Known Limitations) Tests: tests/foundation/reassembly/ -- 197 passed, 897 subtests.
RFC 6347 section 4.2.3 and RFC 9147 section 5.5 give DTLS handshake reassembly no timeout, so the invented 120 second __timeout__ and the time-based expiry that enforced it are removed. DTLS now inherits the base default of math.inf, and a buffer is held until its messages complete. - reassembly/dtls.py: drop __timeout__ and the timeout argument of DTLS.__init__; drop the expire() call and the idle-deadline refresh in reassembly(). submit() keeps its base-contract timeout argument. - reassembly/data/dtls.py, protocols/application/dtls.py: timestamps are recorded only and no longer described as driving a timer. - docs: drop the __timeout__ autoattribute. - tests: the expiry test now asserts a stale buffer is held and completes; the idle-deadline test asserts delayed fragments complete.
|
Rebased onto main after #2443/#2491 landed, new head |
|
What needs my decision? Context, recommendations and label. |
|
Decision needed: merge #2451 now or hold for rework. Context: the new reassembly-integration convention (point 1) says a protocol class stays unaware of reassembly — IP and TCP already comply, calling into reassembly only through |
|
Take (a) |
|
Ruling applied: merge as reviewed. The reassembly-architecture rework is tracked separately as #2496, blocked until this merges. |
|
|
||
| .. versionadded:: 1.6.0 | ||
|
|
||
| .. versionchanged:: 1.6.0 |
There was a problem hiding this comment.
don't need this version changed prose. It's only added in the same version.
There was a problem hiding this comment.
Fixed post-merge: pushed c6b3848d1 to main, dropping the versionchanged block. This sat unaddressed through the merge -- caught when you flagged it again directly.
|
Added inline comments and changelog should be done in the central issue/pr, not individual ones. Are we tracking or working on the analysis method for reassembled DTLS body? |
|
Confirmed standing practice already: no commit pushed today touched |
|
Take (a) |
|
Ruling applied: folded into #2496. |
|
Correction, my own error. My earlier "regression fixed, 21 passed" claim was wrong. |
…ages SSL._make_tls_handshake_messages was defined twice. Python binds the second definition (further down the class body), which shadowed the first and dropped its fragment-slicing logic -- a completing DTLS fragment's body_bytes was never re-sliced back to its own byte range before re-encoding. test_completing_record_rebuilds_byte_exact in tests/foundation/reassembly/test_dtls_handshake_reassembly_2440_unit.py exercises exactly this path. Confirmed it fails on the pre-fix head (2dc85e9) and passes once the broken second definition is removed, keeping the first (correct) one.
|
Pushed Verified the regression and the fix directly: |
pep.rst still said reassembly was 'Not done' and listed it among the wave-2 DTLS gaps. This PR implements it (see pcapkit.foundation.reassembly.dtls.DTLS and the reassembly=/flow= arguments on pcapkit.protocols.application.dtls.DTLS), so rewrite both mentions to describe the actual behaviour instead.
|
Pushed |
|
Cross-review (Sonnet) at |
Please follow the guide below
make pylint,make mypy,make isort)make testpasses, and a test case covers the changedocs/source/changelog/and regeneratedCHANGELOG.md, if the change is user-visible — N/A, centralisedWhat is the purpose of your pull request?
feat— adds a featureDescription of your pull request and other information
Closes #2440. Targets
main, on top of #2441 (merged).Adds
pcapkit.foundation.reassembly.dtls.DTLS, keyed by UDP 4-tuple plus DTLS epoch.DTLS.read(reassembly=..., flow=...)decodes the fragment that completes a handshake message intoClientHello/ServerHello. Overlapping fragments are accepted.Opt-in only. Automatic
Extractor-level wiring needs a toolkit adapter and changes to all eight capture engines, so it is left as a follow-up.Ran:
tests/foundation/reassembly/197 passed (897 subtests), including the new overlap test, which fails when overlapping fragments are dropped.isort -l100clean on changed files.Not run:
make test,make pylint,make mypy.