Base Class¶
pcapkit.foundation.reassembly.ip contains
IP
only, which reconstructs fragmented IP packets back to
origin, using the RFC 791 procedure described in IP Datagram Reassembly.
- class pcapkit.foundation.reassembly.ip.IP(*, strict=True, store=True, timeout=None)[source]¶
Bases:
ReassemblyBase[Packet[_AT],Datagram[_AT],tuple[_AT,_AT,int, TransType],Buffer[_AT]],Generic[_AT]Reassembly for IP payload.
- Parameters:
strict (
bool) – ifTrue, report a datagram that is not completely reassembled as the tuple of its received runs, empty if none was; otherwise as one contiguous payload, its holes zero-filled – or, while the total length is unknown, only the prefix up to the first hole. Receipt is tracked in 8-octet blocks, and only the final fragment’s partial last block counts as received – a non-final fragment’s, or a snaplen-truncated or buffer-clipped fragment’s, does not: it is left out of the runs and ends the prefix, but once the total length is known the contiguous payload keeps its real octets, with only the rest of the hole zero-filled. A datagram longer than its length field can declare is never completestore (
bool) – if store reassembled datagram in memory, i.e.,self._dtgram(if not, datagram will be discarded after callback)timeout (
float|None) – reassembly timeout in seconds, on the capture’s own clock;Noneselects the protocol’s__timeout__default
Important
This class is not intended to be instantiated directly, but rather used as a base class for the protocol-aware reassembly classes.
Changed in version 1.5.0: An overlapping fragment that disagrees with octets already received overwrites them, as RFC 791 asks, and the disagreement is recorded in
Datagram.conflict(#477). An incomplete buffer expires aftertimeoutseconds of capture time, 60 by default for both IPv4 and IPv6.- reassembly(info)[source]¶
Reassembly procedure.
- Parameters:
info (
Packet[TypeVar(_AT, IPv4Address, IPv6Address)]) – info dict of packets to be reassembled
Note
A completed datagram’s buffer is freed, as in the RFC 791 Section 3.2 reassembly procedure, so a fragment of it that arrives afterwards – a late duplicate, say – opens a new buffer. The caller sees that buffer as a separate incomplete datagram,
PARTIALat the end of the capture orTIMEOUTif it expires first. This is intended, is permitted by RFC 8200 Section 4.5, and matches Linux, Zeek and Wireshark (#1507).
- submit(buf, *, bufid, checked=False, timeout=False)[source]¶
Submit reassembled payload.
- Parameters:
buf (
Buffer[TypeVar(_AT, IPv4Address, IPv6Address)]) – buffer dict of reassembled packetsbufid (
tuple[TypeVar(_AT, IPv4Address, IPv6Address),TypeVar(_AT, IPv4Address, IPv6Address),int,TransType]) – buffer identifierchecked (
bool) – buffer consistency checked flagtimeout (
bool) – whether this buffer is being submitted becauseexpire()abandoned it under the reassembly timeout, which is what separatesCompletion.TIMEOUTfromCompletion.PARTIAL
- Return type:
- Returns:
Reassembled packets.
Data Models¶
- class pcapkit.foundation.reassembly.data.ip.Packet(*args: VT, **kwargs: VT)[source]¶
-
Data model for IPv4 and/or IPv6 packet representation.
- timestamp: float¶
Capture timestamp of the fragment, in seconds since the Unix epoch. This is the capture’s clock, not the host’s: it is what drives the RFC 1122 Section 3.3.2 and RFC 8200 Section 4.5 reassembly timeout, since an offline parser replaying a file has no other notion of time passing.
- pcapkit.foundation.reassembly.data.ip.BufferID: Tuple[_AT, _AT, int, pcapkit.const.reg.transtype.TransType]¶
Data module for buffer ID.
- class pcapkit.foundation.reassembly.data.ip.Buffer(*args: VT, **kwargs: VT)[source]¶
-
Data model for IPv4 and/or IPv6 reassembly buffer entry.
- timestamp: float¶
Capture timestamp of the first-arriving fragment of this datagram, in seconds since the Unix epoch. This is the origin of the reassembly timer: RFC 8200 Section 4.5 counts its 60 seconds “of the reception of the first-arriving fragment”, so a later fragment does not extend the deadline and this field is never revised once set.
- conflict: list[tuple[int, int]]¶
Octet ranges, absolute into
datagramand both inclusive, on which an arriving fragment disagreed with bytes already placed there by an earlier one. Accumulated across every fragment merged into this buffer, in the order the conflicts were found; carried ontoDatagram.conflictverbatim when the buffer is submitted.
- class pcapkit.foundation.reassembly.data.ip.Datagram(*args: VT, **kwargs: VT)[source]¶
Bases:
DeferredPacket,Info,Generic[_AT]Data model for IPv4 and/or IPv6 reassembled datagram.
- completed: Completion¶
How completely the datagram was reassembled, and why reassembly stopped. Only
Completion.COMPLETEis truthy, soif datagram.completed:reads as it would for abool; equality againstTrueorFalsedoes not hold.
- id: DatagramID[_AT]¶
Original packet identifier.
- packet: ProtocolBase | None¶
Parsed IP payload. Analysed on first read, not at construction time; a
Deferredmay be passed in its place, and reading this attribute then runs it and keeps the result.
- conflict: tuple[tuple[int, int], ...]¶
Octet ranges, absolute into the reassembled payload and both inclusive – the same convention as
Packet.focombined with its length – on which two fragments disagreed, i.e. an arriving fragment overlapped octets already buffered but did not repeat them. Empty when the datagram never saw a contested octet.RFC 791 resolves the disagreement itself: “In the case that two or more fragments contain the same data either identically or through a partial overlap, this procedure will use the more recently arrived copy in the data buffer and datagram delivered.” So
payloadalways holds whichever fragment arrived last over a contested range – the opposite resolution from TCP’s first-write-wins (RFC 9293 Section 3.10) – and this field is what lets a caller tell a clean datagram from a contested one, since a resolved conflict does not, on its own, leave a hole forcompletedto report.Buffer.RCVBTonly records receipt in 8-octet blocks, coarser than the octet granularity a conflict needs, and an octet is compared only if its block is marked.Packet.fois always a multiple of 8, being wire-encoded in 8-octet units, and only the final fragment marks a partial last block, so the only marked block that can be partially real is the one holding the final fragment’s own tail – and a range reported here never extends pastBuffer.TDLfor exactly that reason, even though a wholeRCVBTblock straddling it reads as “received”. Any other partial last block – a non-final, truncated or clipped fragment’s – is left unmarked, so a later fragment that overwrites its octets records no conflict. SeeIP._detect_conflicts.
Type Variables¶
- pcapkit.foundation.reassembly.data.ip._AT: ipaddress.IPv4Address | ipaddress.IPv6Address¶