Reassembly Integration¶
Where a new reassembly engine under pcapkit.foundation.reassembly plugs into
the rest of the package. Points 1 to 3 are the owner’s ruling on the DTLS reassembly
work, applied in review of #2451 (#2440); the issue itself does not hold
it. Point 4 rests on #2469, which settled the DTLS case alone: in review of
how DTLS sizes a handshake message’s buffer, the owner had DTLS reassembly follow its
RFCs.
No issue holds that ruling.
The Rule¶
A protocol class does not handle or integrate reassembly itself. The protocol dissector stays a parser; it does not reach into
pcapkit.foundation.reassemblydirectly. A public method that parses a reassembled unit from its own octets is still a parser, so a protocol class may offer one (#2496).A new engine needs a new
pcapkit.toolkithelper that declares which output engines (dpkt,pyshark,scapy, the default) support it.A new engine’s reassembled outcome needs a new
pcapkit.foundation.analysismethod to parse that outcome into a usable result, rather than leaving the caller to interpret raw reassembled bytes. The package mirrorspcapkit.foundation.reassembly: a module per engine, whose public names the package,pcapkit.foundationandpcapkit.allexport (#2496).Reassembly always follows the RFC’s own definition, never an algorithm this package invents. Where the RFC states no required algorithm – buffer the whole message, accept overlaps – the engine does the same and adds no timeout, cap or ordering rule the RFC does not call for.
TCP’s gap cap is a safety limit, not a reassembly rule. No RFC calls for
TCP_GAP_LIMIT, the widest gap TCP reassembly
zero-fills to merge a segment. It bounds the memory a capture can have zero-filled, as
MAX_ZERO_PAD_LENGTH does for a field, and -1
lifts it to give the uncapped reassembly point 4 asks for. Ruled on #2546.
Parse Ownership¶
The protocol class owns the parse of a reassembled outcome, and
pcapkit.foundation.analysis is a public layer over it. Ruled on #2622:
The parse is a method of the protocol class:
Protocol.analyzefor IPv4 and IPv6,Transport.analyzefor TCP, andDTLS.analyze_handshakefor a DTLS handshake message.Each
pcapkit.foundation.analysisfunction is a public wrapper that calls that method and holds no parsing of its own.The reassembly
Deferredcalls the same method, on the reassembly’s own__protocol_type__.Protocol code never imports
pcapkit.foundationto do its own work: the dependency runs fromfoundationto the protocols. What the protocol base does import frompcapkit.foundation.registry.protocolsregisters a class rather than parsing.tests/project/test_protocols_import_boundary_2622_unit.pyfails on any other import ofpcapkit.foundationunderpcapkit/protocols/made outside aTYPE_CHECKINGblock, the rest ofpcapkit.foundation.registryincluded.
Compliance, Measured¶
Point 1 holds for every engine. None of
IPv4,
IPv6,
TCP and
DTLS imports or calls into
pcapkit.foundation.reassembly at all. The real path is
pcapkit.foundation.engines calling a pcapkit.toolkit.<engine> extraction
function on an already-parsed frame, feeding the result to the reassembly instance the
Extractor holds; for DTLS that function is
pcapkit.toolkit.pcap.dtls_reassembly() (#2496).
DTLS.read_handshake
and DTLS.analyze_handshake
are the parser methods the rule allows.
No engine meets point 2. No single pcapkit.toolkit helper enumerates which
output engines support a given reassembly engine. Support is established ad hoc, per
engine backend, by defining the extraction functions, by defining them raising
UnsupportedCall, or by disabling reassembly at the
engine level, as pcapkit.foundation.engines.pyshark does. DTLS defines them for
the default engine and is disabled at the engine level on every other.
Point 3 holds for every engine.
ip_datagram() parses a reassembled IPv4 or IPv6
datagram’s payload by its payload protocol type, through
Protocol.analyze;
tcp_datagram() parses a reassembled TCP
datagram’s by its ports, through
Transport.analyze;
and dtls_handshake() decodes a reassembled
DTLS handshake message (#2496), through
DTLS.analyze_handshake
(#2622). The owner chose on #2581 to give IP and TCP modules of their
own, each function named for the datagram its engine reassembles, rather than leave
their outcomes to those dispatchers with no analysis method, which kept the rule true
for DTLS alone.
Where the rule is silent, DTLS takes the IP/TCP shape (#2531). IPv4, IPv6,
TCP and DTLS reassembly each set __protocol_type__, and each reports its parsed
outcome as a datagram’s packet, deferred to first read by
Deferred. Each Deferred runs the
parse behind its engine’s analysis function, so a packet is what that function
returns. Each binds that parse to __protocol_type__, calling its analyze for
IP and TCP (#2581) and its analyze_handshake for DTLS (#2622), so a
subclass naming another protocol has its packet parsed by that one. The engines
differ in what an incomplete outcome holds. IP and TCP parse a contiguous payload
whether or not it is complete, as strict=False reports one, and hold None
only for the received runs strict=True reports; DTLS holds None for any
incomplete message.