Repository navigation
TCP._make_mptcp_capable writes length 20/32 where RFC 8684 gives 12/20, and now packs wrong bytes rather than crashing #567
Description
Activity
- addedbugIssues reporting a defect (set by the bug report template; a default, not an assessment)Issues reporting a defect (set by the bug report template; a default, not an assessment)
on Sep 21, 2026 - added a commit that references this issue
on Sep 21, 2026 Scope correction: the maker's arithmetic is only half of it.
MPTCPCapable.rkey's own predicate is independently wrong and directly contradicts the maker, so fixing the maker alone would leave the defect half-live.Found during #565's cross-review, and verified against
origin/main:pcapkit/protocols/schema/transport/tcp.py:667-670rkey: 'int' = ConditionalField( UInt64Field(), lambda pkt: pkt['length'] != 32, )
So the receiver key is included when
length != 32— that is, dropped whenlength == 32. But_make_mptcp_capablewriteslength=20 if rkey is None else 32, meaning it signals rkey present with the single value that tells the schema to discard it. The two are exactly opposed.Measured consequences, both on a tree where the
kind/lengthfields are real (i.e. post-#541):length=32with an rkey packs 12 octets, with the receiver key silently gone.length=12— the RFC 8684 value for the no-key form — without an rkey packs 20 octets, carrying a phantom all-zero key.
So the schema cannot currently express a 12-octet MP_CAPABLE at all. That is a stronger statement than the original filing: it is not only that the maker writes wrong numbers, but that the field's own condition is keyed to a value the RFC never uses for that meaning.
Whatever fix lands must therefore change both the maker's arithmetic and the predicate, in one pass, and should assert the packed octet count for each of the two RFC-defined forms — 12 without the receiver key, 20 with it — rather than asserting against either component in isolation. Fixing one without the other swaps which of the two forms is broken rather than repairing either.
- added 7 commits that reference this issue
on Sep 21, 2026
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
TCP._make_mptcp_capablewrites an MP_CAPABLE length that is wrong in both branches. Found while fixing #541, which unmasked it; filed separately.The arithmetic
pcapkit/protocols/transport/tcp.py:2669:RFC 8684 section 3.1 gives MP_CAPABLE as 12 octets without the receiver's key and 20 octets with it. So both branches are wrong, and confusingly the no-key branch writes 20 — which is the correct value for the other case.
Why it appears now
It was entirely masked. Before #541,
MPTCPdeclaredkind/lengthonly undertyping.TYPE_CHECKING, so the maker'slength=was dropped withUnknownFieldWarningand packing died onKeyError: 'length'before the value could reach the wire. #541 declares them as real fields, so the length now lands — and lands wrong.That makes this the more dangerous of the two defects #541 exposed: unlike #566, which raises, this one packs successfully with wrong bytes. A caller gets an MP_CAPABLE option whose length octet disagrees with its own payload and no exception to warn them.
Coverage
A test asserting the packed byte length of MP_CAPABLE for both the key-present and key-absent cases, against RFC 8684 section 3.1 rather than against current behaviour. Proven to fail without the fix, exit code read from a file.
Worth checking the sibling
_make_mptcp_*helpers' length arithmetic in the same pass: #541 established that all eleven share a common history of never having had their lengths exercised, so this may not be the only one. The four packed-byte assertions #541 added forADD_ADDR(1e08340101020304at length 8,1e0a34010102030401bbat 10, and the IPv6 forms at 20 and 22) are the pattern to follow.